This implements the base PMIC GLINK driver, a power_supply driver and a driver
for the USB Type-C altmode protocol. This has been tested and shown to provide
battery information, USB Type-C switch and mux requests and DisplayPort
notifications on SC8180X, SC8280XP and SM8350.
Bjorn Andersson (4):
dt-bindings: soc: qcom: Introduce PMIC GLINK binding
soc: qcom: pmic_glink: Introduce base PMIC GLINK driver
soc: qcom: pmic_glink: Introduce altmode support
power: supply: Introduce Qualcomm PMIC GLINK power supply
.../bindings/soc/qcom/qcom,pmic-glink.yaml | 98 ++
drivers/power/supply/Kconfig | 9 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/qcom_battmgr.c | 1422 +++++++++++++++++
drivers/soc/qcom/Kconfig | 14 +
drivers/soc/qcom/Makefile | 2 +
drivers/soc/qcom/pmic_glink.c | 336 ++++
drivers/soc/qcom/pmic_glink_altmode.c | 477 ++++++
include/linux/soc/qcom/pmic_glink.h | 32 +
9 files changed, 2391 insertions(+)
create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
create mode 100644 drivers/power/supply/qcom_battmgr.c
create mode 100644 drivers/soc/qcom/pmic_glink.c
create mode 100644 drivers/soc/qcom/pmic_glink_altmode.c
create mode 100644 include/linux/soc/qcom/pmic_glink.h
--
2.35.1
The PMIC GLINK service runs on one of the co-processors of some modern
Qualcomm platforms and implements USB-C and battery managements. It uses
a message based protocol over GLINK for communication with the OS, hence
the name.
The driver implemented provides the rpmsg device for communication and
uses auxilirary bus to spawn off individual devices in respsective
subsystem. The auxilirary devices are spawned off from a
platform_device, so that the drm_bridge is available early, to allow the
DisplayPort driver to probe even before the remoteproc has spun up.
Signed-off-by: Bjorn Andersson <[email protected]>
---
drivers/soc/qcom/Kconfig | 14 ++
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/pmic_glink.c | 336 ++++++++++++++++++++++++++++
include/linux/soc/qcom/pmic_glink.h | 32 +++
4 files changed, 383 insertions(+)
create mode 100644 drivers/soc/qcom/pmic_glink.c
create mode 100644 include/linux/soc/qcom/pmic_glink.h
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index e0d7a5459562..2289f5e0d5ad 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -91,6 +91,20 @@ config QCOM_PDR_HELPERS
tristate
select QCOM_QMI_HELPERS
+config QCOM_PMIC_GLINK
+ tristate "Qualcomm PMIC GLINK driver"
+ depends on RPMSG
+ depends on TYPEC
+ depends on DRM
+ select QCOM_PDR_HELPERS
+ help
+ The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
+ USB and battery firmware running on one of the coprocessors in
+ several modern Qualcomm platforms.
+
+ Say yes here to support USB-C and battery status on modern Qualcomm
+ platforms.
+
config QCOM_QMI_HELPERS
tristate
depends on NET
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index d66604aff2b0..fbbd1231e554 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
obj-$(CONFIG_QCOM_OCMEM) += ocmem.o
obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o
+obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
new file mode 100644
index 000000000000..d42127521eca
--- /dev/null
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/pdr.h>
+#include <linux/soc/qcom/pmic_glink.h>
+
+struct pmic_glink {
+ struct device *dev;
+ struct pdr_handle *pdr;
+
+ struct rpmsg_endpoint *ept;
+
+ struct auxiliary_device altmode_aux;
+ struct auxiliary_device ps_aux;
+ struct auxiliary_device ucsi_aux;
+
+ /* serializing client_state and pdr_state updates */
+ struct mutex state_lock;
+ unsigned int client_state;
+ unsigned int pdr_state;
+
+ /* serializing clients list updates */
+ struct mutex client_lock;
+ struct list_head clients;
+};
+
+static struct pmic_glink *__pmic_glink;
+static DEFINE_MUTEX(__pmic_glink_lock);
+
+struct pmic_glink_client {
+ struct list_head node;
+
+ struct pmic_glink *pmic;
+ unsigned int id;
+
+ void (*cb)(const void *data, size_t len, void *priv);
+ void (*pdr_notify)(void *priv, int state);
+ void *priv;
+};
+
+static void _devm_pmic_glink_release_client(struct device *dev, void *res)
+{
+ struct pmic_glink_client *client = *(struct pmic_glink_client **)res;
+ struct pmic_glink *pg = client->pmic;
+
+ mutex_lock(&pg->client_lock);
+ list_del(&client->node);
+ mutex_unlock(&pg->client_lock);
+}
+
+struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
+ unsigned int id,
+ void (*cb)(const void *, size_t, void *),
+ void (*pdr)(void *, int),
+ void *priv)
+{
+ struct pmic_glink_client *client;
+ struct pmic_glink *pg = dev_get_drvdata(dev->parent);
+
+ client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->pmic = pg;
+ client->id = id;
+ client->cb = cb;
+ client->pdr_notify = pdr;
+ client->priv = priv;
+
+ mutex_lock(&pg->client_lock);
+ list_add(&client->node, &pg->clients);
+ mutex_unlock(&pg->client_lock);
+
+ devres_add(dev, client);
+
+ return client;
+}
+EXPORT_SYMBOL_GPL(devm_pmic_glink_register_client);
+
+int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len)
+{
+ struct pmic_glink *pg = client->pmic;
+
+ return rpmsg_send(pg->ept, data, len);
+}
+EXPORT_SYMBOL_GPL(pmic_glink_send);
+
+static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
+ int len, void *priv, u32 addr)
+{
+ struct pmic_glink_client *client;
+ struct pmic_glink_hdr *hdr;
+ struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev);
+
+ if (len < sizeof(*hdr)) {
+ dev_warn(pg->dev, "ignoring truncated message\n");
+ return 0;
+ }
+
+ hdr = data;
+
+ list_for_each_entry(client, &pg->clients, node) {
+ if (client->id == le32_to_cpu(hdr->owner))
+ client->cb(data, len, client->priv);
+ }
+
+ return 0;
+}
+
+static void pmic_glink_aux_release(struct device *dev) {}
+
+static int pmic_glink_add_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux,
+ const char *name)
+{
+ struct device *parent = pg->dev;
+ int ret;
+
+ aux->name = name;
+ aux->dev.parent = parent;
+ aux->dev.release = pmic_glink_aux_release;
+ device_set_of_node_from_dev(&aux->dev, parent);
+ ret = auxiliary_device_init(aux);
+ if (ret)
+ return ret;
+
+ ret = auxiliary_device_add(aux);
+ if (ret)
+ auxiliary_device_uninit(aux);
+
+ return ret;
+}
+
+static void pmic_glink_del_aux_device(struct pmic_glink *pg,
+ struct auxiliary_device *aux)
+{
+ auxiliary_device_delete(aux);
+ auxiliary_device_uninit(aux);
+}
+
+static void pmic_glink_state_notify_clients(struct pmic_glink *pg)
+{
+ struct pmic_glink_client *client;
+ unsigned int new_state = pg->client_state;
+
+ if (pg->client_state != SERVREG_SERVICE_STATE_UP) {
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ new_state = SERVREG_SERVICE_STATE_UP;
+ } else {
+ if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept)
+ new_state = SERVREG_SERVICE_STATE_DOWN;
+ }
+
+ if (new_state != pg->client_state) {
+ list_for_each_entry(client, &pg->clients, node)
+ client->pdr_notify(client->priv, new_state);
+ pg->client_state = new_state;
+ }
+}
+
+static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv)
+{
+ struct pmic_glink *pg = priv;
+
+ mutex_lock(&pg->state_lock);
+ pg->pdr_state = state;
+
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+}
+
+static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg = __pmic_glink;
+ int ret = 0;
+
+ mutex_lock(&__pmic_glink_lock);
+ if (!pg) {
+ ret = dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n");
+ goto out_unlock;
+ }
+
+ dev_set_drvdata(&rpdev->dev, pg);
+
+ mutex_lock(&pg->state_lock);
+ pg->ept = rpdev->ept;
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+
+out_unlock:
+ mutex_unlock(&__pmic_glink_lock);
+ return ret;
+}
+
+static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ struct pmic_glink *pg;
+
+ mutex_lock(&__pmic_glink_lock);
+ pg = __pmic_glink;
+ if (!pg)
+ goto out_unlock;
+
+ mutex_lock(&pg->state_lock);
+ pg->ept = NULL;
+ pmic_glink_state_notify_clients(pg);
+ mutex_unlock(&pg->state_lock);
+out_unlock:
+ mutex_unlock(&__pmic_glink_lock);
+}
+
+static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = {
+ { "PMIC_RTR_ADSP_APPS" },
+ {}
+};
+
+static struct rpmsg_driver pmic_glink_rpmsg_driver = {
+ .probe = pmic_glink_rpmsg_probe,
+ .remove = pmic_glink_rpmsg_remove,
+ .callback = pmic_glink_rpmsg_callback,
+ .id_table = pmic_glink_rpmsg_id_match,
+ .drv = {
+ .name = "qcom_pmic_glink_rpmsg",
+ },
+};
+
+static int pmic_glink_probe(struct platform_device *pdev)
+{
+ struct pdr_service *service;
+ struct pmic_glink *pg;
+ int ret;
+
+ pg = devm_kzalloc(&pdev->dev, sizeof(*pg), GFP_KERNEL);
+ if (!pg)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, pg);
+
+ pg->dev = &pdev->dev;
+
+ INIT_LIST_HEAD(&pg->clients);
+ mutex_init(&pg->client_lock);
+ mutex_init(&pg->state_lock);
+
+ ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode");
+ if (ret)
+ return ret;
+ ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply");
+ if (ret)
+ goto out_release_altmode_aux;
+
+ pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg);
+ if (IS_ERR(pg->pdr)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), "failed to initialize pdr\n");
+ goto out_release_aux_devices;
+ }
+
+ service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd");
+ if (IS_ERR(service)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(service),
+ "failed adding pdr lookup for charger_pd\n");
+ goto out_release_pdr_handle;
+ }
+
+ mutex_lock(&__pmic_glink_lock);
+ __pmic_glink = pg;
+ mutex_unlock(&__pmic_glink_lock);
+
+ return 0;
+
+out_release_pdr_handle:
+ pdr_handle_release(pg->pdr);
+out_release_aux_devices:
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+out_release_altmode_aux:
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+
+ return ret;
+}
+
+static int pmic_glink_remove(struct platform_device *pdev)
+{
+ struct pmic_glink *pg = dev_get_drvdata(&pdev->dev);
+
+ pdr_handle_release(pg->pdr);
+
+ pmic_glink_del_aux_device(pg, &pg->ps_aux);
+ pmic_glink_del_aux_device(pg, &pg->altmode_aux);
+
+ mutex_lock(&__pmic_glink_lock);
+ __pmic_glink = NULL;
+ mutex_unlock(&__pmic_glink_lock);
+
+ return 0;
+}
+
+static const struct of_device_id pmic_glink_of_match[] = {
+ { .compatible = "qcom,pmic-glink", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
+
+static struct platform_driver pmic_glink_driver = {
+ .probe = pmic_glink_probe,
+ .remove = pmic_glink_remove,
+ .driver = {
+ .name = "qcom_pmic_glink",
+ .of_match_table = pmic_glink_of_match,
+ },
+};
+
+static int pmic_glink_init(void)
+{
+ platform_driver_register(&pmic_glink_driver);
+ register_rpmsg_driver(&pmic_glink_rpmsg_driver);
+
+ return 0;
+};
+module_init(pmic_glink_init);
+
+static void pmic_glink_exit(void)
+{
+ platform_driver_unregister(&pmic_glink_driver);
+ unregister_rpmsg_driver(&pmic_glink_rpmsg_driver);
+};
+module_exit(pmic_glink_exit);
+
+MODULE_DESCRIPTION("Qualcomm PMIC GLINK driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/soc/qcom/pmic_glink.h b/include/linux/soc/qcom/pmic_glink.h
new file mode 100644
index 000000000000..40470f8dfc1e
--- /dev/null
+++ b/include/linux/soc/qcom/pmic_glink.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022, Linaro Ltd
+ */
+#ifndef __PMIC_GLINK_H__
+#define __PMIC_GLINK_H__
+
+struct pmic_glink;
+struct pmic_glink_client;
+
+#define PMIC_GLINK_OWNER_BATTMGR 32778
+#define PMIC_GLINK_OWNER_USBC 32779
+#define PMIC_GLINK_OWNER_USBC_PAN 32780
+
+#define PMIC_GLINK_REQ_RESP 1
+#define PMIC_GLINK_NOTIFY 2
+
+struct pmic_glink_hdr {
+ __le32 owner;
+ __le32 type;
+ __le32 opcode;
+};
+
+int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len);
+
+struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev,
+ unsigned int id,
+ void (*cb)(const void *, size_t, void *),
+ void (*pdr)(void *, int),
+ void *priv);
+
+#endif
--
2.35.1
On 18/08/2022 06:15, Bjorn Andersson wrote:
> The PMIC GLINK service runs on one of the co-processors of some modern
> Qualcomm platforms and implements USB-C and battery managements. It uses
> a message based protocol over GLINK for communication with the OS, hence
> the name.
>
> The driver implemented provides the rpmsg device for communication and
> uses auxilirary bus to spawn off individual devices in respsective
typos:
auxiliary
respective
> subsystem. The auxilirary devices are spawned off from a
auxiliary
> platform_device, so that the drm_bridge is available early, to allow the
> DisplayPort driver to probe even before the remoteproc has spun up.
>
(...)
> +
> +static int pmic_glink_init(void)
> +{
> + platform_driver_register(&pmic_glink_driver);
> + register_rpmsg_driver(&pmic_glink_rpmsg_driver);
> +
> + return 0;
> +};
> +module_init(pmic_glink_init);
> +
> +static void pmic_glink_exit(void)
> +{
> + platform_driver_unregister(&pmic_glink_driver);
> + unregister_rpmsg_driver(&pmic_glink_rpmsg_driver);
Shouldn't this be in reversed order of init()? So first unregister
rpmsg, then platform driver.
> +};
> +module_exit(pmic_glink_exit);
> +
> +MODULE_DESCRIPTION("Qualcomm PMIC GLINK driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/soc/qcom/pmic_glink.h b/include/linux/soc/qcom/pmic_glink.h
> new file mode 100644
> index 000000000000..40470f8dfc1e
> --- /dev/null
> +++ b/include/linux/soc/qcom/pmic_glink.h
> @@ -0,0 +1,32 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022, Linaro Ltd
> + */
> +#ifndef __PMIC_GLINK_H__
I propose more detailed guard:
__SOC_QCOM_PMIC_GLINK_H__
> +#define __PMIC_GLINK_H__
Best regards,
Krzysztof
On 8/17/22 10:15 PM, Bjorn Andersson wrote:
> This implements the base PMIC GLINK driver, a power_supply driver and a driver
> for the USB Type-C altmode protocol. This has been tested and shown to provide
> battery information, USB Type-C switch and mux requests and DisplayPort
> notifications on SC8180X, SC8280XP and SM8350.
>
> Bjorn Andersson (4):
> dt-bindings: soc: qcom: Introduce PMIC GLINK binding
> soc: qcom: pmic_glink: Introduce base PMIC GLINK driver
> soc: qcom: pmic_glink: Introduce altmode support
> power: supply: Introduce Qualcomm PMIC GLINK power supply
>
> .../bindings/soc/qcom/qcom,pmic-glink.yaml | 98 ++
> drivers/power/supply/Kconfig | 9 +
> drivers/power/supply/Makefile | 1 +
> drivers/power/supply/qcom_battmgr.c | 1422 +++++++++++++++++
> drivers/soc/qcom/Kconfig | 14 +
> drivers/soc/qcom/Makefile | 2 +
> drivers/soc/qcom/pmic_glink.c | 336 ++++
> drivers/soc/qcom/pmic_glink_altmode.c | 477 ++++++
> include/linux/soc/qcom/pmic_glink.h | 32 +
> 9 files changed, 2391 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml
> create mode 100644 drivers/power/supply/qcom_battmgr.c
> create mode 100644 drivers/soc/qcom/pmic_glink.c
> create mode 100644 drivers/soc/qcom/pmic_glink_altmode.c
> create mode 100644 include/linux/soc/qcom/pmic_glink.h
>
Tested-by: Steev Klimaszewski <[email protected]> #Thinkpad X13s
On Wed, Aug 17, 2022 at 08:15:10PM -0700, Bjorn Andersson wrote:
> The PMIC GLINK service runs on one of the co-processors of some modern
> Qualcomm platforms and implements USB-C and battery managements. It uses
> a message based protocol over GLINK for communication with the OS, hence
> the name.
>
> The driver implemented provides the rpmsg device for communication and
> uses auxilirary bus to spawn off individual devices in respsective
> subsystem. The auxilirary devices are spawned off from a
> platform_device, so that the drm_bridge is available early, to allow the
> DisplayPort driver to probe even before the remoteproc has spun up.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
<snip>
> diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
> new file mode 100644
> index 000000000000..d42127521eca
> --- /dev/null
> +++ b/drivers/soc/qcom/pmic_glink.c
> @@ -0,0 +1,336 @@
<snip>
> +
> +static void _devm_pmic_glink_release_client(struct device *dev, void *res)
> +{
> + struct pmic_glink_client *client = *(struct pmic_glink_client **)res;
As Eric Chanudet pointed out to me, this should be:
struct pmic_glink_client *client = (struct pmic_glink_client *)res;
Otherwise you get a splat like below (which somehow resulted in my
panel output not to work on my x13s... not sure of the connection
there, and is easily reproducible with a probe deferal or qcom_battmgr
unload):
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000958
Mem abort info:
ESR = 0x0000000096000004
EC = 0x25: DABT (current EL), IL = 32 bits
ESR = 0x0000000096000004
EC = 0x25: DABT (current EL), IL = 32 bits
SET = 0, FnV = 0
EA = 0, S1PTW = 0
FSC = 0x04: level 0 translation fault
Data abort info:
ISV = 0, ISS = 0x00000004
CM = 0, WnR = 0
user pgtable: 4k pages, 48-bit VAs, pgdp=0000000106b92000
[0000000000000958] pgd=0000000000000000, p4d=0000000000000000
Internal error: Oops: 96000004 [#1] PREEMPT SMP
Modules linked in: llcc_qcom qcom_battmgr aes_ce_blk pmic_glink_altmode aes_ce_cipher ghash_ce gf128mul sha2_ce sha256_arm64 sha1_ce gpio_sbu_mux pmic_glink gpio_keys autofs4
CPU: 2 PID: 182 Comm: kworker/u16:5 Not tainted 6.0.0-rc6 #29
Hardware name: LENOVO 21BX0016US/21BX0016US, BIOS N3HET47W (1.19 ) 07/04/2022
Workqueue: events_unbound deferred_probe_work_func
pstate: 80400005 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : mutex_lock+0x1c/0x60
lr : _devm_pmic_glink_release_client+0x2c/0x74 [pmic_glink]
sp : ffff80000c553970
x29: ffff80000c553970 x28: 0000000000000000 x27: 0000000000000000
x26: ffffc297e181e0e8 x25: ffffc297e181d000 x24: ffffc2984efd9a80
x23: ffffc2984ea7a008 x22: ffff1738863cc3a0 x21: ffff80000c553a28
x20: 0000000000000958 x19: ffff1738863cc9f8 x18: ffffffffffffffff
x17: 0000000000000000 x16: ffffc2984e1bb110 x15: 61622d6d6f63713d
x14: ffffc2984f3b23e0 x13: 554e514553007972 x12: 0000000000000000
x11: 00313731333d4d55 x10: 0000000000000000 x9 : ffffc297e181d1cc
x8 : ffff80000c553910 x7 : 0000000000000000 x6 : 0000000080200016
x5 : 0000000000000038 x4 : 0000000000000000 x3 : 0000000000000958
x2 : ffff17388522c100 x1 : 0000000000000000 x0 : 0000000000000958
Call trace:
mutex_lock+0x1c/0x60
release_nodes+0x68/0x100
devres_release_all+0x94/0xf0
device_unbind_cleanup+0x20/0x70
device_release_driver_internal+0x214/0x260
device_release_driver+0x20/0x30
bus_remove_device+0xdc/0x170
device_del+0x178/0x3ac
pmic_glink_probe+0x1e8/0x240 [pmic_glink]
platform_probe+0x70/0xcc
really_probe+0xc8/0x3e0
__driver_probe_device+0x84/0x190
driver_probe_device+0x44/0x100
__device_attach_driver+0xc4/0x160
bus_for_each_drv+0x84/0xe0
__device_attach+0xa4/0x1c4
device_initial_probe+0x1c/0x30
bus_probe_device+0xa4/0xb0
deferred_probe_work_func+0xc0/0x114
process_one_work+0x1ec/0x470
worker_thread+0x74/0x410
kthread+0xfc/0x110
ret_from_fork+0x10/0x20
Code: d5384102 d503201f d2800001 aa0103e4 (c8e47c02)
---[ end trace 0000000000000000 ]---
All credit to Eric[0] on that, I'm just tying up loose ends.
[0] https://gitlab.com/ahalaney/linux/-/commit/1819fbccd03de430d9fd4c58ded35f5be83e9aa8
Thanks,
Andrew
> +static struct pmic_glink *__pmic_glink;
> +static DEFINE_MUTEX(__pmic_glink_lock);
Having this global device and lock to update pmic_glink struct pointer
might not work well if there are multiple pmic_glink devices that
corresponds to multiple pmic_glink channels (or rpmsg devices). This
is fine for the primary pmic_glink channel that supports mission mode
clients. However, to support debugging, there could be a secondary
pmic_glink channel and some clients under it.
> +struct pmic_glink_client {
> + struct list_head node;
> +
> + struct pmic_glink *pmic;
It would be good to name this pointer as "pg" or something.
[ Resending to Bjorn's current address. ]
On Wed, Aug 17, 2022 at 08:15:10PM -0700, Bjorn Andersson wrote:
> The PMIC GLINK service runs on one of the co-processors of some modern
> Qualcomm platforms and implements USB-C and battery managements. It uses
> a message based protocol over GLINK for communication with the OS, hence
> the name.
>
> The driver implemented provides the rpmsg device for communication and
> uses auxilirary bus to spawn off individual devices in respsective
> subsystem. The auxilirary devices are spawned off from a
> platform_device, so that the drm_bridge is available early, to allow the
> DisplayPort driver to probe even before the remoteproc has spun up.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> drivers/soc/qcom/Kconfig | 14 ++
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/pmic_glink.c | 336 ++++++++++++++++++++++++++++
> include/linux/soc/qcom/pmic_glink.h | 32 +++
> 4 files changed, 383 insertions(+)
> create mode 100644 drivers/soc/qcom/pmic_glink.c
> create mode 100644 include/linux/soc/qcom/pmic_glink.h
>
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index e0d7a5459562..2289f5e0d5ad 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -91,6 +91,20 @@ config QCOM_PDR_HELPERS
> tristate
> select QCOM_QMI_HELPERS
>
> +config QCOM_PMIC_GLINK
> + tristate "Qualcomm PMIC GLINK driver"
> + depends on RPMSG
> + depends on TYPEC
> + depends on DRM
You should add
select AUXILIARY_BUS
here as this driver will not compile without it. Then you can drop the
corresponding select from the battery driver.
> + select QCOM_PDR_HELPERS
> + help
> + The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
> + USB and battery firmware running on one of the coprocessors in
> + several modern Qualcomm platforms.
> +
> + Say yes here to support USB-C and battery status on modern Qualcomm
> + platforms.
Johan
On Wed, Aug 17, 2022 at 08:15:10PM -0700, Bjorn Andersson wrote:
> The PMIC GLINK service runs on one of the co-processors of some modern
> Qualcomm platforms and implements USB-C and battery managements. It uses
> a message based protocol over GLINK for communication with the OS, hence
> the name.
>
> The driver implemented provides the rpmsg device for communication and
> uses auxilirary bus to spawn off individual devices in respsective
> subsystem. The auxilirary devices are spawned off from a
> platform_device, so that the drm_bridge is available early, to allow the
> DisplayPort driver to probe even before the remoteproc has spun up.
>
> Signed-off-by: Bjorn Andersson <[email protected]>
> ---
> drivers/soc/qcom/Kconfig | 14 ++
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/pmic_glink.c | 336 ++++++++++++++++++++++++++++
> include/linux/soc/qcom/pmic_glink.h | 32 +++
> 4 files changed, 383 insertions(+)
> create mode 100644 drivers/soc/qcom/pmic_glink.c
> create mode 100644 include/linux/soc/qcom/pmic_glink.h
>
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> index e0d7a5459562..2289f5e0d5ad 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -91,6 +91,20 @@ config QCOM_PDR_HELPERS
> tristate
> select QCOM_QMI_HELPERS
>
> +config QCOM_PMIC_GLINK
> + tristate "Qualcomm PMIC GLINK driver"
> + depends on RPMSG
> + depends on TYPEC
> + depends on DRM
You should add
select AUXILIARY_BUS
here as this driver will not compile without it. Then you can drop the
corresponding select from the battery driver.
> + select QCOM_PDR_HELPERS
> + help
> + The Qualcomm PMIC GLINK driver provides access, over GLINK, to the
> + USB and battery firmware running on one of the coprocessors in
> + several modern Qualcomm platforms.
> +
> + Say yes here to support USB-C and battery status on modern Qualcomm
> + platforms.
Johan
On Wed, 17 Aug 2022 20:15:08 -0700, Bjorn Andersson wrote:
> This implements the base PMIC GLINK driver, a power_supply driver and a driver
> for the USB Type-C altmode protocol. This has been tested and shown to provide
> battery information, USB Type-C switch and mux requests and DisplayPort
> notifications on SC8180X, SC8280XP and SM8350.
>
> Bjorn Andersson (4):
> dt-bindings: soc: qcom: Introduce PMIC GLINK binding
> soc: qcom: pmic_glink: Introduce base PMIC GLINK driver
> soc: qcom: pmic_glink: Introduce altmode support
> power: supply: Introduce Qualcomm PMIC GLINK power supply
>
> [...]
Applied, thanks!
[1/4] dt-bindings: soc: qcom: Introduce PMIC GLINK binding
commit: 68d868adc121f68edde0f4c0e16923103b868945
[2/4] soc: qcom: pmic_glink: Introduce base PMIC GLINK driver
commit: 58ef4ece1e41ac525db3e79529909683325d85df
[3/4] soc: qcom: pmic_glink: Introduce altmode support
commit: 080b4e24852b1d5b66929f69344e6c3eeb963941
[4/4] power: supply: Introduce Qualcomm PMIC GLINK power supply
(no commit info)
Best regards,
--
Bjorn Andersson <[email protected]>