xref: /openbmc/linux/drivers/soc/qcom/pmic_glink.c (revision f3c3091b98d5d52df40aaf27f11530701d02ac56)
158ef4eceSBjorn Andersson // SPDX-License-Identifier: GPL-2.0-only
258ef4eceSBjorn Andersson /*
358ef4eceSBjorn Andersson  * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
458ef4eceSBjorn Andersson  * Copyright (c) 2022, Linaro Ltd
558ef4eceSBjorn Andersson  */
658ef4eceSBjorn Andersson #include <linux/auxiliary_bus.h>
758ef4eceSBjorn Andersson #include <linux/module.h>
86484be9dSRob Herring #include <linux/of.h>
958ef4eceSBjorn Andersson #include <linux/platform_device.h>
1058ef4eceSBjorn Andersson #include <linux/rpmsg.h>
1158ef4eceSBjorn Andersson #include <linux/slab.h>
1258ef4eceSBjorn Andersson #include <linux/soc/qcom/pdr.h>
1358ef4eceSBjorn Andersson #include <linux/soc/qcom/pmic_glink.h>
14fbadcde1SBjorn Andersson #include <linux/spinlock.h>
1558ef4eceSBjorn Andersson 
16ff642773SNeil Armstrong enum {
17ff642773SNeil Armstrong 	PMIC_GLINK_CLIENT_BATT = 0,
18ff642773SNeil Armstrong 	PMIC_GLINK_CLIENT_ALTMODE,
19ff642773SNeil Armstrong 	PMIC_GLINK_CLIENT_UCSI,
20ff642773SNeil Armstrong };
21ff642773SNeil Armstrong 
22ff642773SNeil Armstrong #define PMIC_GLINK_CLIENT_DEFAULT	(BIT(PMIC_GLINK_CLIENT_BATT) |	\
23ff642773SNeil Armstrong 					 BIT(PMIC_GLINK_CLIENT_ALTMODE))
24ff642773SNeil Armstrong 
2558ef4eceSBjorn Andersson struct pmic_glink {
2658ef4eceSBjorn Andersson 	struct device *dev;
2758ef4eceSBjorn Andersson 	struct pdr_handle *pdr;
2858ef4eceSBjorn Andersson 
2958ef4eceSBjorn Andersson 	struct rpmsg_endpoint *ept;
3058ef4eceSBjorn Andersson 
31ff642773SNeil Armstrong 	unsigned long client_mask;
32ff642773SNeil Armstrong 
3358ef4eceSBjorn Andersson 	struct auxiliary_device altmode_aux;
3458ef4eceSBjorn Andersson 	struct auxiliary_device ps_aux;
3558ef4eceSBjorn Andersson 	struct auxiliary_device ucsi_aux;
3658ef4eceSBjorn Andersson 
3758ef4eceSBjorn Andersson 	/* serializing client_state and pdr_state updates */
3858ef4eceSBjorn Andersson 	struct mutex state_lock;
3958ef4eceSBjorn Andersson 	unsigned int client_state;
4058ef4eceSBjorn Andersson 	unsigned int pdr_state;
4158ef4eceSBjorn Andersson 
4258ef4eceSBjorn Andersson 	/* serializing clients list updates */
43fbadcde1SBjorn Andersson 	spinlock_t client_lock;
4458ef4eceSBjorn Andersson 	struct list_head clients;
4558ef4eceSBjorn Andersson };
4658ef4eceSBjorn Andersson 
4758ef4eceSBjorn Andersson static struct pmic_glink *__pmic_glink;
4858ef4eceSBjorn Andersson static DEFINE_MUTEX(__pmic_glink_lock);
4958ef4eceSBjorn Andersson 
5058ef4eceSBjorn Andersson struct pmic_glink_client {
5158ef4eceSBjorn Andersson 	struct list_head node;
5258ef4eceSBjorn Andersson 
5358ef4eceSBjorn Andersson 	struct pmic_glink *pg;
5458ef4eceSBjorn Andersson 	unsigned int id;
5558ef4eceSBjorn Andersson 
5658ef4eceSBjorn Andersson 	void (*cb)(const void *data, size_t len, void *priv);
5758ef4eceSBjorn Andersson 	void (*pdr_notify)(void *priv, int state);
5858ef4eceSBjorn Andersson 	void *priv;
5958ef4eceSBjorn Andersson };
6058ef4eceSBjorn Andersson 
_devm_pmic_glink_release_client(struct device * dev,void * res)6158ef4eceSBjorn Andersson static void _devm_pmic_glink_release_client(struct device *dev, void *res)
6258ef4eceSBjorn Andersson {
6358ef4eceSBjorn Andersson 	struct pmic_glink_client *client = (struct pmic_glink_client *)res;
6458ef4eceSBjorn Andersson 	struct pmic_glink *pg = client->pg;
65fbadcde1SBjorn Andersson 	unsigned long flags;
6658ef4eceSBjorn Andersson 
67fbadcde1SBjorn Andersson 	spin_lock_irqsave(&pg->client_lock, flags);
6858ef4eceSBjorn Andersson 	list_del(&client->node);
69fbadcde1SBjorn Andersson 	spin_unlock_irqrestore(&pg->client_lock, flags);
7058ef4eceSBjorn Andersson }
7158ef4eceSBjorn Andersson 
devm_pmic_glink_client_alloc(struct device * dev,unsigned int id,void (* cb)(const void *,size_t,void *),void (* pdr)(void *,int),void * priv)72*1efdbf53SBjorn Andersson struct pmic_glink_client *devm_pmic_glink_client_alloc(struct device *dev,
7358ef4eceSBjorn Andersson 						       unsigned int id,
7458ef4eceSBjorn Andersson 						       void (*cb)(const void *, size_t, void *),
7558ef4eceSBjorn Andersson 						       void (*pdr)(void *, int),
7658ef4eceSBjorn Andersson 						       void *priv)
7758ef4eceSBjorn Andersson {
7858ef4eceSBjorn Andersson 	struct pmic_glink_client *client;
7958ef4eceSBjorn Andersson 	struct pmic_glink *pg = dev_get_drvdata(dev->parent);
8058ef4eceSBjorn Andersson 
8158ef4eceSBjorn Andersson 	client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
8258ef4eceSBjorn Andersson 	if (!client)
8358ef4eceSBjorn Andersson 		return ERR_PTR(-ENOMEM);
8458ef4eceSBjorn Andersson 
8558ef4eceSBjorn Andersson 	client->pg = pg;
8658ef4eceSBjorn Andersson 	client->id = id;
8758ef4eceSBjorn Andersson 	client->cb = cb;
8858ef4eceSBjorn Andersson 	client->pdr_notify = pdr;
8958ef4eceSBjorn Andersson 	client->priv = priv;
90*1efdbf53SBjorn Andersson 	INIT_LIST_HEAD(&client->node);
91*1efdbf53SBjorn Andersson 
92*1efdbf53SBjorn Andersson 	devres_add(dev, client);
93*1efdbf53SBjorn Andersson 
94*1efdbf53SBjorn Andersson 	return client;
95*1efdbf53SBjorn Andersson }
96*1efdbf53SBjorn Andersson EXPORT_SYMBOL_GPL(devm_pmic_glink_client_alloc);
97*1efdbf53SBjorn Andersson 
pmic_glink_client_register(struct pmic_glink_client * client)98*1efdbf53SBjorn Andersson void pmic_glink_client_register(struct pmic_glink_client *client)
99*1efdbf53SBjorn Andersson {
100*1efdbf53SBjorn Andersson 	struct pmic_glink *pg = client->pg;
101*1efdbf53SBjorn Andersson 	unsigned long flags;
10258ef4eceSBjorn Andersson 
1038fc79346SDmitry Baryshkov 	mutex_lock(&pg->state_lock);
104fbadcde1SBjorn Andersson 	spin_lock_irqsave(&pg->client_lock, flags);
1058fc79346SDmitry Baryshkov 
10658ef4eceSBjorn Andersson 	list_add(&client->node, &pg->clients);
1078fc79346SDmitry Baryshkov 	client->pdr_notify(client->priv, pg->client_state);
1088fc79346SDmitry Baryshkov 
109fbadcde1SBjorn Andersson 	spin_unlock_irqrestore(&pg->client_lock, flags);
1108fc79346SDmitry Baryshkov 	mutex_unlock(&pg->state_lock);
11158ef4eceSBjorn Andersson 
11258ef4eceSBjorn Andersson }
113*1efdbf53SBjorn Andersson EXPORT_SYMBOL_GPL(pmic_glink_client_register);
11458ef4eceSBjorn Andersson 
pmic_glink_send(struct pmic_glink_client * client,void * data,size_t len)11558ef4eceSBjorn Andersson int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
11658ef4eceSBjorn Andersson {
11758ef4eceSBjorn Andersson 	struct pmic_glink *pg = client->pg;
11858ef4eceSBjorn Andersson 
11958ef4eceSBjorn Andersson 	return rpmsg_send(pg->ept, data, len);
12058ef4eceSBjorn Andersson }
12158ef4eceSBjorn Andersson EXPORT_SYMBOL_GPL(pmic_glink_send);
12258ef4eceSBjorn Andersson 
pmic_glink_rpmsg_callback(struct rpmsg_device * rpdev,void * data,int len,void * priv,u32 addr)12358ef4eceSBjorn Andersson static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
12458ef4eceSBjorn Andersson 				     int len, void *priv, u32 addr)
12558ef4eceSBjorn Andersson {
12658ef4eceSBjorn Andersson 	struct pmic_glink_client *client;
12758ef4eceSBjorn Andersson 	struct pmic_glink_hdr *hdr;
12858ef4eceSBjorn Andersson 	struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev);
129fbadcde1SBjorn Andersson 	unsigned long flags;
13058ef4eceSBjorn Andersson 
13158ef4eceSBjorn Andersson 	if (len < sizeof(*hdr)) {
13258ef4eceSBjorn Andersson 		dev_warn(pg->dev, "ignoring truncated message\n");
13358ef4eceSBjorn Andersson 		return 0;
13458ef4eceSBjorn Andersson 	}
13558ef4eceSBjorn Andersson 
13658ef4eceSBjorn Andersson 	hdr = data;
13758ef4eceSBjorn Andersson 
138fbadcde1SBjorn Andersson 	spin_lock_irqsave(&pg->client_lock, flags);
13958ef4eceSBjorn Andersson 	list_for_each_entry(client, &pg->clients, node) {
14058ef4eceSBjorn Andersson 		if (client->id == le32_to_cpu(hdr->owner))
14158ef4eceSBjorn Andersson 			client->cb(data, len, client->priv);
14258ef4eceSBjorn Andersson 	}
143fbadcde1SBjorn Andersson 	spin_unlock_irqrestore(&pg->client_lock, flags);
14458ef4eceSBjorn Andersson 
14558ef4eceSBjorn Andersson 	return 0;
14658ef4eceSBjorn Andersson }
14758ef4eceSBjorn Andersson 
pmic_glink_aux_release(struct device * dev)14858ef4eceSBjorn Andersson static void pmic_glink_aux_release(struct device *dev) {}
14958ef4eceSBjorn Andersson 
pmic_glink_add_aux_device(struct pmic_glink * pg,struct auxiliary_device * aux,const char * name)15058ef4eceSBjorn Andersson static int pmic_glink_add_aux_device(struct pmic_glink *pg,
15158ef4eceSBjorn Andersson 				     struct auxiliary_device *aux,
15258ef4eceSBjorn Andersson 				     const char *name)
15358ef4eceSBjorn Andersson {
15458ef4eceSBjorn Andersson 	struct device *parent = pg->dev;
15558ef4eceSBjorn Andersson 	int ret;
15658ef4eceSBjorn Andersson 
15758ef4eceSBjorn Andersson 	aux->name = name;
15858ef4eceSBjorn Andersson 	aux->dev.parent = parent;
15958ef4eceSBjorn Andersson 	aux->dev.release = pmic_glink_aux_release;
16058ef4eceSBjorn Andersson 	device_set_of_node_from_dev(&aux->dev, parent);
16158ef4eceSBjorn Andersson 	ret = auxiliary_device_init(aux);
16258ef4eceSBjorn Andersson 	if (ret)
16358ef4eceSBjorn Andersson 		return ret;
16458ef4eceSBjorn Andersson 
16558ef4eceSBjorn Andersson 	ret = auxiliary_device_add(aux);
16658ef4eceSBjorn Andersson 	if (ret)
16758ef4eceSBjorn Andersson 		auxiliary_device_uninit(aux);
16858ef4eceSBjorn Andersson 
16958ef4eceSBjorn Andersson 	return ret;
17058ef4eceSBjorn Andersson }
17158ef4eceSBjorn Andersson 
pmic_glink_del_aux_device(struct pmic_glink * pg,struct auxiliary_device * aux)17258ef4eceSBjorn Andersson static void pmic_glink_del_aux_device(struct pmic_glink *pg,
17358ef4eceSBjorn Andersson 				      struct auxiliary_device *aux)
17458ef4eceSBjorn Andersson {
17558ef4eceSBjorn Andersson 	auxiliary_device_delete(aux);
17658ef4eceSBjorn Andersson 	auxiliary_device_uninit(aux);
17758ef4eceSBjorn Andersson }
17858ef4eceSBjorn Andersson 
pmic_glink_state_notify_clients(struct pmic_glink * pg)17958ef4eceSBjorn Andersson static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
18058ef4eceSBjorn Andersson {
18158ef4eceSBjorn Andersson 	struct pmic_glink_client *client;
18258ef4eceSBjorn Andersson 	unsigned int new_state = pg->client_state;
183fbadcde1SBjorn Andersson 	unsigned long flags;
18458ef4eceSBjorn Andersson 
18558ef4eceSBjorn Andersson 	if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
18658ef4eceSBjorn Andersson 		if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
18758ef4eceSBjorn Andersson 			new_state = SERVREG_SERVICE_STATE_UP;
18858ef4eceSBjorn Andersson 	} else {
189c704091bSBjorn Andersson 		if (pg->pdr_state == SERVREG_SERVICE_STATE_DOWN || !pg->ept)
19058ef4eceSBjorn Andersson 			new_state = SERVREG_SERVICE_STATE_DOWN;
19158ef4eceSBjorn Andersson 	}
19258ef4eceSBjorn Andersson 
19358ef4eceSBjorn Andersson 	if (new_state != pg->client_state) {
194fbadcde1SBjorn Andersson 		spin_lock_irqsave(&pg->client_lock, flags);
19558ef4eceSBjorn Andersson 		list_for_each_entry(client, &pg->clients, node)
19658ef4eceSBjorn Andersson 			client->pdr_notify(client->priv, new_state);
197fbadcde1SBjorn Andersson 		spin_unlock_irqrestore(&pg->client_lock, flags);
19858ef4eceSBjorn Andersson 		pg->client_state = new_state;
19958ef4eceSBjorn Andersson 	}
20058ef4eceSBjorn Andersson }
20158ef4eceSBjorn Andersson 
pmic_glink_pdr_callback(int state,char * svc_path,void * priv)20258ef4eceSBjorn Andersson static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv)
20358ef4eceSBjorn Andersson {
20458ef4eceSBjorn Andersson 	struct pmic_glink *pg = priv;
20558ef4eceSBjorn Andersson 
20658ef4eceSBjorn Andersson 	mutex_lock(&pg->state_lock);
20758ef4eceSBjorn Andersson 	pg->pdr_state = state;
20858ef4eceSBjorn Andersson 
20958ef4eceSBjorn Andersson 	pmic_glink_state_notify_clients(pg);
21058ef4eceSBjorn Andersson 	mutex_unlock(&pg->state_lock);
21158ef4eceSBjorn Andersson }
21258ef4eceSBjorn Andersson 
pmic_glink_rpmsg_probe(struct rpmsg_device * rpdev)21358ef4eceSBjorn Andersson static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev)
21458ef4eceSBjorn Andersson {
21558ef4eceSBjorn Andersson 	struct pmic_glink *pg = __pmic_glink;
21658ef4eceSBjorn Andersson 	int ret = 0;
21758ef4eceSBjorn Andersson 
21858ef4eceSBjorn Andersson 	mutex_lock(&__pmic_glink_lock);
21958ef4eceSBjorn Andersson 	if (!pg) {
22058ef4eceSBjorn Andersson 		ret = dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n");
22158ef4eceSBjorn Andersson 		goto out_unlock;
22258ef4eceSBjorn Andersson 	}
22358ef4eceSBjorn Andersson 
22458ef4eceSBjorn Andersson 	dev_set_drvdata(&rpdev->dev, pg);
22558ef4eceSBjorn Andersson 
22658ef4eceSBjorn Andersson 	mutex_lock(&pg->state_lock);
22758ef4eceSBjorn Andersson 	pg->ept = rpdev->ept;
22858ef4eceSBjorn Andersson 	pmic_glink_state_notify_clients(pg);
22958ef4eceSBjorn Andersson 	mutex_unlock(&pg->state_lock);
23058ef4eceSBjorn Andersson 
23158ef4eceSBjorn Andersson out_unlock:
23258ef4eceSBjorn Andersson 	mutex_unlock(&__pmic_glink_lock);
23358ef4eceSBjorn Andersson 	return ret;
23458ef4eceSBjorn Andersson }
23558ef4eceSBjorn Andersson 
pmic_glink_rpmsg_remove(struct rpmsg_device * rpdev)23658ef4eceSBjorn Andersson static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev)
23758ef4eceSBjorn Andersson {
23858ef4eceSBjorn Andersson 	struct pmic_glink *pg;
23958ef4eceSBjorn Andersson 
24058ef4eceSBjorn Andersson 	mutex_lock(&__pmic_glink_lock);
24158ef4eceSBjorn Andersson 	pg = __pmic_glink;
24258ef4eceSBjorn Andersson 	if (!pg)
24358ef4eceSBjorn Andersson 		goto out_unlock;
24458ef4eceSBjorn Andersson 
24558ef4eceSBjorn Andersson 	mutex_lock(&pg->state_lock);
24658ef4eceSBjorn Andersson 	pg->ept = NULL;
24758ef4eceSBjorn Andersson 	pmic_glink_state_notify_clients(pg);
24858ef4eceSBjorn Andersson 	mutex_unlock(&pg->state_lock);
24958ef4eceSBjorn Andersson out_unlock:
25058ef4eceSBjorn Andersson 	mutex_unlock(&__pmic_glink_lock);
25158ef4eceSBjorn Andersson }
25258ef4eceSBjorn Andersson 
25358ef4eceSBjorn Andersson static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = {
25458ef4eceSBjorn Andersson 	{ "PMIC_RTR_ADSP_APPS" },
25558ef4eceSBjorn Andersson 	{}
25658ef4eceSBjorn Andersson };
25758ef4eceSBjorn Andersson 
25858ef4eceSBjorn Andersson static struct rpmsg_driver pmic_glink_rpmsg_driver = {
25958ef4eceSBjorn Andersson 	.probe = pmic_glink_rpmsg_probe,
26058ef4eceSBjorn Andersson 	.remove = pmic_glink_rpmsg_remove,
26158ef4eceSBjorn Andersson 	.callback = pmic_glink_rpmsg_callback,
26258ef4eceSBjorn Andersson 	.id_table = pmic_glink_rpmsg_id_match,
26358ef4eceSBjorn Andersson 	.drv  = {
26458ef4eceSBjorn Andersson 		.name  = "qcom_pmic_glink_rpmsg",
26558ef4eceSBjorn Andersson 	},
26658ef4eceSBjorn Andersson };
26758ef4eceSBjorn Andersson 
pmic_glink_probe(struct platform_device * pdev)26858ef4eceSBjorn Andersson static int pmic_glink_probe(struct platform_device *pdev)
26958ef4eceSBjorn Andersson {
270ff642773SNeil Armstrong 	const unsigned long *match_data;
27158ef4eceSBjorn Andersson 	struct pdr_service *service;
27258ef4eceSBjorn Andersson 	struct pmic_glink *pg;
27358ef4eceSBjorn Andersson 	int ret;
27458ef4eceSBjorn Andersson 
27558ef4eceSBjorn Andersson 	pg = devm_kzalloc(&pdev->dev, sizeof(*pg), GFP_KERNEL);
27658ef4eceSBjorn Andersson 	if (!pg)
27758ef4eceSBjorn Andersson 		return -ENOMEM;
27858ef4eceSBjorn Andersson 
27958ef4eceSBjorn Andersson 	dev_set_drvdata(&pdev->dev, pg);
28058ef4eceSBjorn Andersson 
28158ef4eceSBjorn Andersson 	pg->dev = &pdev->dev;
28258ef4eceSBjorn Andersson 
28358ef4eceSBjorn Andersson 	INIT_LIST_HEAD(&pg->clients);
284fbadcde1SBjorn Andersson 	spin_lock_init(&pg->client_lock);
28558ef4eceSBjorn Andersson 	mutex_init(&pg->state_lock);
28658ef4eceSBjorn Andersson 
287ff642773SNeil Armstrong 	match_data = (unsigned long *)of_device_get_match_data(&pdev->dev);
288ff642773SNeil Armstrong 	if (match_data)
289ff642773SNeil Armstrong 		pg->client_mask = *match_data;
290ff642773SNeil Armstrong 	else
291ff642773SNeil Armstrong 		pg->client_mask = PMIC_GLINK_CLIENT_DEFAULT;
292ff642773SNeil Armstrong 
293737d2e93SRob Clark 	pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
294737d2e93SRob Clark 	if (IS_ERR(pg->pdr)) {
295737d2e93SRob Clark 		ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr),
296737d2e93SRob Clark 				    "failed to initialize pdr\n");
297737d2e93SRob Clark 		return ret;
298737d2e93SRob Clark 	}
299737d2e93SRob Clark 
300ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) {
301ff642773SNeil Armstrong 		ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi");
30258ef4eceSBjorn Andersson 		if (ret)
303737d2e93SRob Clark 			goto out_release_pdr_handle;
304ff642773SNeil Armstrong 	}
305ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) {
306ff642773SNeil Armstrong 		ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
307ff642773SNeil Armstrong 		if (ret)
308ff642773SNeil Armstrong 			goto out_release_ucsi_aux;
309ff642773SNeil Armstrong 	}
310ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) {
31158ef4eceSBjorn Andersson 		ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
31258ef4eceSBjorn Andersson 		if (ret)
31358ef4eceSBjorn Andersson 			goto out_release_altmode_aux;
314ff642773SNeil Armstrong 	}
31558ef4eceSBjorn Andersson 
31658ef4eceSBjorn Andersson 	service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
31758ef4eceSBjorn Andersson 	if (IS_ERR(service)) {
31858ef4eceSBjorn Andersson 		ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
31958ef4eceSBjorn Andersson 				    "failed adding pdr lookup for charger_pd\n");
320737d2e93SRob Clark 		goto out_release_aux_devices;
32158ef4eceSBjorn Andersson 	}
32258ef4eceSBjorn Andersson 
32358ef4eceSBjorn Andersson 	mutex_lock(&__pmic_glink_lock);
32458ef4eceSBjorn Andersson 	__pmic_glink = pg;
32558ef4eceSBjorn Andersson 	mutex_unlock(&__pmic_glink_lock);
32658ef4eceSBjorn Andersson 
32758ef4eceSBjorn Andersson 	return 0;
32858ef4eceSBjorn Andersson 
32958ef4eceSBjorn Andersson out_release_aux_devices:
330ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
33158ef4eceSBjorn Andersson 		pmic_glink_del_aux_device(pg, &pg->ps_aux);
33258ef4eceSBjorn Andersson out_release_altmode_aux:
333ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
33458ef4eceSBjorn Andersson 		pmic_glink_del_aux_device(pg, &pg->altmode_aux);
335ff642773SNeil Armstrong out_release_ucsi_aux:
336ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
337ff642773SNeil Armstrong 		pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
338737d2e93SRob Clark out_release_pdr_handle:
339737d2e93SRob Clark 	pdr_handle_release(pg->pdr);
34058ef4eceSBjorn Andersson 
34158ef4eceSBjorn Andersson 	return ret;
34258ef4eceSBjorn Andersson }
34358ef4eceSBjorn Andersson 
pmic_glink_remove(struct platform_device * pdev)34458ef4eceSBjorn Andersson static int pmic_glink_remove(struct platform_device *pdev)
34558ef4eceSBjorn Andersson {
34658ef4eceSBjorn Andersson 	struct pmic_glink *pg = dev_get_drvdata(&pdev->dev);
34758ef4eceSBjorn Andersson 
34858ef4eceSBjorn Andersson 	pdr_handle_release(pg->pdr);
34958ef4eceSBjorn Andersson 
350ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT))
35158ef4eceSBjorn Andersson 		pmic_glink_del_aux_device(pg, &pg->ps_aux);
352ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE))
35358ef4eceSBjorn Andersson 		pmic_glink_del_aux_device(pg, &pg->altmode_aux);
354ff642773SNeil Armstrong 	if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI))
355ff642773SNeil Armstrong 		pmic_glink_del_aux_device(pg, &pg->ucsi_aux);
35658ef4eceSBjorn Andersson 
35758ef4eceSBjorn Andersson 	mutex_lock(&__pmic_glink_lock);
35858ef4eceSBjorn Andersson 	__pmic_glink = NULL;
35958ef4eceSBjorn Andersson 	mutex_unlock(&__pmic_glink_lock);
36058ef4eceSBjorn Andersson 
36158ef4eceSBjorn Andersson 	return 0;
36258ef4eceSBjorn Andersson }
36358ef4eceSBjorn Andersson 
364ff642773SNeil Armstrong static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
3654b11fa4fSNeil Armstrong 							   BIT(PMIC_GLINK_CLIENT_ALTMODE) |
3664b11fa4fSNeil Armstrong 							   BIT(PMIC_GLINK_CLIENT_UCSI);
3674b11fa4fSNeil Armstrong 
36858ef4eceSBjorn Andersson static const struct of_device_id pmic_glink_of_match[] = {
369ff642773SNeil Armstrong 	{ .compatible = "qcom,sm8450-pmic-glink", .data = &pmic_glink_sm8450_client_mask },
3707daada86SNeil Armstrong 	{ .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8450_client_mask },
371ff642773SNeil Armstrong 	{ .compatible = "qcom,pmic-glink" },
37258ef4eceSBjorn Andersson 	{}
37358ef4eceSBjorn Andersson };
37458ef4eceSBjorn Andersson MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
37558ef4eceSBjorn Andersson 
37658ef4eceSBjorn Andersson static struct platform_driver pmic_glink_driver = {
37758ef4eceSBjorn Andersson 	.probe = pmic_glink_probe,
37858ef4eceSBjorn Andersson 	.remove = pmic_glink_remove,
37958ef4eceSBjorn Andersson 	.driver = {
38058ef4eceSBjorn Andersson 		.name = "qcom_pmic_glink",
38158ef4eceSBjorn Andersson 		.of_match_table = pmic_glink_of_match,
38258ef4eceSBjorn Andersson 	},
38358ef4eceSBjorn Andersson };
38458ef4eceSBjorn Andersson 
pmic_glink_init(void)38558ef4eceSBjorn Andersson static int pmic_glink_init(void)
38658ef4eceSBjorn Andersson {
387762384e9SChen Ni 	int ret;
388762384e9SChen Ni 
389762384e9SChen Ni 	ret = platform_driver_register(&pmic_glink_driver);
390762384e9SChen Ni 	if (ret < 0)
391762384e9SChen Ni 		return ret;
392762384e9SChen Ni 
393762384e9SChen Ni 	ret = register_rpmsg_driver(&pmic_glink_rpmsg_driver);
394762384e9SChen Ni 	if (ret < 0) {
395762384e9SChen Ni 		platform_driver_unregister(&pmic_glink_driver);
396762384e9SChen Ni 		return ret;
397762384e9SChen Ni 	}
39858ef4eceSBjorn Andersson 
39958ef4eceSBjorn Andersson 	return 0;
40058ef4eceSBjorn Andersson };
40158ef4eceSBjorn Andersson module_init(pmic_glink_init);
40258ef4eceSBjorn Andersson 
pmic_glink_exit(void)40358ef4eceSBjorn Andersson static void pmic_glink_exit(void)
40458ef4eceSBjorn Andersson {
40558ef4eceSBjorn Andersson 	unregister_rpmsg_driver(&pmic_glink_rpmsg_driver);
40658ef4eceSBjorn Andersson 	platform_driver_unregister(&pmic_glink_driver);
40758ef4eceSBjorn Andersson };
40858ef4eceSBjorn Andersson module_exit(pmic_glink_exit);
40958ef4eceSBjorn Andersson 
41058ef4eceSBjorn Andersson MODULE_DESCRIPTION("Qualcomm PMIC GLINK driver");
41158ef4eceSBjorn Andersson MODULE_LICENSE("GPL");
412