From nobody Tue Oct 7 11:37:27 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 21DA228B50A; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; cv=none; b=LOJOhLnODekMVWjpeLPtTNsLaKgRrMkx9APZDx10QQuMQrOdL3KGKm6IS4YMDz5GE0uI5EKixjCaB4duzWa+i814+0Dajbc8xwX94cOgLsclOGDttB/4AzFmCJuyngA+2HNA9kQYeK1vCUofEQV7d74bDBX2ZoFeLqdWGFQcfCg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; c=relaxed/simple; bh=tyuq3hwCRSgt2JKMB5Ao+hcQq+13/0Loc0oxGsCOY0M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cyKTKOS2lA+v8SSjFdtl+9P2WtNqnPkXcgv8NrYCsYtg/Qo0z//r8rKCA7gK16pV/HgCpRxvR1uWKZIIMuGnNvfuP3H7SOnazcr14TQT+33PJt7XWFw0MMz9gjtN4ERCDCO+vmAkE8OqfFfdo/fHjy4f2Hqka3b0hks83N0oM3E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UZ/2Kcpq; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UZ/2Kcpq" Received: by smtp.kernel.org (Postfix) with ESMTPS id AE32AC4CEF5; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1752134790; bh=tyuq3hwCRSgt2JKMB5Ao+hcQq+13/0Loc0oxGsCOY0M=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=UZ/2KcpqalDxdI8hG6ROVnnlKOt2KFNDUzvFVZDXeOrqnHv7mChslNyYE1Kd8IKCQ KQY5rtmfYhi0JZyik8BXYgTctqRh0iQqlnOq9sYWvR3R1QLGPdpM50l4SLUgU6Cr93 ykqfGWuhC88QJ0U4lOTQ+H5fSYoG2UPFCeDwE1LQv60+eMKby1mmWe3ZGKVjUOfq72 n/kAuaFUwRVZFphHPdtq9FwGCkhc4cGssmVk12qcEOMB307A3QytBPxHFRtG48JHQZ yo9v/6drcaQX2Wr7D4rFL5CwMqj6EkNl+waYRlRMndfn8AasNjRouTwmzdsm06WEgs J3NvGOsWRXTMg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9C7ABC83F09; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) From: Yassine Oudjana via B4 Relay Date: Thu, 10 Jul 2025 09:06:27 +0100 Subject: [PATCH v2 1/4] net: qrtr: smd: Rename qdev to qsdev Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250710-qcom-smgr-v2-1-f6e198b7aa8e@protonmail.com> References: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> In-Reply-To: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> To: Manivannan Sadhasivam , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Bjorn Andersson , Konrad Dybcio , Masahiro Yamada , Nathan Chancellor , Nicolas Schier , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Luca Weiss Cc: linux-arm-msm@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, linux-iio@vger.kernel.org, Yassine Oudjana X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1752134788; l=3304; i=y.oudjana@protonmail.com; s=20250710; h=from:subject:message-id; bh=NBj3Fu0MTFrWqXINim9NdBsnVOSNt9LjsMdF6y3k4Cg=; b=xjYXoOZOKB6m4nE87FAlppiLSPFtZkvYgwYdCoQH+m5AJ/1bfveSL4L0Z07eUL5vjOoa+Qies wG+oJ4uUrevDs5nCbxZ/VuWESwQ3SwRzIiOSpRB3YD5IYnEwwo4/j4W X-Developer-Key: i=y.oudjana@protonmail.com; a=ed25519; pk=kZKEHR1e5QKCbhElU9LF/T1SbfTr8xzy2cO8fN70QgY= X-Endpoint-Received: by B4 Relay for y.oudjana@protonmail.com/20250710 with auth_id=455 X-Original-From: Yassine Oudjana Reply-To: y.oudjana@protonmail.com From: Yassine Oudjana In preparation to turn QRTR into a bus, rename replace all current occurences of qdev in smd.c with qsdev in order to distinguish between the to-be-added QRTR device which represents a QRTR service with the existing QRTR SMD device which represents the endpoint through which services are provided. Signed-off-by: Yassine Oudjana --- net/qrtr/smd.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c index c91bf030fbc7d973a90a1f88e90e66df42ab2bdd..940ee9349a9ce7438a01dd193c5= c1d61c7b82ffd 100644 --- a/net/qrtr/smd.c +++ b/net/qrtr/smd.c @@ -20,15 +20,15 @@ struct qrtr_smd_dev { static int qcom_smd_qrtr_callback(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 addr) { - struct qrtr_smd_dev *qdev =3D dev_get_drvdata(&rpdev->dev); + struct qrtr_smd_dev *qsdev =3D dev_get_drvdata(&rpdev->dev); int rc; =20 - if (!qdev) + if (!qsdev) return -EAGAIN; =20 - rc =3D qrtr_endpoint_post(&qdev->ep, data, len); + rc =3D qrtr_endpoint_post(&qsdev->ep, data, len); if (rc =3D=3D -EINVAL) { - dev_err(qdev->dev, "invalid ipcrouter packet\n"); + dev_err(qsdev->dev, "invalid ipcrouter packet\n"); /* return 0 to let smd drop the packet */ rc =3D 0; } @@ -39,14 +39,14 @@ static int qcom_smd_qrtr_callback(struct rpmsg_device *= rpdev, /* from qrtr to smd */ static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *sk= b) { - struct qrtr_smd_dev *qdev =3D container_of(ep, struct qrtr_smd_dev, ep); + struct qrtr_smd_dev *qsdev =3D container_of(ep, struct qrtr_smd_dev, ep); int rc; =20 rc =3D skb_linearize(skb); if (rc) goto out; =20 - rc =3D rpmsg_send(qdev->channel, skb->data, skb->len); + rc =3D rpmsg_send(qsdev->channel, skb->data, skb->len); =20 out: if (rc) @@ -58,22 +58,24 @@ static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep,= struct sk_buff *skb) =20 static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev) { - struct qrtr_smd_dev *qdev; + struct qrtr_smd_dev *qsdev; int rc; =20 - qdev =3D devm_kzalloc(&rpdev->dev, sizeof(*qdev), GFP_KERNEL); - if (!qdev) + qsdev =3D devm_kzalloc(&rpdev->dev, sizeof(*qsdev), GFP_KERNEL); + if (!qsdev) return -ENOMEM; =20 - qdev->channel =3D rpdev->ept; - qdev->dev =3D &rpdev->dev; - qdev->ep.xmit =3D qcom_smd_qrtr_send; + qsdev->channel =3D rpdev->ept; + qsdev->dev =3D &rpdev->dev; + qsdev->ep.xmit =3D qcom_smd_qrtr_send; + qsdev->ep.add_device =3D qcom_smd_qrtr_add_device; + qsdev->ep.del_device =3D qcom_smd_qrtr_del_device; =20 - rc =3D qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO); + rc =3D qrtr_endpoint_register(&qsdev->ep, QRTR_EP_NID_AUTO); if (rc) return rc; =20 - dev_set_drvdata(&rpdev->dev, qdev); + dev_set_drvdata(&rpdev->dev, qsdev); =20 dev_dbg(&rpdev->dev, "Qualcomm SMD QRTR driver probed\n"); =20 @@ -82,9 +84,9 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev) =20 static void qcom_smd_qrtr_remove(struct rpmsg_device *rpdev) { - struct qrtr_smd_dev *qdev =3D dev_get_drvdata(&rpdev->dev); + struct qrtr_smd_dev *qsdev =3D dev_get_drvdata(&rpdev->dev); =20 - qrtr_endpoint_unregister(&qdev->ep); + qrtr_endpoint_unregister(&qsdev->ep); =20 dev_set_drvdata(&rpdev->dev, NULL); } --=20 2.50.0 From nobody Tue Oct 7 11:37:27 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 21E0828B50E; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; cv=none; b=LBhcv8kjV1n4k/W6qdBTbWTLRKqAILmSgfKxBZAjQb2YLP4UqCmUGA1OgzunteOJCScqVtTjR9IpL62SHPyPRAc9cn71RJHr2gKU3AtM94ByL+tS/sdzgGYMmw9KniktslN7RczwUxKDR4z6EHewkcVBqXAxzjttufBGgvQMBB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; c=relaxed/simple; bh=HEhZOrDen9GDQYkFTc80pO2Gobam8W9J62fqtXHgtNo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Hfy0l10zDZcp/odD1f7ioSPjIEMbLb+CWOfaqjnBAOyvnrhHobfDkcUaK7O5PzOD+f9fT9EOe93uWAnGoT53KTJNBx2ea1MWVuGjYg9wt1gna7kYOBiR+PVRDmjWAjs8khz8sQUbM+J7zpipS3txfNfNd9d6B1mnmFg/vGt5Zv4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Uj4gC0/N; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Uj4gC0/N" Received: by smtp.kernel.org (Postfix) with ESMTPS id BC778C4CEFA; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1752134790; bh=HEhZOrDen9GDQYkFTc80pO2Gobam8W9J62fqtXHgtNo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Uj4gC0/NYXW7pDdZdsIqYwAt5c6p3O7F2CK7ODWTjn90g1Lm5fA15BDumOBoDg6Ds OS3FuHXVTbQfIam/TdiFbUxcVoGaDm1E4qFK6lp++UO8zsKWHlLypzT6ZB3rWfqSz+ 4jZh4tej13iyxGtdcEduI1aUADXTz8VvFWY89JjM/XLo6I/NZ6Qet9YTI1AzUQ3ZD0 pNa6Kyjjg3zx8VdT7xLQFZQ53UK/nDBAJuWyUMTQ6guaF1Y6JAzhMfIqDHCBj8XN/x e4+mv2Zc4qwmUiJGiK15hF8ncNA2/2Kcju9tyIvX4k7Iuz4Npz+Qo2TWECNott0M4S Y8YSJiubhSuig== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id B0874C83F1D; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) From: Yassine Oudjana via B4 Relay Date: Thu, 10 Jul 2025 09:06:28 +0100 Subject: [PATCH v2 2/4] net: qrtr: Turn QRTR into a bus Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250710-qcom-smgr-v2-2-f6e198b7aa8e@protonmail.com> References: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> In-Reply-To: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> To: Manivannan Sadhasivam , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Bjorn Andersson , Konrad Dybcio , Masahiro Yamada , Nathan Chancellor , Nicolas Schier , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Luca Weiss Cc: linux-arm-msm@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, linux-iio@vger.kernel.org, Yassine Oudjana X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1752134788; l=13409; i=y.oudjana@protonmail.com; s=20250710; h=from:subject:message-id; bh=BEz6+mix/8Ro0NQY01YjtawBe2jefM7XH43H8tm5Dq0=; b=ZDD7byeRJ8P7n1x5fcHYw0FIO6mXnZSRcIFKOXREqnDhvllF1YWmSobf1UgfrvgPVyLND0lZi bmtBMlnztH3AhJIiiI618QFd6ecKVy7Y4L+QzqeFTU1eqPRyEJcTMJD X-Developer-Key: i=y.oudjana@protonmail.com; a=ed25519; pk=kZKEHR1e5QKCbhElU9LF/T1SbfTr8xzy2cO8fN70QgY= X-Endpoint-Received: by B4 Relay for y.oudjana@protonmail.com/20250710 with auth_id=455 X-Original-From: Yassine Oudjana Reply-To: y.oudjana@protonmail.com From: Yassine Oudjana Implement a QRTR bus to allow for creating drivers for individual QRTR services. With this in place, devices are dynamically registered for QRTR services as they become available, and drivers for these devices are matched using service and instance IDs. Signed-off-by: Yassine Oudjana --- include/linux/mod_devicetable.h | 9 ++ include/linux/soc/qcom/qrtr.h | 36 +++++++ net/qrtr/af_qrtr.c | 23 +++- net/qrtr/qrtr.h | 3 + net/qrtr/smd.c | 218 ++++++++++++++++++++++++++++++++++= +++- scripts/mod/devicetable-offsets.c | 4 + scripts/mod/file2alias.c | 10 ++ 7 files changed, 297 insertions(+), 6 deletions(-) diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetabl= e.h index 6077972e8b45de3d07881c0226459d815dd1f83d..23c6a1a4bca54f871c78765f8d5= 401cca5c1e6eb 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -549,6 +549,15 @@ struct spmi_device_id { kernel_ulong_t driver_data; /* Data private to the driver */ }; =20 +#define QRTR_NAME_SIZE 32 +#define QRTR_MODULE_PREFIX "qrtr:" + +struct qrtr_device_id { + __u16 service; + __u16 instance; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + /* dmi */ enum dmi_field { DMI_NONE, diff --git a/include/linux/soc/qcom/qrtr.h b/include/linux/soc/qcom/qrtr.h new file mode 100644 index 0000000000000000000000000000000000000000..e9249d9422b8ca96baa43073cf0= 7c4a75c163219 --- /dev/null +++ b/include/linux/soc/qcom/qrtr.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __QCOM_QRTR_H__ +#define __QCOM_QRTR_H__ + +#include + +struct qrtr_device { + struct device dev; + unsigned int node; + unsigned int port; + u16 service; + u16 instance; +}; + +#define to_qrtr_device(d) container_of(d, struct qrtr_device, dev) + +struct qrtr_driver { + int (*probe)(struct qrtr_device *qdev); + void (*remove)(struct qrtr_device *qdev); + const struct qrtr_device_id *id_table; + struct device_driver driver; +}; + +#define to_qrtr_driver(d) container_of(d, struct qrtr_driver, driver) + +#define qrtr_driver_register(drv) __qrtr_driver_register(drv, THIS_MODULE) + +int __qrtr_driver_register(struct qrtr_driver *drv, struct module *owner); +void qrtr_driver_unregister(struct qrtr_driver *drv); + +#define module_qrtr_driver(__qrtr_driver) \ + module_driver(__qrtr_driver, qrtr_driver_register, \ + qrtr_driver_unregister) + +#endif /* __QCOM_QRTR_H__ */ diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c index 00c51cf693f3d054f1771de5246498bf013775d0..e11682fd796083a9866527824fa= f428affba19bc 100644 --- a/net/qrtr/af_qrtr.c +++ b/net/qrtr/af_qrtr.c @@ -435,6 +435,7 @@ static void qrtr_node_assign(struct qrtr_node *node, un= signed int nid) int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t = len) { struct qrtr_node *node =3D ep->node; + const struct qrtr_ctrl_pkt *pkt; const struct qrtr_hdr_v1 *v1; const struct qrtr_hdr_v2 *v2; struct qrtr_sock *ipc; @@ -443,6 +444,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const = void *data, size_t len) size_t size; unsigned int ver; size_t hdrlen; + int ret =3D 0; =20 if (len =3D=3D 0 || len & 3) return -EINVAL; @@ -516,12 +518,24 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, cons= t void *data, size_t len) =20 qrtr_node_assign(node, cb->src_node); =20 + pkt =3D data + hdrlen; + if (cb->type =3D=3D QRTR_TYPE_NEW_SERVER) { /* Remote node endpoint can bridge other distant nodes */ - const struct qrtr_ctrl_pkt *pkt; - - pkt =3D data + hdrlen; qrtr_node_assign(node, le32_to_cpu(pkt->server.node)); + + /* Create a QRTR device */ + ret =3D ep->add_device(ep, le32_to_cpu(pkt->server.node), + le32_to_cpu(pkt->server.port), + le32_to_cpu(pkt->server.service), + le32_to_cpu(pkt->server.instance)); + if (ret) + goto err; + } else if (cb->type =3D=3D QRTR_TYPE_DEL_SERVER) { + /* Remove QRTR device corresponding to service */ + ret =3D ep->del_device(ep, le32_to_cpu(pkt->server.port)); + if (ret) + goto err; } =20 if (cb->type =3D=3D QRTR_TYPE_RESUME_TX) { @@ -543,8 +557,7 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const = void *data, size_t len) =20 err: kfree_skb(skb); - return -EINVAL; - + return ret ? ret : -EINVAL; } EXPORT_SYMBOL_GPL(qrtr_endpoint_post); =20 diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h index 3f2d28696062a56201f8774ee50fd1c3daa50708..6590483367304b97239de939d4f= 0206aac52c527 100644 --- a/net/qrtr/qrtr.h +++ b/net/qrtr/qrtr.h @@ -19,6 +19,9 @@ struct sk_buff; */ struct qrtr_endpoint { int (*xmit)(struct qrtr_endpoint *ep, struct sk_buff *skb); + int (*add_device)(struct qrtr_endpoint *parent, unsigned int node, unsign= ed int port, + u16 service, u16 instance); + int (*del_device)(struct qrtr_endpoint *parent, unsigned int port); /* private: not for endpoint use */ struct qrtr_node *node; }; diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c index 940ee9349a9ce7438a01dd193c5c1d61c7b82ffd..40fd32fa0890799a88b947b2b7b= c00c2249dea0d 100644 --- a/net/qrtr/smd.c +++ b/net/qrtr/smd.c @@ -7,6 +7,7 @@ #include #include #include +#include =20 #include "qrtr.h" =20 @@ -16,6 +17,197 @@ struct qrtr_smd_dev { struct device *dev; }; =20 +struct qrtr_new_server { + struct qrtr_smd_dev *parent; + unsigned int node; + unsigned int port; + u16 service; + u16 instance; + + struct work_struct work; +}; + +struct qrtr_del_server { + struct qrtr_smd_dev *parent; + unsigned int port; + + struct work_struct work; +}; + +static int qcom_smd_qrtr_device_match(struct device *dev, const struct dev= ice_driver *drv) +{ + struct qrtr_device *qdev =3D to_qrtr_device(dev); + struct qrtr_driver *qdrv =3D to_qrtr_driver(drv); + const struct qrtr_device_id *id =3D qdrv->id_table; + + if (!id) + return 0; + + while (id->service !=3D 0) { + if (id->service =3D=3D qdev->service && id->instance =3D=3D qdev->instan= ce) + return 1; + id++; + } + + return 0; +} + +static int qcom_smd_qrtr_uevent(const struct device *dev, struct kobj_ueve= nt_env *env) +{ + const struct qrtr_device *qdev =3D to_qrtr_device(dev); + + return add_uevent_var(env, "MODALIAS=3D%s%x:%x", QRTR_MODULE_PREFIX, qdev= ->service, + qdev->instance); +} + +static int qcom_smd_qrtr_device_probe(struct device *dev) +{ + struct qrtr_device *qdev =3D to_qrtr_device(dev); + struct qrtr_driver *qdrv =3D to_qrtr_driver(dev->driver); + + return qdrv->probe(qdev); +} + +static void qcom_smd_qrtr_device_remove(struct device *dev) +{ + struct qrtr_device *qdev =3D to_qrtr_device(dev); + struct qrtr_driver *qdrv =3D to_qrtr_driver(dev->driver); + + if (qdrv->remove) + qdrv->remove(qdev); +} + +const struct bus_type qrtr_bus =3D { + .name =3D "qrtr", + .match =3D qcom_smd_qrtr_device_match, + .uevent =3D qcom_smd_qrtr_uevent, + .probe =3D qcom_smd_qrtr_device_probe, + .remove =3D qcom_smd_qrtr_device_remove, +}; +EXPORT_SYMBOL_NS_GPL(qrtr_bus, "QRTR"); + +int __qrtr_driver_register(struct qrtr_driver *drv, struct module *owner) +{ + drv->driver.bus =3D &qrtr_bus; + drv->driver.owner =3D owner; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_NS_GPL(__qrtr_driver_register, "QRTR"); + +void qrtr_driver_unregister(struct qrtr_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_NS_GPL(qrtr_driver_unregister, "QRTR"); + +static void qcom_smd_qrtr_dev_release(struct device *dev) +{ + struct qrtr_device *qdev =3D to_qrtr_device(dev); + + kfree(qdev); +} + +static int qcom_smd_qrtr_match_device_by_port(struct device *dev, const vo= id *data) +{ + struct qrtr_device *qdev =3D to_qrtr_device(dev); + unsigned const int *port =3D data; + + return qdev->port =3D=3D *port; +} + +static void qcom_smd_qrtr_add_device_worker(struct work_struct *work) +{ + struct qrtr_new_server *new_server =3D container_of(work, struct qrtr_new= _server, work); + struct qrtr_smd_dev *qsdev =3D new_server->parent; + struct qrtr_device *qdev; + int ret; + + qdev =3D kzalloc(sizeof(*qdev), GFP_KERNEL); + if (!qdev) + return; + + *qdev =3D (struct qrtr_device) { + .node =3D new_server->node, + .port =3D new_server->port, + .service =3D new_server->service, + .instance =3D new_server->instance + }; + + devm_kfree(qsdev->dev, new_server); + + dev_set_name(&qdev->dev, "%d-%d", qdev->node, qdev->port); + + qdev->dev.bus =3D &qrtr_bus; + qdev->dev.parent =3D qsdev->dev; + qdev->dev.release =3D qcom_smd_qrtr_dev_release; + + ret =3D device_register(&qdev->dev); + if (ret) { + dev_err(qsdev->dev, "Failed to register QRTR device: %pe\n", ERR_PTR(ret= )); + put_device(&qdev->dev); + } +} + +static void qcom_smd_qrtr_del_device_worker(struct work_struct *work) +{ + struct qrtr_del_server *del_server =3D container_of(work, struct qrtr_del= _server, work); + struct qrtr_smd_dev *qsdev =3D del_server->parent; + struct device *dev =3D device_find_child(qsdev->dev, &del_server->port, + qcom_smd_qrtr_match_device_by_port); + + device_unregister(dev); +} + +static int qcom_smd_qrtr_add_device(struct qrtr_endpoint *parent, unsigned= int node, + unsigned int port, u16 service, u16 instance) +{ + struct qrtr_smd_dev *qsdev =3D container_of(parent, struct qrtr_smd_dev, = ep); + struct qrtr_new_server *new_server; + + new_server =3D devm_kzalloc(qsdev->dev, sizeof(*new_server), GFP_KERNEL); + if (!new_server) + return -ENOMEM; + + *new_server =3D (struct qrtr_new_server) { + .parent =3D qsdev, + .node =3D node, + .port =3D port, + .service =3D service, + .instance =3D instance + }; + + INIT_WORK(&new_server->work, qcom_smd_qrtr_add_device_worker); + schedule_work(&new_server->work); + + return 0; +} + +static int qcom_smd_qrtr_del_device(struct qrtr_endpoint *parent, unsigned= int port) +{ + struct qrtr_smd_dev *qsdev =3D container_of(parent, struct qrtr_smd_dev, = ep); + struct qrtr_del_server *del_server; + + del_server =3D devm_kzalloc(qsdev->dev, sizeof(*del_server), GFP_KERNEL); + if (!del_server) + return -ENOMEM; + + del_server->parent =3D qsdev; + del_server->port =3D port; + + INIT_WORK(&del_server->work, qcom_smd_qrtr_del_device_worker); + schedule_work(&del_server->work); + + return 0; +} + +static int qcom_smd_qrtr_device_unregister(struct device *dev, void *data) +{ + device_unregister(dev); + + return 0; +} + /* from smd to qrtr */ static int qcom_smd_qrtr_callback(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 addr) @@ -86,6 +278,8 @@ static void qcom_smd_qrtr_remove(struct rpmsg_device *rp= dev) { struct qrtr_smd_dev *qsdev =3D dev_get_drvdata(&rpdev->dev); =20 + device_for_each_child(qsdev->dev, NULL, qcom_smd_qrtr_device_unregister); + qrtr_endpoint_unregister(&qsdev->ep); =20 dev_set_drvdata(&rpdev->dev, NULL); @@ -106,7 +300,29 @@ static struct rpmsg_driver qcom_smd_qrtr_driver =3D { }, }; =20 -module_rpmsg_driver(qcom_smd_qrtr_driver); +static int __init qcom_smd_qrtr_init(void) +{ + int ret; + + ret =3D bus_register(&qrtr_bus); + if (ret) + return ret; + + ret =3D register_rpmsg_driver(&qcom_smd_qrtr_driver); + if (ret) + bus_unregister(&qrtr_bus); + + return ret; +} + +static void __exit qcom_smd_qrtr_exit(void) +{ + unregister_rpmsg_driver(&qcom_smd_qrtr_driver); + bus_unregister(&qrtr_bus); +} + +subsys_initcall(qcom_smd_qrtr_init); +module_exit(qcom_smd_qrtr_exit); =20 MODULE_ALIAS("rpmsg:IPCRTR"); MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver"); diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-of= fsets.c index d3d00e85edf73553ba3d9b5f9fccf1ff61c99026..0a90323c35d330f13a151948467= d72b927f474f3 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -280,5 +280,9 @@ int main(void) DEVID(coreboot_device_id); DEVID_FIELD(coreboot_device_id, tag); =20 + DEVID(qrtr_device_id); + DEVID_FIELD(qrtr_device_id, service); + DEVID_FIELD(qrtr_device_id, instance); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 00586119a25b7fd399eeeef3760a26467ffbb50c..fef69db4d7023305f03fd8bf85a= c60c47ae7d0ca 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1370,6 +1370,15 @@ static void do_coreboot_entry(struct module *mod, vo= id *symval) module_alias_printf(mod, false, "coreboot:t%08X", tag); } =20 +/* Looks like: qrtr:N:N */ +static void do_qrtr_entry(struct module *mod, void *symval) +{ + DEF_FIELD(symval, qrtr_device_id, service); + DEF_FIELD(symval, qrtr_device_id, instance); + + module_alias_printf(mod, false, "qrtr:%x:%x", service, instance); +} + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { @@ -1466,6 +1475,7 @@ static const struct devtable devtable[] =3D { {"usb", SIZE_usb_device_id, do_usb_entry_multi}, {"pnp", SIZE_pnp_device_id, do_pnp_device_entry}, {"pnp_card", SIZE_pnp_card_device_id, do_pnp_card_entry}, + {"qrtr", SIZE_qrtr_device_id, do_qrtr_entry}, }; =20 /* Create MODULE_ALIAS() statements. --=20 2.50.0 From nobody Tue Oct 7 11:37:27 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 44C9628B513; Thu, 10 Jul 2025 08:06:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; cv=none; b=GHqPp0bNMW1V1P5wcp6Njff9e4S/iMU6MXChjV8LekmXMUJ7hhKSK5zxLzG6LTkv2PmHU0hZPpTPNMeyVF8eECaM3001FDlYxYKHZIV77WQpOvuZdwQg+bcVqLnLXQwoYmVruEpn+e17mLfAqxfXH6xo/gbLOlSTtTrqYZc6aqk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; c=relaxed/simple; bh=NMO3uWbwHBgzseJ9NO1o7dQT1dcu9CFgfYN7QI/jC90=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=R/l2X3fzV2pUUd42XzwfMhIH+Eqpyvm/x+BjENVsqQMWloefY7r52z0mEcDLPvauKXUhdFPNfYhERoHBJyjvRbngEPbSifRH3rIXbBL4XKTrxUQ5HqCZIaQfa8FAbbb8kBovdAngQjDP9zsdXO5M9eaX3p6lzrXsuthg9PY+lwc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XyQi6LUO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XyQi6LUO" Received: by smtp.kernel.org (Postfix) with ESMTPS id D2DE9C4CEFB; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1752134790; bh=NMO3uWbwHBgzseJ9NO1o7dQT1dcu9CFgfYN7QI/jC90=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=XyQi6LUONMAUUbkH7eEuK4luyIPk0riQY+qjuCwYAl+RkbBqAnD3XVu+6PGk6vjhe Mqi6x8PeDPfv1u2SuFR3LR1SDHkZ2IZHIrynbyjdJH1Ra1mAUxMBttllyPlHMRxAdl 834+jSF9kYUjiw0oWQux7RKAPynJSCHR8Imuq1LqZSPgkC3WaZ/DM4wPUJ525YGxpR JV6jbZZBERvKt03pdotIh9USWc6Id88ZB5pa3+lBAovDt3vrdtZVRoB0C8tI+pdw09 O2Ts9TCDp3F39eT/bZXO8/g71IL6VdOwGTZEJnIL7Yc7IhPLdxAiwwhE+HIGTLKsUl +PWqwDJo/XoLg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id C59FEC83F18; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) From: Yassine Oudjana via B4 Relay Date: Thu, 10 Jul 2025 09:06:29 +0100 Subject: [PATCH v2 3/4] net: qrtr: Define macro to convert QMI version and instance to QRTR instance Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250710-qcom-smgr-v2-3-f6e198b7aa8e@protonmail.com> References: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> In-Reply-To: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> To: Manivannan Sadhasivam , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Bjorn Andersson , Konrad Dybcio , Masahiro Yamada , Nathan Chancellor , Nicolas Schier , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Luca Weiss Cc: linux-arm-msm@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, linux-iio@vger.kernel.org, Yassine Oudjana X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1752134788; l=2801; i=y.oudjana@protonmail.com; s=20250710; h=from:subject:message-id; bh=CdngQtC98LuPwMh1HJPPpnlIAibI0ynHsnrmaihvPoY=; b=pCKWZ0ajdUSXjuOj+1zI1jFgI6sXqzY9ZdCsJKqO/pHK1PARy7YA7K879AiWTOGokzg1p6CFd 2Ldzt/tAsWHDcDlxn28PKaYJ8zmXMeSMbQoYaiA6h+5xtwi+kB322Mq X-Developer-Key: i=y.oudjana@protonmail.com; a=ed25519; pk=kZKEHR1e5QKCbhElU9LF/T1SbfTr8xzy2cO8fN70QgY= X-Endpoint-Received: by B4 Relay for y.oudjana@protonmail.com/20250710 with auth_id=455 X-Original-From: Yassine Oudjana Reply-To: y.oudjana@protonmail.com From: Yassine Oudjana Move QRTR instance conversion from qmi_interface into a new macro in order to reuse it in QRTR device ID tables. Signed-off-by: Yassine Oudjana --- drivers/soc/qcom/qmi_interface.c | 5 +++-- include/linux/soc/qcom/qrtr.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interf= ace.c index 6500f863aae5ca218892d13233d4c9bf4b63a0f4..bd97b006757fc20778e4bb51294= 5d85f4cd31b24 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -14,6 +14,7 @@ #include #include #include +#include =20 static struct socket *qmi_sock_create(struct qmi_handle *qmi, struct sockaddr_qrtr *sq); @@ -173,7 +174,7 @@ static void qmi_send_new_lookup(struct qmi_handle *qmi,= struct qmi_service *svc) memset(&pkt, 0, sizeof(pkt)); pkt.cmd =3D cpu_to_le32(QRTR_TYPE_NEW_LOOKUP); pkt.server.service =3D cpu_to_le32(svc->service); - pkt.server.instance =3D cpu_to_le32(svc->version | svc->instance << 8); + pkt.server.instance =3D cpu_to_le32(QRTR_INSTANCE(svc->version, svc->inst= ance)); =20 sq.sq_family =3D qmi->sq.sq_family; sq.sq_node =3D qmi->sq.sq_node; @@ -236,7 +237,7 @@ static void qmi_send_new_server(struct qmi_handle *qmi,= struct qmi_service *svc) memset(&pkt, 0, sizeof(pkt)); pkt.cmd =3D cpu_to_le32(QRTR_TYPE_NEW_SERVER); pkt.server.service =3D cpu_to_le32(svc->service); - pkt.server.instance =3D cpu_to_le32(svc->version | svc->instance << 8); + pkt.server.instance =3D cpu_to_le32(QRTR_INSTANCE(svc->version, svc->inst= ance)); pkt.server.node =3D cpu_to_le32(qmi->sq.sq_node); pkt.server.port =3D cpu_to_le32(qmi->sq.sq_port); =20 diff --git a/include/linux/soc/qcom/qrtr.h b/include/linux/soc/qcom/qrtr.h index e9249d9422b8ca96baa43073cf07c4a75c163219..e2aca520fdbe22bc855004143dc= 8baa7a3f67517 100644 --- a/include/linux/soc/qcom/qrtr.h +++ b/include/linux/soc/qcom/qrtr.h @@ -3,6 +3,8 @@ #ifndef __QCOM_QRTR_H__ #define __QCOM_QRTR_H__ =20 +#include +#include #include =20 struct qrtr_device { @@ -15,6 +17,14 @@ struct qrtr_device { =20 #define to_qrtr_device(d) container_of(d, struct qrtr_device, dev) =20 +#define QRTR_INSTANCE(qmi_version, qmi_instance) \ + (FIELD_PREP(GENMASK(7, 0), qmi_version) | \ + FIELD_PREP(GENMASK(15, 8), qmi_instance)) + +#define QRTR_INSTANCE_CONST(qmi_version, qmi_instance) \ + (FIELD_PREP_CONST(GENMASK(7, 0), qmi_version) | \ + FIELD_PREP_CONST(GENMASK(15, 8), qmi_instance)) + struct qrtr_driver { int (*probe)(struct qrtr_device *qdev); void (*remove)(struct qrtr_device *qdev); --=20 2.50.0 From nobody Tue Oct 7 11:37:27 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6B27528BA85; Thu, 10 Jul 2025 08:06:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; cv=none; b=SPo7kwLVFtE8ixSG2yrgpM6fHwncqyKFA6i6N7CAtSB0e8NKtwMlFTQ7r06LY6EJx/OMzeTTPbcbbvvYusiIfbG2Z2gn+2PD2CFvDz2vPAuAjtTOob2X6rgsH1LEWadBhj2Mps/c0PWbtU73FHXdgR07e6qhpSKPAPyYFJJ3ZFI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752134791; c=relaxed/simple; bh=htRBoIczoOp4Og0zBNLXEu3VzyqYOQLKOWW9CuTS4P0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tALkl+fScufXHnLSq+B9Rogg+c+mULroE2+A+pH3uBnJSieSWV0JdzJPFmx6z/Wa/T9Qt1MAj8aLUmbmLErovVFPiaCnI4P+sYs/QhrSrkkiixWGVW3hnXqpSsuDIWg5i1fSHRz3DF0CVgWxJs0BtD73K/tq8MuShe17RWu2gDE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=H1mJNoAG; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="H1mJNoAG" Received: by smtp.kernel.org (Postfix) with ESMTPS id EADE1C113D0; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1752134791; bh=htRBoIczoOp4Og0zBNLXEu3VzyqYOQLKOWW9CuTS4P0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=H1mJNoAG+2kwLVK+nDgKLqHBuslTvQX88225bZealu/P8efc0vB/BCbRyYYuvYL3s Bon42fm2cY6nHxA1ZEOc74+MyhKg8DgGthhjl1Fjb/+s/1lcvqSEEx6w3pLbnlvJ9y YqpO5TG/De+aX8wL7IV6NQiX/vLcr18UW/328buLHZlrmihtQxFDOlBfVTD1BBOBbv ODBwyPIyOd+qpnPDlW65iM8zkNXoboTnx8S4quwZ/fH5nb8HFFIP7uKDS+3/Hf2pXW hBJ8Z0erJpD8tK7+FxXp/hPYFfpHGbAPmnbRRmJz4+s0jxEzfsVU5Ch5TmsuDT85Fh hW69/8HaVaTgQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id DFC15C83F1A; Thu, 10 Jul 2025 08:06:30 +0000 (UTC) From: Yassine Oudjana via B4 Relay Date: Thu, 10 Jul 2025 09:06:30 +0100 Subject: [PATCH v2 4/4] iio: Add Qualcomm Sensor Manager driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250710-qcom-smgr-v2-4-f6e198b7aa8e@protonmail.com> References: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> In-Reply-To: <20250710-qcom-smgr-v2-0-f6e198b7aa8e@protonmail.com> To: Manivannan Sadhasivam , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Bjorn Andersson , Konrad Dybcio , Masahiro Yamada , Nathan Chancellor , Nicolas Schier , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko , Luca Weiss Cc: linux-arm-msm@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kbuild@vger.kernel.org, linux-iio@vger.kernel.org, Yassine Oudjana X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1752134788; l=60335; i=y.oudjana@protonmail.com; s=20250710; h=from:subject:message-id; bh=Gc2DH6kkSHNi0gOWRr3ov8zs35p+GBLQEFu50V4nhIY=; b=06M8Y/NmwP6lOO74zhclohdS5l/XNU4VY+imNJ1++JKcDhE7pmdxLrtQVgZjEcqUuZABWAshp kABwHDnbSzgBuy2bHhHPAqy2pE1PdUhD3zfwRTAMYZYbGm0twNacZqh X-Developer-Key: i=y.oudjana@protonmail.com; a=ed25519; pk=kZKEHR1e5QKCbhElU9LF/T1SbfTr8xzy2cO8fN70QgY= X-Endpoint-Received: by B4 Relay for y.oudjana@protonmail.com/20250710 with auth_id=455 X-Original-From: Yassine Oudjana Reply-To: y.oudjana@protonmail.com From: Yassine Oudjana Add a driver for sensors exposed by the Qualcomm Sensor Manager service, which is provided by SLPI or ADSP on Qualcomm SoCs. Supported sensors include accelerometers, gyroscopes, pressure sensors, proximity sensors and magnetometers. Signed-off-by: Yassine Oudjana --- MAINTAINERS | 13 + drivers/iio/accel/qcom_smgr_accel.c | 138 ++++ drivers/iio/common/Kconfig | 1 + drivers/iio/common/Makefile | 1 + drivers/iio/common/qcom_smgr/Kconfig | 16 + drivers/iio/common/qcom_smgr/Makefile | 8 + drivers/iio/common/qcom_smgr/qcom_smgr.c | 840 ++++++++++++++++++++= ++++ drivers/iio/common/qcom_smgr/qmi/Makefile | 3 + drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.c | 713 ++++++++++++++++++++ drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.h | 161 +++++ include/linux/iio/common/qcom_smgr.h | 80 +++ 11 files changed, 1974 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b5a472a544cfe2ad87691209c34d7bafe058ba42..0fb91c9bce431fc899776ff10b7= 28ecdc957f51a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20702,6 +20702,19 @@ F: Documentation/networking/device_drivers/cellula= r/qualcomm/rmnet.rst F: drivers/net/ethernet/qualcomm/rmnet/ F: include/linux/if_rmnet.h =20 +QUALCOMM SENSOR MANAGER IIO DRIVER +M: Yassine Oudjana +L: linux-iio@vger.kernel.org +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: drivers/iio/common/qcom_smgr/Kconfig +F: drivers/iio/common/qcom_smgr/Makefile +F: drivers/iio/common/qcom_smgr/qcom_smgr.c +F: drivers/iio/common/qcom_smgr/qmi/Makefile +F: drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.c +F: drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.h +F: include/linux/iio/common/qcom_smgr.h + QUALCOMM TRUST ZONE MEMORY ALLOCATOR M: Bartosz Golaszewski L: linux-arm-msm@vger.kernel.org diff --git a/drivers/iio/accel/qcom_smgr_accel.c b/drivers/iio/accel/qcom_s= mgr_accel.c new file mode 100644 index 0000000000000000000000000000000000000000..ce854312d1d9386300785f1965d= 5886c16995806 --- /dev/null +++ b/drivers/iio/accel/qcom_smgr_accel.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Qualcomm Sensor Manager accelerometer driver + * + * Copyright (c) 2022, Yassine Oudjana + */ + +#include +#include +#include +#include +#include +#include + +static const struct iio_chan_spec qcom_smgr_accel_iio_channels[] =3D { + { + .type =3D IIO_ACCEL, + .modified =3D true, + .channel2 =3D IIO_MOD_X, + .scan_index =3D 0, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_ACCEL, + .modified =3D true, + .channel2 =3D IIO_MOD_Y, + .scan_index =3D 1, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_ACCEL, + .modified =3D true, + .channel2 =3D IIO_MOD_Z, + .scan_index =3D 2, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_TIMESTAMP, + .channel =3D -1, + .scan_index =3D 3, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 64, + .endianness =3D IIO_LE, + }, + }, +}; + +static int qcom_smgr_accel_probe(struct platform_device *pdev) +{ + struct iio_dev *iio_dev; + struct qcom_smgr_iio_priv *priv; + int ret; + + iio_dev =3D devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + if (!iio_dev) + return -ENOMEM; + + priv =3D iio_priv(iio_dev); + priv->sensor =3D *(struct qcom_smgr_sensor **)pdev->dev.platform_data; + priv->sensor->iio_dev =3D iio_dev; + + iio_dev->name =3D "qcom-smgr-accel"; + iio_dev->info =3D &qcom_smgr_iio_info; + iio_dev->channels =3D qcom_smgr_accel_iio_channels; + iio_dev->num_channels =3D ARRAY_SIZE(qcom_smgr_accel_iio_channels); + + ret =3D devm_iio_kfifo_buffer_setup(&pdev->dev, iio_dev, + &qcom_smgr_buffer_ops); + if (ret) { + dev_err(&pdev->dev, "Failed to setup buffer: %pe\n", + ERR_PTR(ret)); + return ret; + } + + ret =3D devm_iio_device_register(&pdev->dev, iio_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register IIO device: %pe\n", + ERR_PTR(ret)); + return ret; + } + + platform_set_drvdata(pdev, priv->sensor); + + return 0; +} + +static void qcom_smgr_accel_remove(struct platform_device *pdev) +{ + struct qcom_smgr_sensor *sensor =3D platform_get_drvdata(pdev); + + sensor->iio_dev =3D NULL; +} + +static const struct platform_device_id qcom_smgr_accel_ids[] =3D { + { .name =3D "qcom-smgr-accel" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, qcom_smgr_accel_ids); + +static struct platform_driver qcom_smgr_accel_driver =3D { + .probe =3D qcom_smgr_accel_probe, + .remove =3D qcom_smgr_accel_remove, + .driver =3D { + .name =3D "qcom_smgr_accel", + }, + .id_table =3D qcom_smgr_accel_ids, +}; +module_platform_driver(qcom_smgr_accel_driver); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("Qualcomm Sensor Manager accelerometer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig index 1ccb5ccf3706609fc57a4ade7c6a4354fa41c6bd..0ad8b39720874ca64a5560384e8= cb6ae78fac1cf 100644 --- a/drivers/iio/common/Kconfig +++ b/drivers/iio/common/Kconfig @@ -8,5 +8,6 @@ source "drivers/iio/common/hid-sensors/Kconfig" source "drivers/iio/common/inv_sensors/Kconfig" source "drivers/iio/common/ms_sensors/Kconfig" source "drivers/iio/common/scmi_sensors/Kconfig" +source "drivers/iio/common/qcom_smgr/Kconfig" source "drivers/iio/common/ssp_sensors/Kconfig" source "drivers/iio/common/st_sensors/Kconfig" diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile index d3e952239a62191decd0bf3e84c7b59cc46bcfb3..f3f18484c91b9215f9302985fcc= 7e0aa401a7a4e 100644 --- a/drivers/iio/common/Makefile +++ b/drivers/iio/common/Makefile @@ -13,5 +13,6 @@ obj-y +=3D hid-sensors/ obj-y +=3D inv_sensors/ obj-y +=3D ms_sensors/ obj-y +=3D scmi_sensors/ +obj-y +=3D qcom_smgr/ obj-y +=3D ssp_sensors/ obj-y +=3D st_sensors/ diff --git a/drivers/iio/common/qcom_smgr/Kconfig b/drivers/iio/common/qcom= _smgr/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..30baee9b0eff2bf90a6047f14c4= dfb9d70d28792 --- /dev/null +++ b/drivers/iio/common/qcom_smgr/Kconfig @@ -0,0 +1,16 @@ +# +# Qualcomm Sensor Manager IIO +# + +config IIO_QCOM_SMGR + tristate "Qualcomm SSC Sensor Manager" + depends on ARCH_QCOM + depends on QRTR_SMD + select QCOM_QMI_HELPERS + select IIO_BUFFER + help + Say yes here to build support for the Sensor Manager (SMGR) + service provided by the Qualcomm Snapdragon Sensor Core (SSC). + + To compile this driver as a module, choose M here: the + module will be called smgr. diff --git a/drivers/iio/common/qcom_smgr/Makefile b/drivers/iio/common/qco= m_smgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..84554cedd2e5f2f13c04df884e1= b51d3b9d8a9cf --- /dev/null +++ b/drivers/iio/common/qcom_smgr/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for Qualcomm Sensor Manager driver +# + +obj-y +=3D qmi/ + +obj-$(CONFIG_IIO_QCOM_SMGR) +=3D qcom_smgr.o diff --git a/drivers/iio/common/qcom_smgr/qcom_smgr.c b/drivers/iio/common/= qcom_smgr/qcom_smgr.c new file mode 100644 index 0000000000000000000000000000000000000000..79d1160f7a5c32f1a9e0a20f29e= 304e5cb18be8f --- /dev/null +++ b/drivers/iio/common/qcom_smgr/qcom_smgr.c @@ -0,0 +1,840 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Qualcomm Sensor Manager driver + * + * Copyright (c) 2021-2025, Yassine Oudjana + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qmi/qmi_sns_smgr.h" + +MODULE_IMPORT_NS("QRTR"); + +#define SMGR_TICKS_PER_SECOND 32768 +#define SMGR_REPORT_RATE_HZ (SMGR_TICKS_PER_SECOND * 2) +#define SMGR_VALUE_DECIMAL_OFFSET 16 + +static int qcom_smgr_request_all_sensor_info(struct qcom_smgr *smgr, + struct qcom_smgr_sensor **sensors) +{ + struct sns_smgr_all_sensor_info_resp resp =3D {}; + struct qmi_txn txn; + u8 i; + int ret; + + dev_dbg(smgr->dev, "Getting available sensors\n"); + + ret =3D qmi_txn_init(&smgr->sns_smgr_hdl, &txn, + sns_smgr_all_sensor_info_resp_ei, &resp); + if (ret < 0) { + dev_err(smgr->dev, "Failed to initialize QMI TXN: %d\n", ret); + return ret; + } + + ret =3D qmi_send_request(&smgr->sns_smgr_hdl, &smgr->sns_smgr_info, &txn, + SNS_SMGR_ALL_SENSOR_INFO_MSG_ID, + SNS_SMGR_ALL_SENSOR_INFO_REQ_MAX_LEN, NULL, + NULL); + if (ret) { + dev_err(smgr->dev, + "Failed to send available sensors request: %d\n", ret); + qmi_txn_cancel(&txn); + return ret; + } + + ret =3D qmi_txn_wait(&txn, 5 * HZ); + if (ret < 0) + return ret; + + /* Check the response */ + if (resp.result) { + dev_err(smgr->dev, "Available sensors request failed: 0x%x\n", + resp.result); + return -EREMOTEIO; + } + + *sensors =3D devm_kzalloc(smgr->dev, + sizeof(struct qcom_smgr_sensor) * resp.item_len, + GFP_KERNEL); + + for (i =3D 0; i < resp.item_len; ++i) { + (*sensors)[i].id =3D resp.items[i].id; + (*sensors)[i].type =3D + sns_smgr_sensor_type_from_str(resp.items[i].type); + } + + return resp.item_len; +} + +static int qcom_smgr_request_single_sensor_info(struct qcom_smgr *smgr, + struct qcom_smgr_sensor *sensor) +{ + struct sns_smgr_single_sensor_info_req req =3D { + .sensor_id =3D sensor->id, + }; + struct sns_smgr_single_sensor_info_resp resp =3D {}; + struct qmi_txn txn; + u8 i; + int ret; + + dev_vdbg(smgr->dev, "Getting single sensor info for ID 0x%02x\n", + sensor->id); + + ret =3D qmi_txn_init(&smgr->sns_smgr_hdl, &txn, + sns_smgr_single_sensor_info_resp_ei, &resp); + if (ret < 0) { + dev_err(smgr->dev, "Failed to initialize QMI transaction: %d\n", + ret); + return ret; + } + + ret =3D qmi_send_request(&smgr->sns_smgr_hdl, &smgr->sns_smgr_info, &txn, + SNS_SMGR_SINGLE_SENSOR_INFO_MSG_ID, + SNS_SMGR_SINGLE_SENSOR_INFO_REQ_MAX_LEN, + sns_smgr_single_sensor_info_req_ei, &req); + if (ret < 0) { + dev_err(smgr->dev, "Failed to send sensor data request: %d\n", + ret); + qmi_txn_cancel(&txn); + return ret; + } + + ret =3D qmi_txn_wait(&txn, 5 * HZ); + if (ret < 0) + return ret; + + /* Check the response */ + if (resp.result) { + dev_err(smgr->dev, "Single sensor info request failed: 0x%x\n", + resp.result); + return -EREMOTEIO; + } + + sensor->data_type_count =3D resp.data_type_len; + sensor->data_types =3D + devm_kzalloc(smgr->dev, + sizeof(struct qcom_smgr_data_type_item) * + sensor->data_type_count, + GFP_KERNEL); + if (!sensor->data_types) + return -ENOMEM; + + for (i =3D 0; i < sensor->data_type_count; ++i) { + sensor->data_types[i].name =3D devm_kstrdup_const( + smgr->dev, resp.data_types[i].name, GFP_KERNEL); + sensor->data_types[i].vendor =3D devm_kstrdup_const( + smgr->dev, resp.data_types[i].vendor, GFP_KERNEL); + + sensor->data_types[i].range =3D resp.data_types[i].range; + + sensor->data_types[i].native_sample_rate_count =3D + resp.native_sample_rates[i].rate_count; + if (sensor->data_types[i].native_sample_rate_count) { + sensor->data_types[i] + .native_sample_rates =3D devm_kmemdup_array( + smgr->dev, resp.native_sample_rates[i].rates, + sensor->data_types[i].native_sample_rate_count, + sizeof(u16), GFP_KERNEL); + if (!sensor->data_types[i].native_sample_rates) + return -ENOMEM; + } + + sensor->data_types[i].max_sample_rate =3D + resp.data_types[i].max_sample_rate_hz; + } + + return 0; +} + +static int qcom_smgr_request_buffering(struct qcom_smgr *smgr, + struct qcom_smgr_sensor *sensor, + bool enable) +{ + struct sns_smgr_buffering_req req =3D { + /* + * Reuse sensor ID as a report ID to avoid having to keep track + * of a separate set of IDs + */ + .report_id =3D sensor->id, + .notify_suspend_valid =3D false + }; + struct sns_smgr_buffering_resp resp =3D {}; + struct qmi_txn txn; + u16 sample_rate =3D 0; + int ret; + + if (enable) { + req.action =3D SNS_SMGR_BUFFERING_ACTION_ADD; + + /* + * Report rate and sample rate can be configured separately. + * The former is the rate at which buffering report indications + * are sent, while the latter is the actual sample rate of the + * sensor. If report rate is set lower than sample rate, + * multiple samples can be bundled and sent in one report. + * A report cannot have 0 samples, therefore report rate cannot + * be higher than sample rate. + * + * Fow now we default to the maximum sample rate and set the + * report rate such that every report contains only 1 sample. + * This gives us the lowest latency. + */ + if (sensor->data_types[0].native_sample_rates) + sample_rate =3D sensor->data_types[0].native_sample_rates + [sensor->data_types[0] + .native_sample_rate_count - 1]; + + /* + * SMGR may support a lower maximum sample rate than natively + * supported by the sensor. + */ + if (sample_rate =3D=3D 0 || + sample_rate > sensor->data_types[0].max_sample_rate) + sample_rate =3D sensor->data_types[0].max_sample_rate; + + req.report_rate =3D sample_rate * SMGR_REPORT_RATE_HZ; + + req.item_len =3D 1; + req.items[0].sensor_id =3D sensor->id; + req.items[0].data_type =3D SNS_SMGR_DATA_TYPE_PRIMARY; + + req.items[0].sampling_rate =3D sample_rate; + + /* + * Unknown fields set to values frequently seen in dumps and + * known to be working (although many different random values + * appear to not cause any trouble). + */ + req.items[0].val1 =3D 3; + req.items[0].val2 =3D 1; + } else + req.action =3D SNS_SMGR_BUFFERING_ACTION_DELETE; + + ret =3D qmi_txn_init(&smgr->sns_smgr_hdl, &txn, + sns_smgr_buffering_resp_ei, &resp); + if (ret < 0) { + dev_err(smgr->dev, "Failed to initialize QMI TXN: %d\n", ret); + return ret; + } + + ret =3D qmi_send_request(&smgr->sns_smgr_hdl, &smgr->sns_smgr_info, &txn, + SNS_SMGR_BUFFERING_MSG_ID, + SNS_SMGR_BUFFERING_REQ_MAX_LEN, + sns_smgr_buffering_req_ei, &req); + if (ret < 0) { + dev_err(smgr->dev, "Failed to send buffering request: %d\n", + ret); + qmi_txn_cancel(&txn); + return ret; + } + + ret =3D qmi_txn_wait(&txn, 5 * HZ); + if (ret < 0) + return ret; + + /* Check the response */ + if (resp.result) { + dev_err(smgr->dev, "Buffering request failed: 0x%x\n", + resp.result); + return -EREMOTEIO; + } + + /* Keep track of requested sample rate */ + sensor->data_types[0].cur_sample_rate =3D sample_rate; + + return 0; +} + +static void qcom_smgr_buffering_report_handler(struct qmi_handle *hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, + const void *data) +{ + struct qcom_smgr *smgr =3D + container_of(hdl, struct qcom_smgr, sns_smgr_hdl); + const struct sns_smgr_buffering_report_ind *ind =3D data; + struct qcom_smgr_sensor *sensor; + struct qcom_smgr_iio_data iio_data; + int temp; + u8 i, j; + + for (i =3D 0; i < smgr->sensor_count; ++i) { + sensor =3D &smgr->sensors[i]; + + /* Find sensor matching report */ + if (sensor->id =3D=3D ind->report_id) + break; + } + + if (i =3D=3D smgr->sensor_count) { + dev_warn_ratelimited(smgr->dev, + "Received buffering report with unknown ID: %02x", + ind->report_id); + return; + } + + /* + * Construct data to be passed to IIO. Since we are matching report rate + * with sample rate, we only get a single sample in every report. + */ + for (j =3D 0; j < ARRAY_SIZE(ind->samples[0].values); ++j) + iio_data.values[j] =3D ind->samples[0].values[j]; + + /* + * SMGR reports sensor data in 32-bit fixed-point values, with 16 bits + * holding the integer part and the other 16 bits holding the numerator + * of a fraction with the denominator 2**16. + * + * Proximity sensor values are reported differently from other sensors. + * The value reported is a boolean (0 or 1, still in the same fixed-point + * format) where 1 means the sensor is activated, i.e. something is + * within its range. Use the reported range to pass an actual distance + * value to IIO. We pass the sensor range when nothing is within range + * (sensor maxed out) and 0 when something is within range (assume + * sensor is covered). + */ + if (sensor->type =3D=3D SNS_SMGR_SENSOR_TYPE_PROX_LIGHT) { + temp =3D le32_to_cpu(iio_data.values[0]); + temp >>=3D SMGR_VALUE_DECIMAL_OFFSET; + temp =3D ~temp & 1; + temp *=3D sensor->data_types[0].range; + iio_data.values[0] =3D cpu_to_le32(temp); + } + + iio_push_to_buffers(sensor->iio_dev, &iio_data); +} + +static const struct qmi_msg_handler qcom_smgr_msg_handlers[] =3D { + { + .type =3D QMI_INDICATION, + .msg_id =3D SNS_SMGR_BUFFERING_REPORT_MSG_ID, + .ei =3D sns_smgr_buffering_report_ind_ei, + .decoded_size =3D sizeof(struct sns_smgr_buffering_report_ind), + .fn =3D qcom_smgr_buffering_report_handler, + }, + { } +}; + +static int qcom_smgr_sensor_postenable(struct iio_dev *iio_dev) +{ + struct qcom_smgr *smgr =3D dev_get_drvdata(iio_dev->dev.parent); + struct qcom_smgr_iio_priv *priv =3D iio_priv(iio_dev); + struct qcom_smgr_sensor *sensor =3D priv->sensor; + + return qcom_smgr_request_buffering(smgr, sensor, true); +} + +static int qcom_smgr_sensor_predisable(struct iio_dev *iio_dev) +{ + struct qcom_smgr *smgr =3D dev_get_drvdata(iio_dev->dev.parent); + struct qcom_smgr_iio_priv *priv =3D iio_priv(iio_dev); + struct qcom_smgr_sensor *sensor =3D priv->sensor; + + dev_info(smgr->dev, "disable buffering %02x\n", sensor->id); + return qcom_smgr_request_buffering(smgr, sensor, false); +} + +static const struct iio_buffer_setup_ops qcom_smgr_buffer_ops =3D { + .postenable =3D &qcom_smgr_sensor_postenable, + .predisable =3D &qcom_smgr_sensor_predisable +}; + +/* SMGR reports values for 3-axis sensors in north-east-down coordinates */ +static const struct iio_mount_matrix qcom_smgr_iio_mount_matrix =3D { + .rotation =3D { + "0", "-1", "0", + "-1", "0", "0", + "0", "0", "1" + } +}; + +static const struct iio_mount_matrix * +qcom_smgr_iio_get_mount_matrix(const struct iio_dev *iio_dev, + const struct iio_chan_spec *chan) +{ + return &qcom_smgr_iio_mount_matrix; +} + +static const struct iio_chan_spec_ext_info qcom_smgr_iio_ext_info[] =3D { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, qcom_smgr_iio_get_mount_matrix), + { } +}; + +static int qcom_smgr_iio_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct qcom_smgr_iio_priv *priv =3D iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *val =3D priv->sensor->data_types[0].cur_sample_rate; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val =3D 1; + *val2 =3D 1 << SMGR_VALUE_DECIMAL_OFFSET; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int qcom_smgr_iio_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct qcom_smgr_iio_priv *priv =3D iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (!iio_device_claim_direct(iio_dev)) + return -EBUSY; + + priv->sensor->data_types[0].cur_sample_rate =3D val; + + iio_device_release_direct(iio_dev); + return 0; + default: + return -EINVAL; + } +} + +static int qcom_smgr_iio_read_avail(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct qcom_smgr_iio_priv *priv =3D iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *type =3D IIO_VAL_INT; + *vals =3D priv->samp_freq_vals; + *length =3D ARRAY_SIZE(priv->samp_freq_vals); + return IIO_AVAIL_RANGE; + default: + return -EINVAL; + } +} + +static const struct iio_info qcom_smgr_iio_info =3D { + .read_raw =3D qcom_smgr_iio_read_raw, + .write_raw =3D qcom_smgr_iio_write_raw, + .read_avail =3D qcom_smgr_iio_read_avail, +}; + +static const struct iio_chan_spec qcom_smgr_accel_iio_channels[] =3D { + { + .type =3D IIO_ACCEL, + .modified =3D true, + .channel2 =3D IIO_MOD_X, + .scan_index =3D 0, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_ACCEL, + .modified =3D true, + .channel2 =3D IIO_MOD_Y, + .scan_index =3D 1, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_ACCEL, + .modified =3D true, + .channel2 =3D IIO_MOD_Z, + .scan_index =3D 2, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_TIMESTAMP, + .channel =3D -1, + .scan_index =3D 3, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 64, + .endianness =3D IIO_LE, + }, + } +}; + +static const struct iio_chan_spec qcom_smgr_gyro_iio_channels[] =3D { + { + .type =3D IIO_ANGL_VEL, + .modified =3D true, + .channel2 =3D IIO_MOD_X, + .scan_index =3D 0, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_ANGL_VEL, + .modified =3D true, + .channel2 =3D IIO_MOD_Y, + .scan_index =3D 1, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_ANGL_VEL, + .modified =3D true, + .channel2 =3D IIO_MOD_Z, + .scan_index =3D 2, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_TIMESTAMP, + .channel =3D -1, + .scan_index =3D 3, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 64, + .endianness =3D IIO_LE, + }, + } +}; + +static const struct iio_chan_spec qcom_smgr_mag_iio_channels[] =3D { + { + .type =3D IIO_MAGN, + .modified =3D true, + .channel2 =3D IIO_MOD_X, + .scan_index =3D 0, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_MAGN, + .modified =3D true, + .channel2 =3D IIO_MOD_Y, + .scan_index =3D 1, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_MAGN, + .modified =3D true, + .channel2 =3D IIO_MOD_Z, + .scan_index =3D 2, + .scan_type =3D { + .sign =3D 's', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_shared_by_type =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .ext_info =3D qcom_smgr_iio_ext_info + }, + { + .type =3D IIO_TIMESTAMP, + .channel =3D -1, + .scan_index =3D 3, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 64, + .endianness =3D IIO_LE, + }, + } +}; + +static const struct iio_chan_spec qcom_smgr_prox_iio_channels[] =3D { + { + .type =3D IIO_PROXIMITY, + .scan_index =3D 0, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) + }, + { + .type =3D IIO_TIMESTAMP, + .channel =3D -1, + .scan_index =3D 3, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 64, + .endianness =3D IIO_LE, + }, + }, +}; + +static const struct iio_chan_spec qcom_smgr_pressure_iio_channels[] =3D { + { + .type =3D IIO_PRESSURE, + .scan_index =3D 0, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 32, + .endianness =3D IIO_LE, + }, + .info_mask_separate =3D BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) + }, + { + .type =3D IIO_TIMESTAMP, + .channel =3D -1, + .scan_index =3D 3, + .scan_type =3D { + .sign =3D 'u', + .realbits =3D 32, + .storagebits =3D 64, + .endianness =3D IIO_LE, + }, + } +}; + +static const char *const qcom_smgr_sensor_type_device_names[] =3D { + [SNS_SMGR_SENSOR_TYPE_ACCEL] =3D "qcom-smgr-accel", + [SNS_SMGR_SENSOR_TYPE_GYRO] =3D "qcom-smgr-gyro", + [SNS_SMGR_SENSOR_TYPE_MAG] =3D "qcom-smgr-mag", + [SNS_SMGR_SENSOR_TYPE_PROX_LIGHT] =3D "qcom-smgr-prox-light", + [SNS_SMGR_SENSOR_TYPE_PRESSURE] =3D "qcom-smgr-pressure", + [SNS_SMGR_SENSOR_TYPE_HALL_EFFECT] =3D "qcom-smgr-hall-effect" +}; + +static const struct iio_chan_spec *const qcom_smgr_sensor_type_iio_channel= s[] =3D { + [SNS_SMGR_SENSOR_TYPE_ACCEL] =3D qcom_smgr_accel_iio_channels, + [SNS_SMGR_SENSOR_TYPE_GYRO] =3D qcom_smgr_gyro_iio_channels, + [SNS_SMGR_SENSOR_TYPE_MAG] =3D qcom_smgr_mag_iio_channels, + [SNS_SMGR_SENSOR_TYPE_PROX_LIGHT] =3D qcom_smgr_prox_iio_channels, + [SNS_SMGR_SENSOR_TYPE_PRESSURE] =3D qcom_smgr_pressure_iio_channels, + [SNS_SMGR_SENSOR_TYPE_HALL_EFFECT] =3D NULL /* Unsupported */ +}; + +static const size_t qcom_smgr_sensor_type_num_channels[] =3D { + [SNS_SMGR_SENSOR_TYPE_ACCEL] =3D ARRAY_SIZE(qcom_smgr_accel_iio_channels), + [SNS_SMGR_SENSOR_TYPE_GYRO] =3D ARRAY_SIZE(qcom_smgr_gyro_iio_channels), + [SNS_SMGR_SENSOR_TYPE_MAG] =3D ARRAY_SIZE(qcom_smgr_mag_iio_channels), + [SNS_SMGR_SENSOR_TYPE_PROX_LIGHT] =3D ARRAY_SIZE(qcom_smgr_prox_iio_chann= els), + [SNS_SMGR_SENSOR_TYPE_PRESSURE] =3D ARRAY_SIZE(qcom_smgr_pressure_iio_cha= nnels) +}; + +static int qcom_smgr_register_sensor(struct qcom_smgr *smgr, + struct qcom_smgr_sensor *sensor) +{ + struct iio_dev *iio_dev; + struct qcom_smgr_iio_priv *priv; + int ret; + + iio_dev =3D devm_iio_device_alloc(smgr->dev, sizeof(*priv)); + if (!iio_dev) + return -ENOMEM; + + priv =3D iio_priv(iio_dev); + priv->sensor =3D sensor; + + priv->samp_freq_vals[0] =3D 1; + priv->samp_freq_vals[1] =3D 1; + priv->samp_freq_vals[2] =3D priv->sensor->data_types[0].max_sample_rate; + + iio_dev->name =3D qcom_smgr_sensor_type_device_names[sensor->type]; + iio_dev->info =3D &qcom_smgr_iio_info; + iio_dev->channels =3D qcom_smgr_sensor_type_iio_channels[sensor->type]; + iio_dev->num_channels =3D qcom_smgr_sensor_type_num_channels[sensor->type= ]; + + sensor->iio_dev =3D iio_dev; + + ret =3D devm_iio_kfifo_buffer_setup(smgr->dev, iio_dev, + &qcom_smgr_buffer_ops); + if (ret) { + dev_err(smgr->dev, "Failed to setup buffer: %pe\n", + ERR_PTR(ret)); + return ret; + } + + ret =3D devm_iio_device_register(smgr->dev, iio_dev); + if (ret) { + dev_err(smgr->dev, "Failed to register IIO device: %pe\n", + ERR_PTR(ret)); + return ret; + } + + return 0; +} + +static int qcom_smgr_probe(struct qrtr_device *qdev) +{ + struct qcom_smgr *smgr; + int i, j; + int ret; + + smgr =3D devm_kzalloc(&qdev->dev, sizeof(*smgr), GFP_KERNEL); + if (!smgr) + return -ENOMEM; + + smgr->dev =3D &qdev->dev; + + smgr->sns_smgr_info.sq_family =3D AF_QIPCRTR; + smgr->sns_smgr_info.sq_node =3D qdev->node; + smgr->sns_smgr_info.sq_port =3D qdev->port; + + dev_set_drvdata(&qdev->dev, smgr); + + ret =3D qmi_handle_init(&smgr->sns_smgr_hdl, + SNS_SMGR_SINGLE_SENSOR_INFO_RESP_MAX_LEN, NULL, + qcom_smgr_msg_handlers); + if (ret < 0) + return dev_err_probe(smgr->dev, ret, + "Failed to initialize sensor manager handle\n"); + + ret =3D devm_add_action_or_reset(smgr->dev, + (void(*)(void *))qmi_handle_release, + &smgr->sns_smgr_hdl); + if (ret) + return ret; + + ret =3D qcom_smgr_request_all_sensor_info(smgr, &smgr->sensors); + if (ret < 0) + return dev_err_probe(smgr->dev, ret, + "Failed to get available sensors\n"); + + smgr->sensor_count =3D ret; + + /* Get primary and secondary sensors from each sensor ID */ + for (i =3D 0; i < smgr->sensor_count; i++) { + ret =3D qcom_smgr_request_single_sensor_info(smgr, + &smgr->sensors[i]); + if (ret < 0) + return dev_err_probe(smgr->dev, ret, + "Failed to get sensors from ID 0x%02x\n", + smgr->sensors[i].id); + + for (j =3D 0; j < smgr->sensors[i].data_type_count; j++) { + /* Default to maximum sample rate */ + smgr->sensors[i].data_types->cur_sample_rate =3D + smgr->sensors[i].data_types->max_sample_rate; + + dev_dbg(smgr->dev, "0x%02x,%d: %s %s\n", + smgr->sensors[i].id, j, + smgr->sensors[i].data_types[j].vendor, + smgr->sensors[i].data_types[j].name); + } + + /* Skip if sensor type is not supported */ + if (smgr->sensors[i]->type =3D=3D SNS_SMGR_SENSOR_TYPE_UNKNOWN || + !qcom_smgr_sensor_type_iio_channels[smgr->sensors[i]->type]) + continue; + + ret =3D qcom_smgr_register_sensor(smgr, &smgr->sensors[i]); + if (ret) + return dev_err_probe(smgr->dev, ret, + "Failed to register sensor 0x%02x\n", + smgr->sensors[i].id); + } + + return 0; +} + +static const struct qrtr_device_id qcom_smgr_qrtr_match[] =3D { + { + .service =3D SNS_SMGR_QMI_SVC_ID, + /* Found on MSM8953 */ + .instance =3D QRTR_INSTANCE_CONST(0, 1) + }, + { + .service =3D SNS_SMGR_QMI_SVC_ID, + /* Found on MSM8974 and MSM8226 */ + .instance =3D QRTR_INSTANCE_CONST(1, 0) + }, + { + .service =3D SNS_SMGR_QMI_SVC_ID, + /* Found on MSM8996 and SDM660 */ + .instance =3D QRTR_INSTANCE_CONST(1, 50) + }, + { }, +}; +MODULE_DEVICE_TABLE(qrtr, qcom_smgr_qrtr_match); + +static struct qrtr_driver qcom_smgr_driver =3D { + .probe =3D qcom_smgr_probe, + .id_table =3D qcom_smgr_qrtr_match, + .driver =3D { + .name =3D "qcom_smgr", + }, +}; +module_qrtr_driver(qcom_smgr_driver); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("Qualcomm Sensor Manager driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/common/qcom_smgr/qmi/Makefile b/drivers/iio/common= /qcom_smgr/qmi/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e69208db495f999e962a6513404= 05ee3632bf463 --- /dev/null +++ b/drivers/iio/common/qcom_smgr/qmi/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_IIO_QCOM_SMGR) +=3D qmi_sns_smgr.o diff --git a/drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.c b/drivers/iio/= common/qcom_smgr/qmi/qmi_sns_smgr.c new file mode 100644 index 0000000000000000000000000000000000000000..1b58e266280d0b26a8d62f1ba64= edc5ac3136b1e --- /dev/null +++ b/drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * QMI element info arrays and helper functions for Qualcomm Sensor Manager + * + * Copyright (c) 2021-2025, Yassine Oudjana + */ + +#include +#include +#include +#include + +#include "qmi_sns_smgr.h" + +static const struct qmi_elem_info sns_smgr_all_sensor_info_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_all_sensor_info, id), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_all_sensor_info, id), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_all_sensor_info, type_len), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_all_sensor_info, type_len), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D SNS_SMGR_SENSOR_TYPE_MAX_LEN, + .elem_size =3D sizeof(char), + .array_type =3D VAR_LEN_ARRAY, + .offset =3D offsetof(struct sns_smgr_all_sensor_info, type), + }, + { + .data_type =3D QMI_EOTI, + }, +}; + +const struct qmi_elem_info sns_smgr_all_sensor_info_resp_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_all_sensor_info_resp, + result), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x02, + .offset =3D + offsetof(struct sns_smgr_all_sensor_info_resp, result), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_all_sensor_info_resp, + item_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x03, + .offset =3D offsetof(struct sns_smgr_all_sensor_info_resp, + item_len), + }, + { + .data_type =3D QMI_STRUCT, + .elem_len =3D SNS_SMGR_ALL_SENSOR_INFO_MAX_LEN, + .elem_size =3D sizeof(struct sns_smgr_all_sensor_info), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x03, + .offset =3D offsetof(struct sns_smgr_all_sensor_info_resp, items), + .ei_array =3D sns_smgr_all_sensor_info_ei, + }, + { + .data_type =3D QMI_EOTI, + }, +}; +EXPORT_SYMBOL_GPL(sns_smgr_all_sensor_info_resp_ei); + +const struct qmi_elem_info sns_smgr_single_sensor_info_req_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_req, sensor_id), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x01, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_req, + sensor_id), + }, + { + .data_type =3D QMI_EOTI, + }, +}; +EXPORT_SYMBOL_GPL(sns_smgr_single_sensor_info_req_ei); + +static const struct qmi_elem_info sns_smgr_single_sensor_info_data_type_ei= [] =3D { + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, + sensor_id), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + sensor_id), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, + data_type), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + data_type), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, name_len), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + name_len), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 0xff, + .elem_size =3D sizeof(char), + .array_type =3D VAR_LEN_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + name), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, + vendor_len), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + vendor_len), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 0xff, + .elem_size =3D sizeof(char), + .array_type =3D VAR_LEN_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + vendor), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, val1), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + val1), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, + max_sample_rate_hz), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + max_sample_rate_hz), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, val2), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + val2), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, + current_ua), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + current_ua), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, range), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + range), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_data_type, + resolution), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_data_type, + resolution), + }, + { + .data_type =3D QMI_EOTI, + }, +}; + +static const struct qmi_elem_info sns_smgr_single_sensor_info_native_sampl= e_rates_ei[] =3D { + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_native_sample_rates, rate_count), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_native_sample_ra= tes, + rate_count), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D SNS_SMGR_NATIVE_SAMPLE_RATES_MAX_LEN, + .elem_size =3D sizeof(u16), + .array_type =3D VAR_LEN_ARRAY, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_native_sample_ra= tes, + rates), + }, + { + .data_type =3D QMI_EOTI, + }, +}; + +const struct qmi_elem_info sns_smgr_single_sensor_info_resp_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_resp, result), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x02, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + result), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_resp, data_type_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x03, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data_type_len), + }, + { + .data_type =3D QMI_STRUCT, + .elem_len =3D SNS_SMGR_DATA_TYPE_COUNT, + .elem_size =3D + sizeof(struct sns_smgr_single_sensor_info_data_type), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x03, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data_types), + .ei_array =3D sns_smgr_single_sensor_info_data_type_ei, + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_resp, data1_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x10, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data1_len), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D SNS_SMGR_DATA_TYPE_COUNT, + .elem_size =3D sizeof(u32), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x10, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data1), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_resp, data2), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x11, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data2), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_resp, data3_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x12, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data3_len), + }, + { + .data_type =3D QMI_UNSIGNED_8_BYTE, + .elem_len =3D SNS_SMGR_DATA_TYPE_COUNT, + .elem_size =3D sizeof(u64), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x12, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data3), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_resp, + native_sample_rates_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x13, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + native_sample_rates_len), + }, + { + .data_type =3D QMI_STRUCT, + .elem_len =3D SNS_SMGR_DATA_TYPE_COUNT, + .elem_size =3D sizeof( + struct sns_smgr_single_sensor_info_native_sample_rates), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x13, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + native_sample_rates), + .ei_array =3D sns_smgr_single_sensor_info_native_sample_rates_ei, + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_single_sensor_info_resp, data5_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x14, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data5_len), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D SNS_SMGR_DATA_TYPE_COUNT, + .elem_size =3D sizeof(u32), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x14, + .offset =3D offsetof(struct sns_smgr_single_sensor_info_resp, + data5), + }, + { + .data_type =3D QMI_EOTI, + }, +}; +EXPORT_SYMBOL_GPL(sns_smgr_single_sensor_info_resp_ei); + +static const struct qmi_elem_info sns_smgr_buffering_req_item_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req_item, + sensor_id), + .array_type =3D NO_ARRAY, + .offset =3D + offsetof(struct sns_smgr_buffering_req_item, sensor_id), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req_item, + data_type), + .array_type =3D NO_ARRAY, + .offset =3D + offsetof(struct sns_smgr_buffering_req_item, data_type), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req_item, + val1), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_req_item, + val1), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req_item, + sampling_rate), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_req_item, + sampling_rate), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req_item, + val2), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_req_item, + val2), + }, + { + .data_type =3D QMI_EOTI, + }, +}; + +static const struct qmi_elem_info sns_smgr_buffering_req_notify_suspend_ei= [] =3D { + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_req_notify_suspend, + proc_type), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_req_notify_suspend, + proc_type), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_req_notify_suspend, + send_indications_during_suspend), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_req_notify_suspend, + send_indications_during_suspend), + }, + { + .data_type =3D QMI_EOTI, + }, +}; + +const struct qmi_elem_info sns_smgr_buffering_req_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_buffering_req, report_id), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x01, + .offset =3D offsetof(struct sns_smgr_buffering_req, report_id), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_buffering_req, action), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x02, + .offset =3D offsetof(struct sns_smgr_buffering_req, action), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req, + report_rate), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x03, + .offset =3D offsetof(struct sns_smgr_buffering_req, report_rate), + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_buffering_req, item_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x04, + .offset =3D offsetof(struct sns_smgr_buffering_req, item_len), + }, + { + .data_type =3D QMI_STRUCT, + .elem_len =3D SNS_SMGR_DATA_TYPE_COUNT, + .elem_size =3D sizeof(struct sns_smgr_buffering_req_item), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x04, + .offset =3D offsetof(struct sns_smgr_buffering_req, items), + .ei_array =3D sns_smgr_buffering_req_item_ei, + }, + { + .data_type =3D QMI_OPT_FLAG, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req, + notify_suspend_valid), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x10, + .offset =3D offsetof(struct sns_smgr_buffering_req, + notify_suspend_valid), + }, + { + .data_type =3D QMI_STRUCT, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_req, + notify_suspend), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x10, + .offset =3D + offsetof(struct sns_smgr_buffering_req, notify_suspend), + .ei_array =3D sns_smgr_buffering_req_notify_suspend_ei, + }, + { + .data_type =3D QMI_EOTI, + }, +}; +EXPORT_SYMBOL_GPL(sns_smgr_buffering_req_ei); + +const struct qmi_elem_info sns_smgr_buffering_resp_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_buffering_resp, result), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x02, + .offset =3D offsetof(struct sns_smgr_buffering_resp, result), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_buffering_resp, report_id), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x10, + .offset =3D offsetof(struct sns_smgr_buffering_resp, report_id), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_buffering_resp, ack_nak), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x11, + .offset =3D offsetof(struct sns_smgr_buffering_resp, ack_nak), + }, + { + .data_type =3D QMI_EOTI, + }, +}; +EXPORT_SYMBOL_GPL(sns_smgr_buffering_resp_ei); + +static const struct qmi_elem_info sns_smgr_buffering_report_metadata_ei[] = =3D { + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_report_metadata, val1), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_report_metadata, + val1), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D + sizeof_field(struct sns_smgr_buffering_report_metadata, + sample_count), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_report_metadata, + sample_count), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_report_metadata, timestamp), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_report_metadata, + timestamp), + }, + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_report_metadata, val2), + .array_type =3D NO_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_report_metadata, + val2), + }, + { + .data_type =3D QMI_EOTI, + }, +}; + +static const struct qmi_elem_info sns_smgr_buffering_report_sample_ei[] = =3D { + { + .data_type =3D QMI_UNSIGNED_4_BYTE, + .elem_len =3D 3, + .elem_size =3D sizeof(u32), + .array_type =3D STATIC_ARRAY, + .offset =3D offsetof(struct sns_smgr_buffering_report_sample, + values), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_report_sample, val1), + .array_type =3D NO_ARRAY, + .offset =3D + offsetof(struct sns_smgr_buffering_report_sample, val1), + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_report_sample, val2), + .array_type =3D NO_ARRAY, + .offset =3D + offsetof(struct sns_smgr_buffering_report_sample, val2), + }, + { + .data_type =3D QMI_UNSIGNED_2_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field( + struct sns_smgr_buffering_report_sample, val3), + .array_type =3D NO_ARRAY, + .offset =3D + offsetof(struct sns_smgr_buffering_report_sample, val3), + }, + { + .data_type =3D QMI_EOTI, + }, +}; + +const struct qmi_elem_info sns_smgr_buffering_report_ind_ei[] =3D { + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_report_ind, + report_id), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x01, + .offset =3D offsetof(struct sns_smgr_buffering_report_ind, + report_id), + }, + { + .data_type =3D QMI_STRUCT, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_report_ind, + metadata), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x02, + .offset =3D offsetof(struct sns_smgr_buffering_report_ind, + metadata), + .ei_array =3D sns_smgr_buffering_report_metadata_ei, + }, + { + .data_type =3D QMI_DATA_LEN, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_report_ind, + samples_len), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x03, + .offset =3D offsetof(struct sns_smgr_buffering_report_ind, + samples_len), + }, + { + .data_type =3D QMI_STRUCT, + .elem_len =3D SNS_SMGR_SAMPLES_MAX_LEN, + .elem_size =3D sizeof(struct sns_smgr_buffering_report_sample), + .array_type =3D VAR_LEN_ARRAY, + .tlv_type =3D 0x03, + .offset =3D + offsetof(struct sns_smgr_buffering_report_ind, samples), + .ei_array =3D sns_smgr_buffering_report_sample_ei, + }, + { + .data_type =3D QMI_UNSIGNED_1_BYTE, + .elem_len =3D 1, + .elem_size =3D sizeof_field(struct sns_smgr_buffering_report_ind, + val2), + .array_type =3D NO_ARRAY, + .tlv_type =3D 0x10, + .offset =3D offsetof(struct sns_smgr_buffering_report_ind, val2), + }, + { + .data_type =3D QMI_EOTI, + }, +}; +EXPORT_SYMBOL_GPL(sns_smgr_buffering_report_ind_ei); + +static const char *smgr_sensor_type_names[SNS_SMGR_SENSOR_TYPE_COUNT] =3D { + [SNS_SMGR_SENSOR_TYPE_ACCEL] =3D "ACCEL", + [SNS_SMGR_SENSOR_TYPE_GYRO] =3D "GYRO", + [SNS_SMGR_SENSOR_TYPE_MAG] =3D "MAG", + [SNS_SMGR_SENSOR_TYPE_PROX_LIGHT] =3D "PROX_LIGHT", + [SNS_SMGR_SENSOR_TYPE_PRESSURE] =3D "PRESSURE", + [SNS_SMGR_SENSOR_TYPE_HALL_EFFECT] =3D "HALL_EFFECT" +}; + +enum qcom_smgr_sensor_type sns_smgr_sensor_type_from_str(const char *str) +{ + enum qcom_smgr_sensor_type i; + + for (i =3D SNS_SMGR_SENSOR_TYPE_UNKNOWN + 1; + i < SNS_SMGR_SENSOR_TYPE_COUNT; i++) + if (!strcmp(str, smgr_sensor_type_names[i])) + return i; + + return SNS_SMGR_SENSOR_TYPE_UNKNOWN; +} +EXPORT_SYMBOL_GPL(sns_smgr_sensor_type_from_str); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("Qualcomm Sensor Manager QMI service helpers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.h b/drivers/iio/= common/qcom_smgr/qmi/qmi_sns_smgr.h new file mode 100644 index 0000000000000000000000000000000000000000..5d0d622b9381bd053f13d5e6a01= ee9fbd0d59470 --- /dev/null +++ b/drivers/iio/common/qcom_smgr/qmi/qmi_sns_smgr.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __QMI_SNS_SMGR_H__ +#define __QMI_SNS_SMGR_H__ + +#include +#include +#include + +/* + * The structures of QMI messages used by the service were determined + * purely by watching transactions between proprietary Android userspace + * components and SSC. along with comparing values reported by Android APIs + * to values received in response messages. Due to that, the purpose or + * meaning of many fields remains unknown. Such fields are named "val*", + * "data*" or similar. Furthermore, the true maximum sizes of some messages + * with unknown array fields may be different than defined here. + */ + +#define SNS_SMGR_QMI_SVC_ID 0x0100 + +#define SNS_SMGR_ALL_SENSOR_INFO_MSG_ID 0x05 +#define SNS_SMGR_SINGLE_SENSOR_INFO_MSG_ID 0x06 +#define SNS_SMGR_BUFFERING_MSG_ID 0x21 +#define SNS_SMGR_BUFFERING_REPORT_MSG_ID 0x22 + +#define SNS_SMGR_ALL_SENSOR_INFO_REQ_MAX_LEN 0x0 +#define SNS_SMGR_ALL_SENSOR_INFO_RESP_MAX_LEN 0x3e +#define SNS_SMGR_SINGLE_SENSOR_INFO_REQ_MAX_LEN 0x4 +#define SNS_SMGR_SINGLE_SENSOR_INFO_RESP_MAX_LEN 0x110 +#define SNS_SMGR_BUFFERING_REQ_MAX_LEN 0x30 +#define SNS_SMGR_BUFFERING_RESP_MAX_LEN 0x1e + +/* TODO: find actual maximums */ +#define SNS_SMGR_ALL_SENSOR_INFO_MAX_LEN 0x10 +#define SNS_SMGR_SENSOR_TYPE_MAX_LEN 0x10 +#define SNS_SMGR_NATIVE_SAMPLE_RATES_MAX_LEN 0x20 +#define SNS_SMGR_SAMPLES_MAX_LEN 0x100 + +enum sns_smgr_buffering_action { + SNS_SMGR_BUFFERING_ACTION_ADD =3D 1, + SNS_SMGR_BUFFERING_ACTION_DELETE =3D 2, +}; + +struct sns_smgr_all_sensor_info { + u8 id; + u8 type_len; + char type[SNS_SMGR_SENSOR_TYPE_MAX_LEN]; +}; + +struct sns_smgr_all_sensor_info_resp { + u16 result; + u8 item_len; + struct sns_smgr_all_sensor_info items[SNS_SMGR_ALL_SENSOR_INFO_MAX_LEN]; +}; + +struct sns_smgr_single_sensor_info_req { + u8 sensor_id; +}; + +struct sns_smgr_single_sensor_info_data_type { + u8 sensor_id; + u8 data_type; + u8 name_len; + char name[0xff]; + u8 vendor_len; + char vendor[0xff]; + /* + * Might be separate u8 or u16 fields, but taken as a u32 it is seen + * to hold the value 1 for all sensors in dumps. + */ + u32 val1; + u16 max_sample_rate_hz; + u16 val2; + u16 current_ua; + u32 range; + u32 resolution; +}; + +struct sns_smgr_single_sensor_info_native_sample_rates { + u8 rate_count; + u16 rates[SNS_SMGR_NATIVE_SAMPLE_RATES_MAX_LEN]; +}; + +struct sns_smgr_single_sensor_info_resp { + u16 result; + u8 data_type_len; + struct sns_smgr_single_sensor_info_data_type data_types[SNS_SMGR_DATA_TYP= E_COUNT]; + u8 data1_len; + u32 data1[SNS_SMGR_DATA_TYPE_COUNT]; + u32 data2; + u8 data3_len; + u64 data3[SNS_SMGR_DATA_TYPE_COUNT]; + u8 native_sample_rates_len; + struct sns_smgr_single_sensor_info_native_sample_rates + native_sample_rates[SNS_SMGR_DATA_TYPE_COUNT]; + u8 data5_len; + u32 data5[SNS_SMGR_DATA_TYPE_COUNT]; +}; + +struct sns_smgr_buffering_req_item { + u8 sensor_id; + u8 data_type; + u16 val1; + u16 sampling_rate; + u16 val2; +}; + +struct sns_smgr_buffering_req_notify_suspend { + u16 proc_type; + u16 send_indications_during_suspend; +}; + +struct sns_smgr_buffering_req { + u8 report_id; + u8 action; + u32 report_rate; + u8 item_len; + struct sns_smgr_buffering_req_item items[SNS_SMGR_DATA_TYPE_COUNT]; + u8 notify_suspend_valid; + struct sns_smgr_buffering_req_notify_suspend notify_suspend; +}; + +struct sns_smgr_buffering_resp { + u16 result; + u8 report_id; + u8 ack_nak; +}; + +struct sns_smgr_buffering_report_metadata { + u32 val1; + u8 sample_count; + u32 timestamp; + u32 val2; +}; + +struct sns_smgr_buffering_report_sample { + u32 values[3]; + u8 val1; + u8 val2; + u16 val3; +}; + +struct sns_smgr_buffering_report_ind { + u8 report_id; + struct sns_smgr_buffering_report_metadata metadata; + u8 samples_len; + struct sns_smgr_buffering_report_sample samples[SNS_SMGR_SAMPLES_MAX_LEN]; + u8 val2; +}; + +extern const struct qmi_elem_info sns_smgr_all_sensor_info_resp_ei[]; +extern const struct qmi_elem_info sns_smgr_single_sensor_info_req_ei[]; +extern const struct qmi_elem_info sns_smgr_single_sensor_info_resp_ei[]; +extern const struct qmi_elem_info sns_smgr_buffering_req_ei[]; +extern const struct qmi_elem_info sns_smgr_buffering_resp_ei[]; +extern const struct qmi_elem_info sns_smgr_buffering_report_ind_ei[]; + +extern enum qcom_smgr_sensor_type sns_smgr_sensor_type_from_str(const char= *str); + +#endif /* __SSC_SNS_SMGR_H__ */ diff --git a/include/linux/iio/common/qcom_smgr.h b/include/linux/iio/commo= n/qcom_smgr.h new file mode 100644 index 0000000000000000000000000000000000000000..fdd3de12bb0a48f1fb9e51cd046= 3c9a9b9ed500f --- /dev/null +++ b/include/linux/iio/common/qcom_smgr.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __QCOM_SMGR_H__ +#define __QCOM_SMGR_H__ + +#include +#include +#include +#include + +enum qcom_smgr_sensor_type { + SNS_SMGR_SENSOR_TYPE_UNKNOWN, + SNS_SMGR_SENSOR_TYPE_ACCEL, + SNS_SMGR_SENSOR_TYPE_GYRO, + SNS_SMGR_SENSOR_TYPE_MAG, + SNS_SMGR_SENSOR_TYPE_PROX_LIGHT, + SNS_SMGR_SENSOR_TYPE_PRESSURE, + SNS_SMGR_SENSOR_TYPE_HALL_EFFECT, + + SNS_SMGR_SENSOR_TYPE_COUNT +}; + +enum qcom_smgr_data_type { + SNS_SMGR_DATA_TYPE_PRIMARY, + SNS_SMGR_DATA_TYPE_SECONDARY, + + SNS_SMGR_DATA_TYPE_COUNT +}; + +struct qcom_smgr_data_type_item { + const char *name; + const char *vendor; + + u32 range; + + size_t native_sample_rate_count; + u16 *native_sample_rates; + + u16 max_sample_rate; + u16 cur_sample_rate; +}; + +struct qcom_smgr_sensor { + u8 id; + enum qcom_smgr_sensor_type type; + + u8 data_type_count; + /* + * Only SNS_SMGR_DATA_TYPE_PRIMARY is used at the moment, but we store + * SNS_SMGR_DATA_TYPE_SECONDARY when available as well for future use. + */ + struct qcom_smgr_data_type_item *data_types; + + struct iio_dev *iio_dev; +}; + +struct qcom_smgr_iio_priv { + struct qcom_smgr_sensor *sensor; + + int samp_freq_vals[3]; +}; + + +struct qcom_smgr_iio_data { + u32 values[3]; + u64 timestamp; +}; + +struct qcom_smgr { + struct device *dev; + + struct qmi_handle sns_smgr_hdl; + struct sockaddr_qrtr sns_smgr_info; + struct work_struct sns_smgr_work; + + u8 sensor_count; + struct qcom_smgr_sensor *sensors; +}; + +#endif /* __QCOM_SMGR_H__ */ --=20 2.50.0