From patchwork Tue Jan 23 23:10:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765329 Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05on2067.outbound.protection.outlook.com [40.107.22.67]) (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 95BFB54669; Tue, 23 Jan 2024 23:11:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.22.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051473; cv=fail; b=ky848K9poDWEyPAVesULNvH3Mb9BWu9fJbJ013fqSk0LacF/Q5U6Xu98Z1dohkMK1odSIJU1Y+ZnV9bYnDKRgcvPHbSAVJpJ7FIRIVuFgetG+bIQAS9rOzL68TLcGWNP4e0gYPYgZf2rU1Peegvy+eduSovylQ7GynBIQ4NKhAE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051473; c=relaxed/simple; bh=L3gpGBAQE0dQR2BNSrVRNNEW9irCL0rFWiOFcy1UVdc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=BuBCnIJDWd3e0KIgsZ9GQkDcLEYJUUkQ6vffYPhMF+1Pf5kCogqTHUgcz5Gm4nFG6uiBWC+QHiVBUlnh1Gpqs2USu4A1+QBT93fmmhhcETxPtRt0/TuIqbG+feljsowjzq4PJL4UPgoyiv4Ta6qRiWNLmvsEXGOqSS7sG5CfldA= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=QEQjZ1uM; arc=fail smtp.client-ip=40.107.22.67 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="QEQjZ1uM" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=a3LUQGChm6XgcJAfm6b81xWfH3EPDolVdQLhFvH9mCySJpTVdSWj7Z60EoB2jdj5DNQKxFD0psFszdKBsLnvWq+ayJbaK4jRTkX4W69NcJLS41YG8vao+lxOQl1TATNvlszWsfDP492OBh/YQRZz8OxTJXZYACTdVzCOwZyMoHODQB/d3VH4yoc2HI9Fk9MiDpHN+IAnyE+1tBYoTEdqlA0mf+87p2z/Rt724m+1o0oFd8e9jcV04kSlB4O+eFm9GVyucd5ad2E8I5fSXRC5orjk+Eor5a4fKQg3++Diwn7Dmy7pmGik9pvKZxt8Oib15RquVOYot1Xu9e2SxMpJuQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Fcy5kB1x4dlvkv4Sat8Bsj+EbLAUuA8NXlPmUML4HK4=; b=aS5nc97ClbuVGOWH/1Aydyzd6v6JZ2rRc7Mt43i34evF5Xyuds4yZ5osporwzGYypA4n7CweD7AscTeV/v022Q1jEbJXniZYofH3OhuG4tVC0Y7yEGt/fkIltCm7WRR59UXcu50ynskE8CfMLtfFNK40Zz7LZL8bhL7NqzWbyb/x+A7WTgt/siXzKfFBPTP/85ml/XiDOXaWAMxz4j7baYoznRgd9n4lphvVQkmW8zzUVkpmrJFJI5ClPBCiwFbJBHduCmbQ15l+M+Z8lTPqXtNh0XNtssPyEncAoshTFU+XDsJ7k85EG2Ti5njk/83o488ljypyZpGMfLBxXUxZ2w== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Fcy5kB1x4dlvkv4Sat8Bsj+EbLAUuA8NXlPmUML4HK4=; b=QEQjZ1uMnwdII/2NDxYtcq0BBzfPQLVX5moAOWkvUOkhANNf1GxEcMBZnzsxgEN9T2vmAVB39e3eAtYQVT07vl45kxmZ8+vonqhWUhSS393O6mtJKacaneIztZEIA1z6K3L8yS/qmufzefD8nwQvo2OvdxknNJw8IX4zZ29SgQ0= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:04 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:04 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 1/8] i3c: add target mode support Date: Tue, 23 Jan 2024 18:10:36 -0500 Message-Id: <20240123231043.3891847-2-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: 0d4f4d84-35b1-467d-430e-08dc1c6892cf X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: og9qDKuGIrtDQgacj/JBXIJsIFjUfgX6NwFn6RcRaQv2/hTIZeN7n/zx0baWlrZh+fXavaCJshfetytpeTqEBDwiaoXp+as244lTqAa0EYJXIRp+7IjARIWeFrxoNuPffkHP9+sGcnTT/0kHuCWfgAcekDuEkCyVCiYVuZKF6V6OBuDGELhRz1gWWUiwj5cFzXlEVHn09e8+eEeJwitjQ6or20Jk0moL+EU6wwrdBYbdBmRz39jMMbfAYUd1mIvIVAUjhL1RHJ1ZL0HYwifFR0xiO8Y7JGXf6/QTv/STEh5yy5ZOEr3vUAr8CC+0kJekLPtMDn38iV+deZm/+qsmtJaf2dqKRfX6qDYrEGYRSHn08/3qq8fbToObPrGVOtjU41GoyWqrhJiftlampvAAKrJRKU8iDRGZStmk4QPtsML2APqiptbVdnHPdLvh90+LhXA9+Jhh8gvWTnKfoj7Ewa4M4086sQbYlWpF/ZXwQCbqRjnm+tHjzm7y7eX/mUSMOOcnMsP7XHpOPsRxXQ+28bmTZIueVRyPO1SY2Sn0S5WWfBLe8WVqfXFp065HqIhfNIp5ln8uUGHcdzWjnN78WZsV0S685x9Vs/yxzLNLq8HSu5zH0NFX6oEF3d1vVpsx X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(30864003)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001)(579004); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: japw3hv1SfW5Aui/mxXWMhyb+3I+CpxW1NiTXjBy+45bhJDl9qMDPTNJJzvBlLZRpJ03zsJFDcwr2Sh+r+1unl89WpYebzUbREEbgaBPbTWv5BlS8MhaFWichQDMw1Kfxq7VDUQx3nr41FypuboNGzHmho3U5zV3i3h362U6QpMJCc8xUcmygW2thHvUQiG91CQMM9ZtQCrPWfC6Gnrp1WB4mJYiEkmW2ySaI3SmlWn4swQXO65H9Zz9AkOUdopGlqLsoX7y2H0x7AOeFdrGOs1AcpKsepnCuU8yulEDEWrY9Dhi36jho7h3Y1pjawUz0st3i5QtAuT/ftP+YUm0RH5UJo6Jd5o8jvEh64yQLlDYzbxqM2NLh0h1HmQMcq2F4qksPzkSknBboC/C9o53+7ZVomZdSb8OWI1oEo3RJwicyqyuKQQFky/XlLz9xQDTaQGkIEn3a67RAw9vz3z0fINw0yqvy4w2zIa9Q+jBgH9SVfgqZlB6+ZgIPJgnFaXX4uzzGYkGBxKhehwykXnLBQRKkZfxrK5RMutdZDiCAB/uwF9BlW91RBT7Abs15Q78guZib5HqvFWG8+fQKGMsrif/jDyC6BrXD4pq3faUd7u6iKkIqWpVmM8ob6wmvyBnCq+kxUHUmsCFOGnX5IzQaA5gC/Nd//Ig/Rp6Tq4n9IKlbd9J9ERAwO9UxSlMxA/y4EK6SWqSfzvqzPzIr7ctxMhdS2UhZk7Ui2KKor91yLqvib298u1lsKSSSaY38yBuxJHQ7/fVe8aGBxowIO/z25y+dMbs3V7Ebc3AEdBIQ5sxI4OACSwHl5lYHPimp607+dedfhjdPK1xhAUSHviwlZuPtZRYGYI2SXJL06ZHdERJAQYNNSz5Z69h5rS5htNYJ94SRD1nauL62/Cv4T+LpzoF5wJuoufWnqVnOCH+eS+9T50M5AiHgGHMPMCtGdKBIJrXde6lvgC8qptM/WMB/qAYdYv+hnvUEnWxhfoVkcoqbDsZeI0jJCW0cL2Mr/+PpoaWn/rqsQyksEqsryE9heBaHltsHhQy1LIRAXB1Zk8Y61KMvYBRedFa5aMQ4i/j9tGA+cDXaWGHUVFI7mFfHFROje/obzRXZ1pAsOerdcCVreN957vzIeOkzmkNP4NmB/8n7h40K1Mz0uM0ntzYHvTR4SXemBQgw++mECU4vaoH0F7pzjOUvbOg0cQ9SRd0cFesk2etw/97fjCRYlizdubSiuixgqJm7EWWJpP04WnFi666vsYDwZn3w3VHp5DdxxWNDlqCd1wyXXtrzo01Q4mhfbBUX6kZklX+MjQ4f9GHbiRfG7bB2YgfqQIEljXQf4liUFr+DCHrYzoj4tLbAmQ4KJcoUBhNrJgOA3FQn5fUhtxu5mNvj4eTMJ/NmDle3rAPZEw/Z9kSJZIThTATLwNCKL6/PpnQ3bFA0Endt9+kT9xuIW12/XPRzJY+SmQ7FNj7l/8AxOZtXLXs8yYyq59vaQPxfWrpklJQVr0bBNSfrgk92dgnEUFWK7BuMgJTr5bsFvQpTUI5/G144KhZRDyTk2CasrziHHWPeeA93ENvafIIzohlizbIzmcdrrFg X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 0d4f4d84-35b1-467d-430e-08dc1c6892cf X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:04.5945 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: uEAU+FeMD7weqwV8+Bs1fud8EjYqfadTn0P+FsgdcnVKfruQ5i/h1nXxFvplC9qTd66aGoCVjL+geTYBFWDq/g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 Introduce a new target core layer in order to support target functions in linux kernel. This comprises the controller library and function library. Controller library implements functions specific to an target controller and function library implements functions specific to an target function. Introduce a new configfs entry to configure the target function configuring and bind the target function with target controller. Signed-off-by: Frank Li --- drivers/i3c/Kconfig | 28 +- drivers/i3c/Makefile | 2 + drivers/i3c/i3c-cfs.c | 389 +++++++++++++++++++++++++++ drivers/i3c/target.c | 453 +++++++++++++++++++++++++++++++ include/linux/i3c/target.h | 527 +++++++++++++++++++++++++++++++++++++ 5 files changed, 1398 insertions(+), 1 deletion(-) create mode 100644 drivers/i3c/i3c-cfs.c create mode 100644 drivers/i3c/target.c create mode 100644 include/linux/i3c/target.h diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig index 30a441506f61c..d59a7eb83d13a 100644 --- a/drivers/i3c/Kconfig +++ b/drivers/i3c/Kconfig @@ -10,7 +10,7 @@ menuconfig I3C support for high speed transfers and native interrupt support without the need for extra pins. - The I3C protocol also standardizes the slave device types and is + The I3C protocol also standardizes the target device types and is mainly designed to communicate with sensors. If you want I3C support, you should say Y here and also to the @@ -22,3 +22,29 @@ menuconfig I3C if I3C source "drivers/i3c/master/Kconfig" endif # I3C + +config I3C_TARGET + bool "I3C Target Support" + help + Support I3C Target Mode. + + Enable this configuration option to support configurable I3C target. + This should be enabled if the platform has a I3C controller that can + operate in target mode. + + Enabling this option will build the I3C target library, which includes + target controller library and target function library. + + If in doubt, say "N" to disable target support. + +config I3C_TARGET_CONFIGFS + bool "I3C Target Configfs Support" + depends on I3C_TARGET + select CONFIGFS_FS + help + Configfs entry for target function and controller. + + This will enable the configfs entry that can be used to configure + the target function and used to bind the function with a target + controller. + diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile index 11982efbc6d91..c275aeae8970c 100644 --- a/drivers/i3c/Makefile +++ b/drivers/i3c/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 i3c-y := device.o master.o obj-$(CONFIG_I3C) += i3c.o +obj-$(CONFIG_I3C_TARGET) += target.o +obj-$(CONFIG_I3C_TARGET_CONFIGFS) += i3c-cfs.o obj-$(CONFIG_I3C) += master/ diff --git a/drivers/i3c/i3c-cfs.c b/drivers/i3c/i3c-cfs.c new file mode 100644 index 0000000000000..a2f0f44fcdaea --- /dev/null +++ b/drivers/i3c/i3c-cfs.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Configfs to configure the I3C Slave + * + * Copyright (C) 2023 NXP + * Author: Frank Li + */ + +#include +#include +#include +#include +#include + +static DEFINE_MUTEX(functions_mutex); +static struct config_group *functions_group; +static struct config_group *controllers_group; + +struct i3c_target_func_group { + struct config_group group; + struct i3c_target_func *func; +}; + +struct i3c_target_ctrl_group { + struct config_group group; + struct i3c_target_ctrl *ctrl; +}; + +static inline struct i3c_target_func_group *to_i3c_target_func_group(struct config_item *item) +{ + return container_of(to_config_group(item), struct i3c_target_func_group, group); +} + +static inline struct i3c_target_ctrl_group *to_i3c_target_ctrl_group(struct config_item *item) +{ + return container_of(to_config_group(item), struct i3c_target_ctrl_group, group); +} + +static int i3c_target_ctrl_func_link(struct config_item *ctrl_cfg, struct config_item *func_cfg) +{ + struct i3c_target_func_group *func_group = to_i3c_target_func_group(func_cfg); + struct i3c_target_ctrl_group *ctrl_group = to_i3c_target_ctrl_group(ctrl_cfg); + struct i3c_target_ctrl *ctrl = ctrl_group->ctrl; + struct i3c_target_func *func = func_group->func; + int ret; + + ret = i3c_target_ctrl_add_func(ctrl, func); + if (ret) + return ret; + + ret = i3c_target_func_bind(func); + if (ret) { + i3c_target_ctrl_remove_func(ctrl, func); + return ret; + } + + return 0; +} + +static void i3c_target_ctrl_func_unlink(struct config_item *ctrl_cfg, struct config_item *func_cfg) +{ + struct i3c_target_func_group *func_group = to_i3c_target_func_group(func_cfg->ci_parent); + struct i3c_target_ctrl_group *ctrl_group = to_i3c_target_ctrl_group(ctrl_cfg); + struct i3c_target_ctrl *ctrl = ctrl_group->ctrl; + struct i3c_target_func *func = func_group->func; + + i3c_target_func_unbind(func); + i3c_target_ctrl_remove_func(ctrl, func); +} + +static ssize_t i3c_target_ctrl_hotjoin_store(struct config_item *item, const char *page, size_t len) +{ + struct i3c_target_ctrl_group *ctrl_group = to_i3c_target_ctrl_group(item); + struct i3c_target_ctrl *ctrl; + int ret; + + ctrl = ctrl_group->ctrl; + + ret = i3c_target_ctrl_hotjoin(ctrl); + if (ret) { + dev_err(&ctrl->dev, "failed to hotjoin i3c target controller\n"); + return -EINVAL; + } + + return len; +} + +static ssize_t i3c_target_ctrl_hotjoin_show(struct config_item *item, char *page) +{ + return sysfs_emit(page, "%d\n", 0); +} + +CONFIGFS_ATTR(i3c_target_ctrl_, hotjoin); + +static struct configfs_item_operations i3c_target_ctrl_item_ops = { + .allow_link = i3c_target_ctrl_func_link, + .drop_link = i3c_target_ctrl_func_unlink, +}; + +static struct configfs_attribute *i3c_target_ctrl_attrs[] = { + &i3c_target_ctrl_attr_hotjoin, + NULL, +}; + +static const struct config_item_type i3c_target_ctrl_type = { + .ct_item_ops = &i3c_target_ctrl_item_ops, + .ct_attrs = i3c_target_ctrl_attrs, + .ct_owner = THIS_MODULE, +}; + +/** + * i3c_target_cfs_add_ctrl_group() - add I3C target controller group + * @ctrl: I3C target controller device + * + * Return: Pointer to struct config_group + */ +struct config_group *i3c_target_cfs_add_ctrl_group(struct i3c_target_ctrl *ctrl) +{ + struct i3c_target_ctrl_group *ctrl_group; + struct config_group *group; + int ret; + + ctrl_group = kzalloc(sizeof(*ctrl_group), GFP_KERNEL); + if (!ctrl_group) { + ret = -ENOMEM; + goto err; + } + + group = &ctrl_group->group; + + config_group_init_type_name(group, dev_name(&ctrl->dev), &i3c_target_ctrl_type); + ret = configfs_register_group(controllers_group, group); + if (ret) { + pr_err("failed to register configfs group for %s\n", dev_name(&ctrl->dev)); + goto err_register_group; + } + + ctrl_group->ctrl = ctrl; + + return group; + +err_register_group: + kfree(ctrl_group); + +err: + return ERR_PTR(ret); +} +EXPORT_SYMBOL(i3c_target_cfs_add_ctrl_group); + +/** + * i3c_target_cfs_remove_ctrl_group() - remove I3C target controller group + * @group: the group to be removed + */ +void i3c_target_cfs_remove_ctrl_group(struct config_group *group) +{ + struct i3c_target_ctrl_group *ctrl_group; + + if (!group) + return; + + ctrl_group = container_of(group, struct i3c_target_ctrl_group, group); + i3c_target_ctrl_put(ctrl_group->ctrl); + configfs_unregister_group(&ctrl_group->group); + kfree(ctrl_group); +} +EXPORT_SYMBOL(i3c_target_cfs_remove_ctrl_group); + +#define I3C_SLAVE_ATTR_R(_name) \ +static ssize_t i3c_target_func_##_name##_show(struct config_item *item, char *page) \ +{ \ + struct i3c_target_func *func = to_i3c_target_func_group(item)->func; \ + return sysfs_emit(page, "0x%04x\n", func->_name); \ +} + +#define I3C_SLAVE_ATTR_W(_name, _u) \ +static ssize_t i3c_target_func_##_name##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + _u val; \ + struct i3c_target_func *func = to_i3c_target_func_group(item)->func; \ + if (kstrto##_u(page, 0, &val) < 0) \ + return -EINVAL; \ + func->_name = val; \ + return len; \ +} + +I3C_SLAVE_ATTR_R(vendor_id); +I3C_SLAVE_ATTR_W(vendor_id, u16); +CONFIGFS_ATTR(i3c_target_func_, vendor_id); + +I3C_SLAVE_ATTR_R(vendor_info); +I3C_SLAVE_ATTR_W(vendor_info, u16); +CONFIGFS_ATTR(i3c_target_func_, vendor_info); + +I3C_SLAVE_ATTR_R(part_id); +I3C_SLAVE_ATTR_W(part_id, u16); +CONFIGFS_ATTR(i3c_target_func_, part_id); + +I3C_SLAVE_ATTR_R(instance_id); +I3C_SLAVE_ATTR_W(instance_id, u8); +CONFIGFS_ATTR(i3c_target_func_, instance_id); + +I3C_SLAVE_ATTR_R(ext_id); +I3C_SLAVE_ATTR_W(ext_id, u16); +CONFIGFS_ATTR(i3c_target_func_, ext_id); + +I3C_SLAVE_ATTR_R(max_write_len); +I3C_SLAVE_ATTR_W(max_write_len, u16); +CONFIGFS_ATTR(i3c_target_func_, max_write_len); + +I3C_SLAVE_ATTR_R(max_read_len); +I3C_SLAVE_ATTR_W(max_read_len, u16); +CONFIGFS_ATTR(i3c_target_func_, max_read_len); + +I3C_SLAVE_ATTR_R(bcr); +I3C_SLAVE_ATTR_W(bcr, u8); +CONFIGFS_ATTR(i3c_target_func_, bcr); + +I3C_SLAVE_ATTR_R(dcr); +I3C_SLAVE_ATTR_W(dcr, u8); +CONFIGFS_ATTR(i3c_target_func_, dcr); + +static struct configfs_attribute *i3c_target_func_attrs[] = { + &i3c_target_func_attr_vendor_id, + &i3c_target_func_attr_vendor_info, + &i3c_target_func_attr_part_id, + &i3c_target_func_attr_instance_id, + &i3c_target_func_attr_ext_id, + &i3c_target_func_attr_max_write_len, + &i3c_target_func_attr_max_read_len, + &i3c_target_func_attr_bcr, + &i3c_target_func_attr_dcr, + NULL, +}; + +static const struct config_item_type i3c_target_func_type = { + .ct_attrs = i3c_target_func_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *i3c_target_func_make(struct config_group *group, const char *name) +{ + struct i3c_target_func_group *func_group; + struct i3c_target_func *func; + int err; + + func_group = kzalloc(sizeof(*func_group), GFP_KERNEL); + if (!func_group) + return ERR_PTR(-ENOMEM); + + config_group_init_type_name(&func_group->group, name, &i3c_target_func_type); + + func = i3c_target_func_create(group->cg_item.ci_name, name); + if (IS_ERR(func)) { + pr_err("failed to create i3c target function device\n"); + err = -EINVAL; + goto free_group; + } + + func->group = &func_group->group; + + func_group->func = func; + + return &func_group->group; + +free_group: + kfree(func_group); + + return ERR_PTR(err); +} + +static void i3c_target_func_drop(struct config_group *group, struct config_item *item) +{ + config_item_put(item); +} + +static struct configfs_group_operations i3c_target_func_group_ops = { + .make_group = &i3c_target_func_make, + .drop_item = &i3c_target_func_drop, +}; + +static const struct config_item_type i3c_target_func_group_type = { + .ct_group_ops = &i3c_target_func_group_ops, + .ct_owner = THIS_MODULE, +}; + +/** + * i3c_target_cfs_add_func_group() - add I3C target function group + * @name: group name + * + * Return: Pointer to struct config_group + */ +struct config_group *i3c_target_cfs_add_func_group(const char *name) +{ + struct config_group *group; + + group = configfs_register_default_group(functions_group, name, + &i3c_target_func_group_type); + if (IS_ERR(group)) + pr_err("failed to register configfs group for %s function\n", + name); + + return group; +} +EXPORT_SYMBOL(i3c_target_cfs_add_func_group); + +/** + * i3c_target_cfs_remove_func_group() - add I3C target function group + * @group: group to be removed + */ +void i3c_target_cfs_remove_func_group(struct config_group *group) +{ + if (IS_ERR_OR_NULL(group)) + return; + + configfs_unregister_default_group(group); +} +EXPORT_SYMBOL(i3c_target_cfs_remove_func_group); + +static const struct config_item_type i3c_target_controllers_type = { + .ct_owner = THIS_MODULE, +}; + +static const struct config_item_type i3c_target_functions_type = { + .ct_owner = THIS_MODULE, +}; + +static const struct config_item_type i3c_target_type = { + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem i3c_target_cfs_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "i3c_target", + .ci_type = &i3c_target_type, + }, + }, + .su_mutex = __MUTEX_INITIALIZER(i3c_target_cfs_subsys.su_mutex), +}; + +static int __init i3c_target_cfs_init(void) +{ + int ret; + struct config_group *root = &i3c_target_cfs_subsys.su_group; + + config_group_init(root); + + ret = configfs_register_subsystem(&i3c_target_cfs_subsys); + if (ret) { + pr_err("Error %d while registering subsystem %s\n", + ret, root->cg_item.ci_namebuf); + goto err; + } + + functions_group = configfs_register_default_group(root, "functions", + &i3c_target_functions_type); + if (IS_ERR(functions_group)) { + ret = PTR_ERR(functions_group); + pr_err("Error %d while registering functions group\n", + ret); + goto err_functions_group; + } + + controllers_group = + configfs_register_default_group(root, "controllers", + &i3c_target_controllers_type); + if (IS_ERR(controllers_group)) { + ret = PTR_ERR(controllers_group); + pr_err("Error %d while registering controllers group\n", + ret); + goto err_controllers_group; + } + + return 0; + +err_controllers_group: + configfs_unregister_default_group(functions_group); + +err_functions_group: + configfs_unregister_subsystem(&i3c_target_cfs_subsys); + +err: + return ret; +} +module_init(i3c_target_cfs_init); + +MODULE_DESCRIPTION("I3C FUNC CONFIGFS"); +MODULE_AUTHOR("Frank Li "); diff --git a/drivers/i3c/target.c b/drivers/i3c/target.c new file mode 100644 index 0000000000000..f0bcda2c4599f --- /dev/null +++ b/drivers/i3c/target.c @@ -0,0 +1,453 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * configfs to configure the I3C Slave + * + * Copyright (C) 2023 NXP + * Author: Frank Li + */ + +#include +#include +#include +#include +#include + +static DEFINE_MUTEX(func_lock); +static struct class *i3c_target_ctrl_class; + +static void i3c_target_func_dev_release(struct device *dev) +{ + struct i3c_target_func *func = to_i3c_target_func(dev); + + kfree(func->name); + kfree(func); +} + +static const struct device_type i3c_target_func_type = { + .release = i3c_target_func_dev_release, +}; + +static int i3c_target_func_match_driver(struct device *dev, struct device_driver *drv) +{ + return !strncmp(dev_name(dev), drv->name, strlen(drv->name)); +} + +static int i3c_target_func_device_probe(struct device *dev) +{ + struct i3c_target_func *func = to_i3c_target_func(dev); + struct i3c_target_func_driver *driver = to_i3c_target_func_driver(dev->driver); + + if (!driver->probe) + return -ENODEV; + + func->driver = driver; + + return driver->probe(func); +} + +static void i3c_target_func_device_remove(struct device *dev) +{ + struct i3c_target_func *func = to_i3c_target_func(dev); + struct i3c_target_func_driver *driver = to_i3c_target_func_driver(dev->driver); + + if (driver->remove) + driver->remove(func); + func->driver = NULL; +} + +static const struct bus_type i3c_target_func_bus_type = { + .name = "i3c_target_func", + .probe = i3c_target_func_device_probe, + .remove = i3c_target_func_device_remove, + .match = i3c_target_func_match_driver, +}; + +static void i3c_target_ctrl_release(struct device *dev) +{ + kfree(to_i3c_target_ctrl(dev)); +} + +static void devm_i3c_target_ctrl_release(struct device *dev, void *res) +{ + struct i3c_target_ctrl *ctrl = *(struct i3c_target_ctrl **)res; + + i3c_target_ctrl_destroy(ctrl); +} + +struct i3c_target_ctrl * +__devm_i3c_target_ctrl_create(struct device *dev, const struct i3c_target_ctrl_ops *ops, + struct module *owner) +{ + struct i3c_target_ctrl **ptr, *ctrl; + + ptr = devres_alloc(devm_i3c_target_ctrl_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + ctrl = __i3c_target_ctrl_create(dev, ops, owner); + if (!IS_ERR(ctrl)) { + *ptr = ctrl; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ctrl; +} + +static int devm_i3c_target_ctrl_match(struct device *dev, void *res, void *match_data) +{ + struct i3c_target_ctrl **ptr = res; + + return *ptr == match_data; +} + +/** + * __i3c_target_ctrl_create() - create a new target controller device + * @dev: device that is creating the new target controller + * @ops: function pointers for performing target controller operations + * @owner: the owner of the module that creates the target controller device + * + * Return: Pointer to struct i3c_target_ctrl + */ +struct i3c_target_ctrl * +__i3c_target_ctrl_create(struct device *dev, const struct i3c_target_ctrl_ops *ops, + struct module *owner) +{ + struct i3c_target_ctrl *ctrl; + int ret; + + if (WARN_ON(!dev)) + return ERR_PTR(-EINVAL); + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + device_initialize(&ctrl->dev); + ctrl->dev.class = i3c_target_ctrl_class; + ctrl->dev.parent = dev; + ctrl->dev.release = i3c_target_ctrl_release; + ctrl->ops = ops; + + ret = dev_set_name(&ctrl->dev, "%s", dev_name(dev)); + if (ret) + goto put_dev; + + ret = device_add(&ctrl->dev); + if (ret) + goto put_dev; + + ctrl->group = i3c_target_cfs_add_ctrl_group(ctrl); + if (!ctrl->group) + goto put_dev; + + return ctrl; + +put_dev: + put_device(&ctrl->dev); + kfree(ctrl); + + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(__i3c_target_ctrl_create); + +/** + * devm_i3c_target_ctrl_destroy() - destroy the target controller device + * @dev: device that hat has to be destroy + * @ctrl: the target controller device that has to be destroy + * + * Invoke to create a new target controller device and add it to i3c_target class. While at that, it + * also associates the device with the i3c_target using devres. On driver detach, release function + * is invoked on the devres data, then devres data is freed. + */ +void devm_i3c_target_ctrl_destroy(struct device *dev, struct i3c_target_ctrl *ctrl) +{ + int r; + + r = devres_destroy(dev, devm_i3c_target_ctrl_release, devm_i3c_target_ctrl_match, + ctrl); + dev_WARN_ONCE(dev, r, "couldn't find I3C controller resource\n"); +} +EXPORT_SYMBOL_GPL(devm_i3c_target_ctrl_destroy); + +/** + * i3c_target_ctrl_destroy() - destroy the target controller device + * @ctrl: the target controller device that has to be destroyed + * + * Invoke to destroy the I3C target device + */ +void i3c_target_ctrl_destroy(struct i3c_target_ctrl *ctrl) +{ + i3c_target_cfs_remove_ctrl_group(ctrl->group); + device_unregister(&ctrl->dev); +} +EXPORT_SYMBOL_GPL(i3c_target_ctrl_destroy); + +/** + * i3c_target_ctrl_add_func() - bind I3C target function to an target controller + * @ctrl: the controller device to which the target function should be added + * @func: the target function to be added + * + * An I3C target device can have only one functions. + */ +int i3c_target_ctrl_add_func(struct i3c_target_ctrl *ctrl, struct i3c_target_func *func) +{ + if (ctrl->func) + return -EBUSY; + + ctrl->func = func; + func->ctrl = ctrl; + + return 0; +} +EXPORT_SYMBOL_GPL(i3c_target_ctrl_add_func); + +/** + * i3c_target_ctrl_remove_func() - unbind I3C target function to an target controller + * @ctrl: the controller device to which the target function should be removed + * @func: the target function to be removed + * + * An I3C target device can have only one functions. + */ +void i3c_target_ctrl_remove_func(struct i3c_target_ctrl *ctrl, struct i3c_target_func *func) +{ + ctrl->func = NULL; +} +EXPORT_SYMBOL_GPL(i3c_target_ctrl_remove_func); + +/** + * i3c_target_ctrl_get() - get the I3C target controller + * @name: device name of the target controller + * + * Invoke to get struct i3c_target_ctrl * corresponding to the device name of the + * target controller + */ +struct i3c_target_ctrl *i3c_target_ctrl_get(const char *name) +{ + int ret = -EINVAL; + struct i3c_target_ctrl *ctrl; + struct device *dev; + struct class_dev_iter iter; + + class_dev_iter_init(&iter, i3c_target_ctrl_class, NULL, NULL); + while ((dev = class_dev_iter_next(&iter))) { + if (strcmp(name, dev_name(dev))) + continue; + + ctrl = to_i3c_target_ctrl(dev); + if (!try_module_get(ctrl->ops->owner)) { + ret = -EINVAL; + goto err; + } + + class_dev_iter_exit(&iter); + get_device(&ctrl->dev); + return ctrl; + } + +err: + class_dev_iter_exit(&iter); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(i3c_target_ctrl_get); + +/** + * i3c_target_ctrl_put() - release the I3C endpoint controller + * @ctrl: target controller returned by pci_target_get() + * + * release the refcount the caller obtained by invoking i3c_target_ctrl_get() + */ +void i3c_target_ctrl_put(struct i3c_target_ctrl *ctrl) +{ + if (!ctrl || IS_ERR(ctrl)) + return; + + module_put(ctrl->ops->owner); + put_device(&ctrl->dev); +} +EXPORT_SYMBOL_GPL(i3c_target_ctrl_put); + +/** + * i3c_target_ctrl_hotjoin() - trigger device hotjoin + * @ctrl: target controller + * + * return: 0: success, others failure + */ +int i3c_target_ctrl_hotjoin(struct i3c_target_ctrl *ctrl) +{ + if (!ctrl || IS_ERR(ctrl)) + return -EINVAL; + + if (!ctrl->ops->hotjoin) + return -EINVAL; + + return ctrl->ops->hotjoin(ctrl); +} +EXPORT_SYMBOL_GPL(i3c_target_ctrl_hotjoin); + +/** + * i3c_target_func_bind() - Notify the function driver that the function device has been bound to a + * controller device + * @func: the function device which has been bound to the controller device + * + * Invoke to notify the function driver that it has been bound to a controller device + */ +int i3c_target_func_bind(struct i3c_target_func *func) +{ + struct device *dev = &func->dev; + int ret; + + if (!func->driver) { + dev_WARN(dev, "func device not bound to driver\n"); + return -EINVAL; + } + + if (!try_module_get(func->driver->owner)) + return -EAGAIN; + + mutex_lock(&func->lock); + ret = func->driver->ops->bind(func); + if (!ret) + func->is_bound = true; + mutex_unlock(&func->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(i3c_target_func_bind); + +/** + * i3c_target_func_unbind() - Notify the function driver that the binding between the function + * device and controller device has been lost. + * @func: the function device which has lost the binding with the controller device. + * + * Invoke to notify the function driver that the binding between the function device and controller + * device has been lost. + */ +void i3c_target_func_unbind(struct i3c_target_func *func) +{ + if (!func->driver) { + dev_WARN(&func->dev, "func device not bound to driver\n"); + return; + } + + mutex_lock(&func->lock); + if (func->is_bound) + func->driver->ops->unbind(func); + mutex_unlock(&func->lock); + + module_put(func->driver->owner); +} +EXPORT_SYMBOL_GPL(i3c_target_func_unbind); + +/** + * i3c_target_func_create() - create a new I3C function device + * @drv_name: the driver name of the I3C function device. + * @name: the name of the function device. + * + * Invoke to create a new I3C function device by providing the name of the function device. + */ +struct i3c_target_func *i3c_target_func_create(const char *drv_name, const char *name) +{ + struct i3c_target_func *func; + struct device *dev; + int ret; + + func = kzalloc(sizeof(*func), GFP_KERNEL); + if (!func) + return ERR_PTR(-ENOMEM); + + dev = &func->dev; + device_initialize(dev); + dev->bus = &i3c_target_func_bus_type; + dev->type = &i3c_target_func_type; + mutex_init(&func->lock); + + ret = dev_set_name(dev, "%s.%s", drv_name, name); + if (ret) { + put_device(dev); + return ERR_PTR(ret); + } + + ret = device_add(dev); + if (ret) { + put_device(dev); + return ERR_PTR(ret); + } + + return func; +} +EXPORT_SYMBOL_GPL(i3c_target_func_create); + +/** + * __i3c_target_func_register_driver() - register a new I3C function driver + * @driver: structure representing I3C function driver + * @owner: the owner of the module that registers the I3C function driver + * + * Invoke to register a new I3C function driver. + */ +int __i3c_target_func_register_driver(struct i3c_target_func_driver *driver, struct module *owner) +{ + int ret = -EEXIST; + + if (!driver->ops) + return -EINVAL; + + if (!driver->ops->bind || !driver->ops->unbind) + return -EINVAL; + + driver->driver.bus = &i3c_target_func_bus_type; + driver->driver.owner = owner; + + ret = driver_register(&driver->driver); + if (ret) + return ret; + + i3c_target_cfs_add_func_group(driver->driver.name); + + return 0; +} +EXPORT_SYMBOL_GPL(__i3c_target_func_register_driver); + +/** + * i3c_target_func_unregister_driver() - unregister the I3C function driver + * @fd: the I3C function driver that has to be unregistered + * + * Invoke to unregister the I3C function driver. + */ +void i3c_target_func_unregister_driver(struct i3c_target_func_driver *fd) +{ + mutex_lock(&func_lock); + mutex_unlock(&func_lock); +} +EXPORT_SYMBOL_GPL(i3c_target_func_unregister_driver); + +static int __init i3c_target_init(void) +{ + int ret; + + i3c_target_ctrl_class = class_create("i3c_target"); + if (IS_ERR(i3c_target_ctrl_class)) { + pr_err("failed to create i3c target class --> %ld\n", + PTR_ERR(i3c_target_ctrl_class)); + return PTR_ERR(i3c_target_ctrl_class); + } + + ret = bus_register(&i3c_target_func_bus_type); + if (ret) { + class_destroy(i3c_target_ctrl_class); + pr_err("failed to register i3c target func bus --> %d\n", ret); + return ret; + } + + return 0; +} +module_init(i3c_target_init); + +static void __exit i3c_target_exit(void) +{ + class_destroy(i3c_target_ctrl_class); + bus_unregister(&i3c_target_func_bus_type); +} +module_exit(i3c_target_exit); + diff --git a/include/linux/i3c/target.h b/include/linux/i3c/target.h new file mode 100644 index 0000000000000..9b73114588350 --- /dev/null +++ b/include/linux/i3c/target.h @@ -0,0 +1,527 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2023 NXP. + * + * Author: Frank Li + */ + +#ifndef I3C_TARGET_H +#define I3C_TARGET_H + +#include + +struct i3c_target_func; +struct i3c_target_ctrl; + +/** + * struct i3c_target_func_ops - set of function pointers for performing i3c target function + * operations + * @bind: ops to perform when a controller device has been bound to function device + * @unbind: ops to perform when a binding has been lost between a controller device and function + * device + */ +struct i3c_target_func_ops { + int (*bind)(struct i3c_target_func *func); + void (*unbind)(struct i3c_target_func *func); +}; + +/** + * struct i3c_target_func_driver - represents the I3C function driver + * @probe: ops to perform when a new function device has been bound to the function driver + * @remove: ops to perform when the binding between the function device and function driver is + * broken + * @name: I3C Function driver name + * @driver: I3C Function driver + * @ops: set of function pointers for performing function operations + * @owner: the owner of the module that registers the I3C function driver + * @epf_group: list of configfs group corresponding to the I3C function driver + */ +struct i3c_target_func_driver { + int (*probe)(struct i3c_target_func *func); + void (*remove)(struct i3c_target_func *func); + + char *name; + struct device_driver driver; + struct i3c_target_func_ops *ops; + struct module *owner; +}; + +/** + * struct i3c_target_func - represents the I3C function device + * @dev: the I3C function device + * @name: the name of the I3C function device + * @driver: the function driver to which this function device is bound + * @group: configfs group associated with the EPF device + * @lock: mutex to protect i3c_target_func_ops + * @ctrl: binded I3C controller device + * @is_bound: indicates if bind notification to function driver has been invoked + * @vendor_id: vendor id + * @part_id: part id + * @instance_id: instance id + * @ext_id: ext id + * @vendor_info: vendor info + * @static_addr: static address for I2C. It is 0 for I3C. + * @max_write_len: maximum write length + * @max_read_len: maximum read length + * @bcr: bus characteristics register (BCR) + * @dcr: device characteristics register (DCR) + */ +struct i3c_target_func { + struct device dev; + char *name; + struct i3c_target_func_driver *driver; + struct config_group *group; + /* mutex to protect against concurrent access of i3c_target_func_ops */ + struct mutex lock; + struct i3c_target_ctrl *ctrl; + bool is_bound; + + u16 vendor_id; + u16 part_id; + u8 instance_id; + u16 ext_id; + u8 vendor_info; + u16 static_addr; + u16 max_write_len; //0 is hardware default max value + u16 max_read_len; //0 is hardware default max value + u8 bcr; + u8 dcr; +}; + +enum i3c_request_stat { + I3C_REQUEST_OKAY, + I3C_REQUEST_PARTIAL, + I3C_REQUEST_ERR, + I3C_REQUEST_CANCEL, +}; + +/** + * struct i3c_request - represents the an I3C transfer request + * @buf: data buffer + * @length: data length + * @complete: call back function when request finished or cancelled + * @context: general data for complete callback function + * @list: link list + * @status: transfer status + * @actual: how much actually transferred + * @ctrl: I3C target controller associate with this request + * @tx: transfer direction, 1: target to master, 0: master to target + */ +struct i3c_request { + void *buf; + unsigned int length; + + void (*complete)(struct i3c_request *req); + void *context; + struct list_head list; + + enum i3c_request_stat status; + unsigned int actual; + struct i3c_target_ctrl *ctrl; + bool tx; +}; + +/** + * struct i3c_target_ctrl_features - represents I3C target controller features. + * @tx_fifo_sz: tx hardware fifo size + * @rx_fifo_sz: rx hardware fifo size + */ +struct i3c_target_ctrl_features { + u32 tx_fifo_sz; + u32 rx_fifo_sz; +}; + +/** + * struct i3c_target_ctrl_ops - set of function pointers for performing controller operations + * @set_config: set I3C controller configuration + * @enable: enable I3C controller + * @disable: disable I3C controller + * @raise_ibi: raise IBI interrupt to master + * @alloc_request: allocate a i3c_request, optional, default use kmalloc + * @free_request: free a i3c_request, default use kfree + * @queue: queue an I3C transfer + * @dequeue: dequeue an I3C transfer + * @cancel_all_reqs: call all pending requests + * @fifo_status: current FIFO status + * @fifo_flush: flush hardware FIFO + * @hotjoin: raise hotjoin request to master + * @set_status_format1: set i3c status format1 + * @get_status_format1: get i3c status format1 + * @get_addr: get i3c dynmatic address + * @get_features: ops to get the features supported by the I3C target controller + * @owner: the module owner containing the ops + */ +struct i3c_target_ctrl_ops { + int (*set_config)(struct i3c_target_ctrl *ctrl, struct i3c_target_func *func); + int (*enable)(struct i3c_target_ctrl *ctrl); + int (*disable)(struct i3c_target_ctrl *ctrl); + int (*raise_ibi)(struct i3c_target_ctrl *ctrl, void *p, u8 size); + + struct i3c_request *(*alloc_request)(struct i3c_target_ctrl *ctrl, gfp_t gfp_flags); + void (*free_request)(struct i3c_request *req); + + int (*queue)(struct i3c_request *req, gfp_t gfp_flags); + int (*dequeue)(struct i3c_request *req); + + void (*cancel_all_reqs)(struct i3c_target_ctrl *ctrl, bool tx); + + int (*fifo_status)(struct i3c_target_ctrl *ctrl, bool tx); + void (*fifo_flush)(struct i3c_target_ctrl *ctrl, bool tx); + int (*hotjoin)(struct i3c_target_ctrl *ctrl); + int (*set_status_format1)(struct i3c_target_ctrl *ctrl, u16 status); + u16 (*get_status_format1)(struct i3c_target_ctrl *ctrl); + u8 (*get_addr)(struct i3c_target_ctrl *ctrl); + const struct i3c_target_ctrl_features *(*get_features)(struct i3c_target_ctrl *ctrl); + struct module *owner; +}; + +/** + * struct i3c_target_ctrl - represents the I3C target device + * @dev: I3C target device + * @ops: function pointers for performing endpoint operations + * @func: target functions present in this controller device + * @group: configfs group representing the I3C controller device + */ +struct i3c_target_ctrl { + struct device dev; + const struct i3c_target_ctrl_ops *ops; + struct i3c_target_func *func; + struct config_group *group; +}; + +/** + * i3c_target_ctrl_raise_ibi() - Raise IBI to master + * @ctrl: I3C target controller + * @p: optional data for IBI + * @size: size of optional data + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline int i3c_target_ctrl_raise_ibi(struct i3c_target_ctrl *ctrl, void *p, u8 size) +{ + if (ctrl && ctrl->ops && ctrl->ops->raise_ibi) + return ctrl->ops->raise_ibi(ctrl, p, size); + + return -EINVAL; +} + +/** + * i3c_target_ctrl_cancel_all_reqs() - Cancel all pending request + * @ctrl: I3C target controller + * @tx: Transfer diretion queue + */ +static inline void i3c_target_ctrl_cancel_all_reqs(struct i3c_target_ctrl *ctrl, bool tx) +{ + if (ctrl && ctrl->ops && ctrl->ops->cancel_all_reqs) + ctrl->ops->cancel_all_reqs(ctrl, tx); +} + +/** + * i3c_target_ctrl_set_config() - Set controller configuration + * @ctrl: I3C target controller device + * @func: Function device + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline int +i3c_target_ctrl_set_config(struct i3c_target_ctrl *ctrl, struct i3c_target_func *func) +{ + if (ctrl && ctrl->ops && ctrl->ops->set_config) + return ctrl->ops->set_config(ctrl, func); + + return -EINVAL; +} + +/** + * i3c_target_ctrl_enable() - Enable I3C controller + * @ctrl: I3C target controller device + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline int +i3c_target_ctrl_enable(struct i3c_target_ctrl *ctrl) +{ + if (ctrl && ctrl->ops && ctrl->ops->enable) + return ctrl->ops->enable(ctrl); + + return -EINVAL; +} + +/** + * i3c_target_ctrl_disable() - Disable I3C controller + * @ctrl: I3C target controller device + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline int +i3c_target_ctrl_disable(struct i3c_target_ctrl *ctrl) +{ + if (ctrl && ctrl->ops && ctrl->ops->disable) + return ctrl->ops->disable(ctrl); + + return -EINVAL; +} + +/** + * i3c_target_ctrl_alloc_request() - Alloc an I3C transfer + * @ctrl: I3C target controller device + * @gfp_flags: additional gfp flags used when allocating the buffers + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline struct i3c_request * +i3c_target_ctrl_alloc_request(struct i3c_target_ctrl *ctrl, gfp_t gfp_flags) +{ + struct i3c_request *req = NULL; + + if (ctrl && ctrl->ops && ctrl->ops->alloc_request) + req = ctrl->ops->alloc_request(ctrl, gfp_flags); + else + req = kzalloc(sizeof(*req), gfp_flags); + + if (req) + req->ctrl = ctrl; + + return req; +} + +/** + * i3c_target_ctrl_free_request() - Free an I3C transfer + * @req: I3C transfer request + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline void +i3c_target_ctrl_free_request(struct i3c_request *req) +{ + struct i3c_target_ctrl *ctrl; + + if (!req) + return; + + ctrl = req->ctrl; + if (ctrl && ctrl->ops && ctrl->ops->free_request) + ctrl->ops->free_request(req); + else + kfree(req); +} + +/** + * i3c_target_ctrl_queue() - Queue an I3C transfer + * @req: I3C transfer request + * @gfp_flags: additional gfp flags used when allocating the buffers + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline int +i3c_target_ctrl_queue(struct i3c_request *req, gfp_t gfp_flags) +{ + struct i3c_target_ctrl *ctrl; + int ret = -EINVAL; + + if (!req) + return -EINVAL; + + ctrl = req->ctrl; + + req->actual = 0; + req->status = 0; + if (ctrl && ctrl->ops && ctrl->ops->queue) + ret = ctrl->ops->queue(req, gfp_flags); + + return ret; +} + +/** + * i3c_target_ctrl_dequeue() - Dequeue an I3C transfer + * @req: I3C transfer request + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline int +i3c_target_ctrl_dequeue(struct i3c_request *req) +{ + struct i3c_target_ctrl *ctrl; + int ret = -EINVAL; + + if (!req) + return -EINVAL; + + ctrl = req->ctrl; + if (ctrl && ctrl->ops && ctrl->ops->dequeue) + ret = ctrl->ops->dequeue(req); + + return ret; +} + +/** + * i3c_target_ctrl_fifo_status() - Get controller FIFO status + * @ctrl: I3C target controller device + * @tx: 1: Target to master, 0: master to target + * + * Returns: How much data in FIFO + */ +static inline int +i3c_target_ctrl_fifo_status(struct i3c_target_ctrl *ctrl, bool tx) +{ + if (ctrl && ctrl->ops && ctrl->ops->fifo_status) + return ctrl->ops->fifo_status(ctrl, tx); + + return 0; +} + +/** + * i3c_target_ctrl_fifo_flush() - Flush controller FIFO + * @ctrl: I3C target controller device + * @tx: 1: Target to master, 0: master to target + * + */ +static inline void +i3c_target_ctrl_fifo_flush(struct i3c_target_ctrl *ctrl, bool tx) +{ + if (ctrl && ctrl->ops && ctrl->ops->fifo_flush) + return ctrl->ops->fifo_flush(ctrl, tx); +} + +/** + * i3c_target_ctrl_get_features() - Get controller supported features + * @ctrl: I3C target controller device + * + * Returns: The pointer to struct i3c_target_ctrl_features + */ +static inline const struct i3c_target_ctrl_features* +i3c_target_ctrl_get_features(struct i3c_target_ctrl *ctrl) +{ + if (ctrl && ctrl->ops && ctrl->ops->get_features) + return ctrl->ops->get_features(ctrl); + + return NULL; +} + +/** + * i3c_target_ctrl_set_status_format1() - Set controller supported features + * @ctrl: I3C target controller device + * @status: I3C GETSTATUS format1 + * + * Returns: Zero for success, or an error code in case of failure + */ +static inline int +i3c_target_ctrl_set_status_format1(struct i3c_target_ctrl *ctrl, u16 status) +{ + if (ctrl && ctrl->ops && ctrl->ops->set_status_format1) + return ctrl->ops->set_status_format1(ctrl, status); + + return -EINVAL; +} + +/** + * i3c_target_ctrl_get_status_format1() - Get controller supported features + * @ctrl: I3C target controller device + * + * Return: I3C GETSTATUS format1 + */ +static inline u16 +i3c_target_ctrl_get_status_format1(struct i3c_target_ctrl *ctrl) +{ + if (ctrl && ctrl->ops && ctrl->ops->get_status_format1) + return ctrl->ops->get_status_format1(ctrl); + + return 0; +} + +/** + * i3c_target_ctrl_get_addr() - Get controller address + * @ctrl: I3C target controller device + * + * Return: address + */ +static inline u8 i3c_target_ctrl_get_addr(struct i3c_target_ctrl *ctrl) +{ + if (ctrl && ctrl->ops && ctrl->ops->get_addr) + return ctrl->ops->get_addr(ctrl); + + return 0; +} + +#define to_i3c_target_ctrl(device) container_of((device), struct i3c_target_ctrl, dev) + +#define to_i3c_target_func(func_dev) container_of((func_dev), struct i3c_target_func, dev) +#define to_i3c_target_func_driver(drv) (container_of((drv), struct i3c_target_func_driver, driver)) + +#define i3c_target_ctrl_create(dev, ops) \ + __i3c_target_ctrl_create((dev), (ops), THIS_MODULE) +#define devm_i3c_target_ctrl_create(dev, ops) \ + __devm_i3c_target_ctrl_create((dev), (ops), THIS_MODULE) + +#ifdef CONFIG_I3C_TARGET +struct i3c_target_ctrl * +__devm_i3c_target_ctrl_create(struct device *dev, const struct i3c_target_ctrl_ops *ops, + struct module *owner); +struct i3c_target_ctrl * +__i3c_target_ctrl_create(struct device *dev, const struct i3c_target_ctrl_ops *ops, + struct module *owner); + +void devm_i3c_target_ctrl_destroy(struct device *dev, struct i3c_target_ctrl *epc); +void i3c_target_ctrl_destroy(struct i3c_target_ctrl *epc); + +int i3c_target_ctrl_add_func(struct i3c_target_ctrl *ctrl, struct i3c_target_func *func); +void i3c_target_ctrl_remove_func(struct i3c_target_ctrl *ctrl, struct i3c_target_func *func); +int i3c_target_ctrl_hotjoin(struct i3c_target_ctrl *ctrl); + +struct config_group *i3c_target_cfs_add_ctrl_group(struct i3c_target_ctrl *ctrl); + +void i3c_target_cfs_remove_ctrl_group(struct config_group *group); +struct config_group *i3c_target_cfs_add_func_group(const char *name); +void i3c_target_cfs_remove_func_group(struct config_group *group); +struct i3c_target_ctrl *i3c_target_ctrl_get(const char *name); +void i3c_target_ctrl_put(struct i3c_target_ctrl *ctrl); + +int i3c_target_func_bind(struct i3c_target_func *func); +void i3c_target_func_unbind(struct i3c_target_func *func); +struct i3c_target_func *i3c_target_func_create(const char *drv_name, const char *name); + +#define i3c_target_func_register_driver(drv) \ + __i3c_target_func_register_driver(drv, THIS_MODULE) + +int __i3c_target_func_register_driver(struct i3c_target_func_driver *drv, struct module *owner); +void i3c_target_func_unregister_driver(struct i3c_target_func_driver *drv); +#else +static inline struct i3c_target_ctrl * +__devm_i3c_target_ctrl_create(struct device *dev, const struct i3c_target_ctrl_ops *ops, + struct module *owner) +{ + return NULL; +} + +static inline struct i3c_target_ctrl * +__i3c_target_ctrl_create(struct device *dev, const struct i3c_target_ctrl_ops *ops, + struct module *owner) +{ + return NULL; +} +#endif + +#define DECLARE_I3C_TARGET_FUNC(_name, _probe, _remove, _ops) \ + static struct i3c_target_func_driver _name ## i3c_func = { \ + .driver.name = __stringify(_name), \ + .owner = THIS_MODULE, \ + .probe = _probe, \ + .remove = _remove, \ + .ops = _ops \ + }; \ + MODULE_ALIAS("i3cfunc:" __stringify(_name)) + +#define DECLARE_I3C_TARGET_INIT(_name, _probe, _remove, _ops) \ + DECLARE_I3C_TARGET_FUNC(_name, _probe, _remove, _ops); \ + static int __init _name ## mod_init(void) \ + { \ + return i3c_target_func_register_driver(&_name ## i3c_func); \ + } \ + static void __exit _name ## mod_exit(void) \ + { \ + i3c_target_func_unregister_driver(&_name ## i3c_func); \ + } \ + module_init(_name ## mod_init); \ + module_exit(_name ## mod_exit) + +#endif From patchwork Tue Jan 23 23:10:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765761 Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05on2067.outbound.protection.outlook.com [40.107.22.67]) (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 17E3C54F80; Tue, 23 Jan 2024 23:11:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.22.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051476; cv=fail; b=jG8NzWRHZ3jWbZ8vtlht2ptIvNZ/8jBm2y7GZegVZw9xs8glsoZabOCMgyDqhLAfOK1WDoXhs80LmxyYlXhvVMctPtFSospjO2Aw2g0c4xM31dMBwaDX5It3NVdxAS4emE8g9uSl+qSy5cGt+lRy8fKr6IbZFxAaTZUTpy4P0LY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051476; c=relaxed/simple; bh=xUss3csYfHdCltrg+pFxqrfdbvboutFgGbf1Juggzig=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=EYgRW52zY/kxlUtOvbdrpPI8tjDH0ArK3qbajH56saLEensYzAYm3EceG1lXoPA9Kacab1CQ+6fiCD9Xo/Q5/uNQjEEX12YIRsrXiYbJfOTiXGDet04ksLlgY+n+Z3BBpXr3PJl1fgCd52F9qtBrE2kXc3iJqYNs6l33TSxiFxA= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=jLMtZ9lT; arc=fail smtp.client-ip=40.107.22.67 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="jLMtZ9lT" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=g9eiTiYabCr9e4nXRSPtTkYIxacGkq7BRfVGKz9MHRmSr1cM9TaYKB+0KJPHDgaNEWMXg9+LKbsIsr6VUZYnBHLEw1Le7wDfAT2txWi42zI/+HLp8OpqWXpnZHMqp3NJAdVPE0A8UmQw+Sc7V1/h3lFgcoCA96pu3vYSqGFWmPuQX8tFFW8tNDzHKgIMXkjJGRsxDfp02SDusKpbUv2BH1vPP9XCVQ8BA4X64bSsSSuMoHCUlmTsez0AOfvNAUBVUaMnao8NjGhaYxa8o2XlJfTKEVV5GaG3XGecdJW3BtpV1INy2IqybDXiskw4kFZLVHoecJ5L0aO7u/zbkABU0A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=eeFeSa6EDN9RUHWjHYeb4cCKIA0/LO0G9GX7zxcsJ/8=; b=DcShAcPA5EHwM/4ezLsCqoGImej+UL8Z3oUDrevGvhXRhAMgLPoJ5X3C4cd/HNlOAJiU+htZZAwhCfLocI9LcfHSrq8GTMHKGMoWWoNON7jFarFvZzRHJTQCLUN7Y5Q397UWQmFgxTto8qLXF9wuE+InhnRKzxuw3uM95S9PK/fCKKp/MvZ039ymb2ymief/0oA6WlCHf0zXhP1p5GZUmg88OWkMDfQ6UcuyDY0eN4aQB9wPE+FJ/cGY0R98j7JcaFwFpzUEpSMmoAlSineApqzlmBoUrhx+oXnvTwZy52t/ocI4W95eIYNUQuY1CBw/oA3r93n7drl7jIKf7Bx6sw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=eeFeSa6EDN9RUHWjHYeb4cCKIA0/LO0G9GX7zxcsJ/8=; b=jLMtZ9lTCVgOcN8nZKPzz78nqwo8UgQyrZ9QRKwf9KMrr7wDdXw4s/l2aF+3WoTeJHPBXe1NF1SRpR8hlimuLTevxpGl2o0WDRD+3k7or4Frbpp+kS0ZpjoVvPZJ9tkNNjuAxrIlB2euBKJAnceph7DA87S88oWV8BG0G2R3q5c= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:08 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:08 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 2/8] dt-bindings: i3c: svc: add proptery mode Date: Tue, 23 Jan 2024 18:10:37 -0500 Message-Id: <20240123231043.3891847-3-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: 1252dd24-90b8-4b3a-a9d7-08dc1c689510 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Ns39v0odS/zDCsUlxiAFTq3/EJfjA1TZFWRzb7L7wcQdHj6pRsjV7AA7VSmKwvCkMBtqdIGy1IAsnvS22jpRY0KbqoVsSgM8vSsx/UnH5GLz1Q5b00rt4Ni5nVzLjof3mWO4d3Z0o7byqngucfsW80xZeLiCtkeMSqR4sOG9l08w4ztvaQEi78lrqT6nbY4kAupZ+auNFv4voXwLpTaEz2FQ4Irh4/A+eH/NKrGmK/vHFGcpZgHMg7Obfv970WSP8aQ2cIov54JedojpqpATe20fHPhA89KU2tS4fwDI1Ej+XCY1xIoyYnUENJh0hp8BNFUqmK6ZT/6m4mQCyrE5Tg737/systhZP48zdxzEvfPmx1QfzRdDUtL/Ry0wgWOr+UrEfvYpeRJxDw3S7lHME0pwVljmLpdXqMPH/FupRu+1wC5V1qKoDwIWEbFponcqy02FnOGgNAhJSQhJw5oB5XLxJtg2HSWO3qX9U7dOMBOZiqJ8RNnQ6kg8MPHJHEipxdhhjy8kfZ+BuCc4mmOsdA5L9qyA4O7DP9AXO3DHZs6N+5H11iGJrh3pmb2S5LswsuL5FZ5h7G5EDiEjOilXO7y3sErb0nM2mcaBPKmol50= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(966005)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: kXPbYnvHlmv7sA/RSTTplPkSY+FhYI+FkI7jObFio8h1v7bhxKcCu0Ix6CfkNus4mCIQ9J+u31v0nGwHQ1Md9A5D3R7rfGjpfWQOCXppB6iyTXeQMjm9WNCajFqcC+KQtA+3F0fXDPaa2YD9GuCb0UVoWXmeDmFRAFCz+6bAHpqAfK+7gSKgbi/Par7siXV38HxVAgK7kH+mpO91wH7Z1qq9c/SxIk32AFCjeSGxnC+osTOB/Jb9uaj37uFsOMXtxzZN+EJXxRdhyO7GRNLwCF831BF26XX7WDq2MLml0vZITbMiKTtB0ws522NvoYTO+IrbhAXKzku6mR/7fPRAjZGzWbKOUkr2fTFqsIQFMIOCh+U3Y0PD+pNKDcpWO/I1NB/6O3sSDGq6SKBDza74uys2UgZ4HrWzUBQ30QCXBeqD1LTwoBfWCaTnmGNMSAw4uxx/4o45XlooPyugHxP3nF97JBNZNjTqXHuhBOdkAprrxaGdEciTNyJb3n0L05XHXB/TSXisce1lvo+Upp5BYUYS2VNZh2n3k+MKJPVYEosbyjeZ1dzcAsaoVAfK5SRtLUmNkWVHGEo26wVq7bAj3hIEF5yljq4rYQv4Ogkut6SEInnSfMMoGjHl+pPG0sJICcGacpsHV4YOBUxlohNAUV1LoU9iTejq2XmfsC2nCf1FMpIHv4TzryRcrK1sN5Z1lTI5radA6KEo4Ijdw03R4EH44hyQU/MAm1NwoeowPDjtWLrH9mHbowQQDE9gXLhWoYc8qdNoE8OvHDcQqCLAaWoKyJrH+jqjy4yrD0YLDyeDktR6h5VjBe0FkLrQlxe2ds0GbYwMF6qhRNWym6fXAx9oR6iqscb6bjsUkD2gKsH2jKueV8aqTXos2WTZXxHbOYrHLEGCWVhfg0AG8uam+rt929xa5t/JVAm4zMEMSsAo6E06DD1a0WSZxE7qbODos07aZdLXWKUsRjkgke1KBTjwIpO/F0OM164WrH0eI6u1E6nlG48PjOwShdFb78EkcNFAybjgjMqvXVUFufBtrMo7T3outWh8SvQBcwyyIqfro3b/wX+1a+WfPsDmCxfDOoGAh0Mq77RwQawoBU+omZXmw6/If3irqv7WLzSFWtPFMRb5F8FpwPwcOoy2zSrUZrxp88q1ADywgh/XVxgwFdg6X6+zoQiQ6t/s48Ftat7r7jsXZMYQhTRK2Z4+cpiWc4eFyht9iKmkImJ08m/ald3lZp/trMsPK2aAUFloGZYBni37AKDPBUdY/yrC+a/GCu9LxdExkppd6XU0hchdEX56EMwT82UVSMM5BIHsDyPG1tCJTYQirCZberpQ+BMPRJcIp5eyFkAovX04wiAWRmXfqH7q7M2z0r1OAYK0JxifzHeNb2p1+rRhtOWezbAD4I35prdkf+sRIRUpkZ9M0WuXyeDY8fQcU9ULyMhkKcQFrrvU0QBsDgO/gsC5NIs/5eufQ3BqtnvaLA+IcgRx3zyZkuT2w3ZBdBzPfCpAh4Xuj8/S6Ot1BDUuNnKc3ZWqyOPRYGCoa2RIYmZTeK29GnBueMhDeR0uL3sQAdaDfCA9H6F6XZmFpYGdX2AI7AM5 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1252dd24-90b8-4b3a-a9d7-08dc1c689510 X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:08.4427 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: JavVMYcjOsEcTKVTZapuuZrCosPgfe+raMzYrAcabmGkt3VQ+BSpk8g6oEMxa2IiSzIDZ9FXtf7MotxSSPolTA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 Add 'mode' property to distinguish between 'controller' and 'target' modes. Signed-off-by: Frank Li --- Notes: Change from v3 to v4 -fix dtb check error Change from v2 to v3 - using 'mode' distringuish master and target mode .../devicetree/bindings/i3c/silvaco,i3c-master.yaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml index 133855f11b4f5..3af77d143f018 100644 --- a/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml +++ b/Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/i3c/silvaco,i3c-master.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Silvaco I3C master +title: Silvaco I3C master/target maintainers: - Conor Culhane @@ -22,6 +22,15 @@ properties: interrupts: maxItems: 1 + mode: + description: + Tells Dual-Role I3C controllers that we want to work on a particular + mode. In case this attribute isn't passed via DT, I3C controllers + should default to 'controller'. + $ref: /schemas/types.yaml#/definitions/string + enum: [controller, target] + default: controller + clocks: items: - description: system clock From patchwork Tue Jan 23 23:10:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765328 Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05on2067.outbound.protection.outlook.com [40.107.22.67]) (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 679B655795; Tue, 23 Jan 2024 23:11:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.22.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051478; cv=fail; b=l1vt1+8ASoPmJzywqypO7QB8yIcTaG+vCuIPT9CFqhptw2ldaYjA4GvcPz//Srj9R8GuhXHWxOqdagklMk7sSQ7aXhjC98Q/+z8VuaffcWjTtF8awpRiIf8omjfYOUW39cDSbvZgHndyH78yLA7LGnAMFsSB4urub/ztTNdA2YI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051478; c=relaxed/simple; bh=cbqJ8B8zoNb1wL5cvsafYdWHOXGpucToAPhTV87jaLA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=e2r/GgtJJBaIfirrdLX3cu1/bEj6t7cTN280+S0BF9UXpJapTMsAbacQ+JG45xT8af/bGNzN3GVPv49uE+R0GRkHLpGE3ItsAJj79FE1kBfL3k+2tcCgq5OjGE6ALefsuEAXN9iA8lJKjgiYhAqlT16kMTVwO9iB0uSlu89PBGg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=MEdYykU8; arc=fail smtp.client-ip=40.107.22.67 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="MEdYykU8" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=b5yGvUhL5HplsR/B24m9rABCvZz6VKFornOA6BdLk+e1wlADKUelRZWhshT8Adqx6ZwJLDkyoSBwGwKbKIZgDTGVpLWnjjQR5oIUUfv+8xtWMV9oBiEoOO+1fZBqWESle2B+sRku0LMM6UGl5ZCnVuoc8bH5ltAH/Sg59p8UNEW/SZqCSdcSrMOrutlfXqNQrsf4Gl01nh3JqqTmNftih4SRPoqd+00H45wDcERe1gJiCtrqh/+S3aFCZdnMxXJuaXnuIG+HjKuOBonWP2uUbYbMN0ikuh1STsnl/BiLYKV3rYhrRhXtIWhyDdfgG51LETr1CH3Ll8sr8xTyay4ADQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=NcAD7n5DFC8zY5SMsqG6DN1S/Q3hAt3IaNHuvXjxowM=; b=KyZPD+kfDper0xWvB6c5pipHpcQwWUlZPfwzMjhwYUc5GiW5hw65/ys9I670iDvbbQcmOIItmIYilySQNLT6QBpijuZw+fgN66hEJgg+uVzm/tEyT6Z55yjzBt+4Ib0RmpJh1vX6SU+coRegYiTULI0p8rX6iB0ka8rTRN8zIoz4U9T4mBLdG/IDyo7LuLKVRcjHI4OvaH/YvFguYYlNFMb9PgoPJBC0zcmX/OYibM549gluLaPSvfQFBnVAnJCPqAesIIOz9kVENC5TeIA2vuWFfziY7CvKk9Dc0FLqwakxo4Pd4qFnycR/jDVZXgEHpAT3uOxpx9u/ahdB6j9Hcw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=NcAD7n5DFC8zY5SMsqG6DN1S/Q3hAt3IaNHuvXjxowM=; b=MEdYykU8PLJCHCi+n4v1YlfD/Y0rYXwnWRSY/GpldwN6YF8rvFMUSXLJldrxL9EiUD+4lp2gAKxKjeHfJn99I54U5QlrZAQQSHaghQtv6nM/PWsjtLZyCg9y4tskN4zrsmok0TYZGoP996ETcE/49oUGxaN+SBXjlJCBEwpe0ek= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:12 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:12 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 3/8] Documentation: i3c: Add I3C target mode controller and function Date: Tue, 23 Jan 2024 18:10:38 -0500 Message-Id: <20240123231043.3891847-4-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: 6ac074e4-0621-42bd-b55e-08dc1c68975e X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 3c0XCX/U6ummA1DB5QXXdvMuB5xgSqvEAeu4ENdp+qBLz0BVXfYle/w6UOOJo+D4cY1oYUmFf3AxiSWziu2tLvj9bqf3zfXQSOAn1oSSIoOyPGigkpaY8rF0wCd9QvQurcRfuqLnswXDMMH4hLZhb9OPuD+Nb/7crRWgLBUHn3umFOLseO679BO77l2cawlrOHHvYEEwhmL8XxY8D9aJSR8NCBTf/iWu59Yk169IpWIkP1S5CBDoxMf/v9qFsm2UF82ds9pOxCzNsh4FJXhKSz/wb0a06DT4SmsXZDGlhoLABLviVgwhJpCqWZl3QMDPz+VzQTTXltpv2USMbsh5hYrWAIbwY0r0bOp4I9ftUd/zT9HzBnCR8Ph7K7Z2/jSk9YYN6hw8ioVBRkgo6PxAjSLXsUuRGJtRk1D6nP3/AX5nWs0Q01BXv4Pa+C6P2yV3mpZCE2hk7KxaHYAtWS4PjEkjH/DsaFQKECNBpHZvPoRQGOtFIvmB8t3L8S1oYVsDg//mM47tyGqdoCf06rb1ix0n0pZBvVAll3483l/3+wr9Vs9ugYx4fGWSJYm3fz0Koh/Q3Gc+6raS+G9aYmXI8xyXvHokfVdu7iDYxp8qCf6Yf4Ob9cWeLOSLVQgdHe5g X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(30864003)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: +7MJntf+2QKpxAPn2y/PfZS3lb1gjv3lN2118DXnbTQKstsCI9Z1CJnVo7DYrDEa0wmUMldu46g3vP4a87cvWVqLXCmUOYBbobDRPl+RzhqLkia1bNhH91K0ex217TN/xitvbBdkcrHUPVEhtK9ojeNQgHKRKUbHvqSfOfoq3SSKt/Kh0Ho+Sv3YvlD+GxojYbBBptRpvpe1Al6ZIM3CwCwOayr3939H1LX1YWlFbOAwfD4c17n7yDuYouauqwSNEA9yfjuTBD4mqNbolCEA6BfB6pizo24+EeVHWTMv4+e+QxEb0GZTYVUcnNSgmmXPT7jxZVHiVqxtYeu79nkaHC2wEqSki/W5Zbl5i+YoMJrITmuu6cjpBsTPZIMiugdzJsd2s7+NnxHQDYcAnZwdcqamhH33A1pGDzaoqypcGlqKL9E0GpIXaxt/9SXK4qHEuCiXumFO7c83sKGH7YzyomnoAQM4J8/C5Y98/vQLkfuOCsG+Z9/wwdro9jVoWaZt6wQlbZhjTYP7goxroj5t7Xp5ij2+qQyCpxfRbgMPZmEF6wrz0WCayo/oOZ66CGDuiCbXTn6BiLcOYe+a8aHEZGFY7Y3RDQrGRVRDUHEyRV41VCWlTHBsPbypQevnFpuP81i9C0etKgPuutoXlFcVL3SPheJTe3WhHUqBBhBDN8EAoYKEWZYjT3oCH78heDC/MXSIcnkWt1/oiNWJuQSOpJTeY/CqbAGaKUCicln3vhIq/BJUSiQbhci2Ajvu7r0b6jPpJG3TzZebJbZmGikDltT1MAsrieBwiqPKmFxa2Z9UWi4PRip58R+j15nJXzJdeDDEE582Ufw0gHYw63qdX9c6w973v5JJ0eYi03eZAZkkEwg7mJh91ot10pAQtugSA/QC1ycVTyOo5Lhpsqbj8B96uaUBY8r7yDnbVQEthZZBGIdTjS57fZFaH3PyJMrAl8xtLArc97d+ls/GoS4Q7jUebU8yU45CZr6wzo0OZMtXdBHikL6BhOEwwnycDExw98qKE0ryIFR6gXQcq2urYqT0N7IqWnOZlB2z/INZd+yJKJPR+Xxx2XPG+hZHumXYnpb+GbE908FAw96wEQZXd4Q8r0Ebw9RPuKOe0sDDJP3SrmFiN3Celkg86cIHuiqu0IxDDlGuSdluL4lceh/DbO5lLdg2zWh+ikxGyiTKRhGCH45A3jkXKITSC0mFfSa9mxgZ5oerbV9EFhvm+vGoGm1/U9PiyKp9LB5dv8ci4fcEOOVrHNVoNWf3148T17LPEV9DD6OMS5Xmp2YS7qIfzHJ/K+nwiRlJshBEwOtJX7runZSYfs5THBS3XnDpdC7rsCL367uMTKFkwiLMSbt2hTOv3TQGac7A5fWMos8vpgQeXAiGQdWXAQc8PIzkKo074pj95x8A5YQTtphO1vCfA64TjelFzXscMJr+AfOmt6MhkEbflRqyAGd2FdgwEQ2xtJ8dZBWqasHU2Ifp2b2HTwlhX3b01LjbYJwvsFygNMIMxEg7Fozkk71+9QCTDjV9d8kVJdMHpmWB+uQ6Vf9253pOEwl3VSdwRaVxbl3cNQc1nQA4m3OaTKgqvkanChSU X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6ac074e4-0621-42bd-b55e-08dc1c68975e X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:12.3976 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 9HU5XHq7dmptpV0dM4a6br3OeBxQ0SjWqKKHTgKWeEx4E8ChS3QFQ0E9M5z8q3hsPLPUhLWFT7Ak5rlQg4QJZg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 Add I3C target mode and tty over i3c func driver document. Signed-off-by: Frank Li --- Documentation/driver-api/i3c/index.rst | 1 + .../driver-api/i3c/target/i3c-target-cfs.rst | 109 ++++++++++ .../driver-api/i3c/target/i3c-target.rst | 189 ++++++++++++++++++ .../driver-api/i3c/target/i3c-tty-howto.rst | 109 ++++++++++ Documentation/driver-api/i3c/target/index.rst | 13 ++ 5 files changed, 421 insertions(+) create mode 100644 Documentation/driver-api/i3c/target/i3c-target-cfs.rst create mode 100644 Documentation/driver-api/i3c/target/i3c-target.rst create mode 100644 Documentation/driver-api/i3c/target/i3c-tty-howto.rst create mode 100644 Documentation/driver-api/i3c/target/index.rst diff --git a/Documentation/driver-api/i3c/index.rst b/Documentation/driver-api/i3c/index.rst index 783d6dad054b6..345a43c9f61b0 100644 --- a/Documentation/driver-api/i3c/index.rst +++ b/Documentation/driver-api/i3c/index.rst @@ -9,3 +9,4 @@ I3C subsystem protocol device-driver-api master-driver-api + target/index diff --git a/Documentation/driver-api/i3c/target/i3c-target-cfs.rst b/Documentation/driver-api/i3c/target/i3c-target-cfs.rst new file mode 100644 index 0000000000000..1fcf829dc4ae2 --- /dev/null +++ b/Documentation/driver-api/i3c/target/i3c-target-cfs.rst @@ -0,0 +1,109 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======================================= +Configuring I3C Target Using CONFIGFS +======================================= + +:Author: Frank Li + +The I3C Target Core exposes configfs entry (i3c_target) to configure the I3C +target function and to bind the target function with the target controller. +(For introducing other mechanisms to configure the I3C Target Function refer to +[1]). + +Mounting configfs +================= + +The I3C Target Core layer creates i3c_target directory in the mounted configfs +directory. configfs can be mounted using the following command:: + + mount -t configfs none /sys/kernel/config + +Directory Structure +=================== + +The i3c_target configfs has two directories at its root: controllers and +functions. Every Controller device present in the system will have an entry in +the *controllers* directory and every Function driver present in the system will +have an entry in the *functions* directory. +:: + + /sys/kernel/config/i3c_target/ + .. controllers/ + .. functions/ + +Creating Function Device +=================== + +Every registered Function driver will be listed in controllers directory. The +entries corresponding to Function driver will be created by the Function core. +:: + + /sys/kernel/config/i3c_target/functions/ + .. / + ... / + ... / + ... / + .. / + ... / + ... / + +In order to create a of the type probed by , +the user has to create a directory inside . + +Every directory consists of the following entries that can be +used to configure the standard configuration header of the target function. +(These entries are created by the framework when any new is +created) +:: + + .. / + ... / + ... vendor_id + ... part_id + ... bcr + ... dcr + ... ext_id + ... instance_id + ... max_read_len + ... max_write_len + ... vendor_info + +Controller Device +========== + +Every registered Controller device will be listed in controllers directory. The +entries corresponding to Controller device will be created by the Controller +core. +:: + + /sys/kernel/config/i3c_target/controllers/ + .. / + ... / + .. / + ... / + +The directory will have a list of symbolic links to +. These symbolic links should be created by the user to +represent the functions present in the target device. Only +that represents a physical function can be linked to a Controller device. + +:: + + | controllers/ + | / + | + | functions/ + | / + | / + | vendor_id + | part_id + | bcr + | dcr + | ext_id + | instance_id + | max_read_len + | max_write_len + | vendor_info + +[1] Documentation/I3C/target/pci-target.rst diff --git a/Documentation/driver-api/i3c/target/i3c-target.rst b/Documentation/driver-api/i3c/target/i3c-target.rst new file mode 100644 index 0000000000000..09ae26b1f311a --- /dev/null +++ b/Documentation/driver-api/i3c/target/i3c-target.rst @@ -0,0 +1,189 @@ +.. SPDX-License-Identifier: GPL-2.0 + +:Author: Frank Li + +This document is a guide to use the I3C Target Framework in order to create +target controller driver, target function driver, and using configfs interface +to bind the function driver to the controller driver. + +Introduction +============ + +Linux has a comprehensive I3C subsystem to support I3C controllers that +operates in master mode. The subsystem has capability to scan I3C bus,assign +i3c device address, load I3C driver (based on Manufacturer ID, part ID), +support other services like hot-join, In-Band Interrupt(IBI). + +However the I3C controller IP integrated in some SoCs is capable of operating +either in Master mode or Target mode. I3C Target Framework will add target mode +support in Linux. This will help to run Linux in an target system which can +have a wide variety of use cases from testing or validation, co-processor +accelerator, etc. + +I3C Target Core +================= + +The I3C Target Core layer comprises 3 components: the Target Controller +library, the Target Function library, and the configfs layer to bind the target +function with the target controller. + +I3C Target Controller Library +------------------------------------ + +The Controller library provides APIs to be used by the controller that can +operate in target mode. It also provides APIs to be used by function +driver/library in order to implement a particular target function. + +APIs for the I3C Target controller Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section lists the APIs that the I3C Target core provides to be used by the +I3C controller driver. + +* devm_i3c_target_ctrl_create()/i3c_target_ctrl_create() + + The I3C controller driver should implement the following ops: + + * set_config: ops to set i3c configuration + * enable: ops to enable controller + * disable: ops to disable controller + * raise_ibi: ops to raise IBI to master controller + * alloc_request: ops to alloc a transfer request + * free_request: ops to free a transfer request + * queue: ops to queue a request to transfer queue + * dequeue: ops to dequeue a request from transfer queue + * cancel_all_reqs: ops to cancel all request from transfer queue + * fifo_status: ops to get fifo status + * fifo_flush: ops to flush hardware fifo + * get_features: ops to get controller supported features + + The I3C controller driver can then create a new Controller device by + invoking devm_i3c_target_ctrl_create()/i3c_target_ctrl_create(). + +* devm_i3c_target_ctrl_destroy()/i3c_target_ctrl_destroy() + + The I3C controller driver can destroy the Controller device created by + either devm_i3c_target_ctrl_create() or i3c_target_ctrl_create() using + devm_i3c_target_ctrl_destroy() or i3c_target_ctrl_destroy(). + +I3C Target Controller APIs for the I3C Target Function Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section lists the APIs that the I3C Target core provides to be used by the +I3C target function driver. + +* i3c_target_ctrl_set_config() + + The I3C target function driver should use i3c_target_ctrl_set_config() to + write i3c configuration to the target controller. + +* i3c_target_ctrl_enable()/i3c_target_ctrl_disable() + + The I3C target function driver should use i3c_target_ctrl_enable()/ + i3c_target_ctrl_disable() to enable/disable i3c target controller. + +* i3c_target_ctrl_alloc_request()/i3c_target_ctrl_free_request() + + The I3C target function driver should usei3c_target_ctrl_alloc_request() / + i3c_target_ctrl_free_request() to alloc/free a i3c request. + +* i3c_target_ctrl_raise_ibi() + + The I3C target function driver should use i3c_target_ctrl_raise_ibi() to + raise IBI. + +* i3c_target_ctrl_queue()/i3c_target_ctrl_dequeue() + + The I3C target function driver should use i3c_target_ctrl_queue()/ + i3c_target_ctrl_dequeue(), to queue/dequeue I3C transfer to/from transfer + queue. + +* i3c_target_ctrl_get_features() + + The I3C target function driver should use i3c_target_ctrl_get_features() to + get I3C target controller supported features. + +Other I3C Target Controller APIs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are other APIs provided by the Controller library. These are used for +binding the I3C Target Function device with Controlller device. i3c-cfs.c can +be used as reference for using these APIs. + +* i3c_target_ctrl_get() + + Get a reference to the I3C target controller based on the device name of + the controller. + +* i3c_target_ctrl_put() + + Release the reference to the I3C target controller obtained using + i3c_target_ctrl_get() + +* i3c_target_ctrl_add_func() + + Add a I3C target function to a I3C target controller. + +* i3c_target_ctrl_remove_func() + + Remove the I3C target function from I3C target controller. + +I3C Target Function Library +---------------------------------- + +The I3C Target Function library provides APIs to be used by the function driver +and the Controller library to provide target mode functionality. + +I3C Target Function APIs for the I3C Target Function Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section lists the APIs that the I3C Target core provides to be used +by the I3C target function driver. + +* i3c_target_func_register_driver() + + The I3C Target Function driver should implement the following ops: + * bind: ops to perform when a Controller device has been bound to + Function device + * unbind: ops to perform when a binding has been lost between a + Controller device and Function device + + The I3C Function driver can then register the I3C Function driver by using + i3c_target_func_register_driver(). + +* i3c_target_func_unregister_driver() + + The I3C Function driver can unregister the I3C Function driver by using + i3c_epf_unregister_driver(). + +APIs for the I3C Target Controller Library +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This section lists the APIs that the I3C Target core provides to be used by the +I3C target controller library. + +Other I3C Target APIs +~~~~~~~~~~~~~~~~~~~~ + +There are other APIs provided by the Function library. These are used to notify +the function driver when the Function device is bound to the EPC device. +i3c-cfs.c can be used as reference for using these APIs. + +* i3c_target_func_create() + + Create a new I3C Function device by passing the name of the I3C EPF device. + This name will be used to bind the Function device to a Function driver. + +* i3c_target_func_destroy() + + Destroy the created I3C Function device. + +* i3c_target_func_bind() + + i3c_target_func_bind() should be invoked when the EPF device has been bound + to a Controller device. + +* i3c_target_func_unbind() + + i3c_target_func_unbind() should be invoked when the binding between EPC + device and function device is lost. diff --git a/Documentation/driver-api/i3c/target/i3c-tty-howto.rst b/Documentation/driver-api/i3c/target/i3c-tty-howto.rst new file mode 100644 index 0000000000000..43a129b18e938 --- /dev/null +++ b/Documentation/driver-api/i3c/target/i3c-tty-howto.rst @@ -0,0 +1,109 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================== +I3C TTY User Guide +=================== + +:Author: Frank Li + +This document is a guide to help users use i3c-target-tty function driver and +i3ctty master driver for testing I3C. The list of steps to be followed in the +master side and target side is given below. + +Endpoint Device +=============== + +Endpoint Controller Devices +--------------------------- + +To find the list of target controller devices in the system:: + + # ls /sys/class/i3c_target/ + 44330000.i3c-target + +If CONFIG_I3C_SLAVE_CONFIGFS is enabled:: + + # ls /sys/kernel/config/i3c_target/controllers/ + 44330000.i3c-target + + +Endpoint Function Drivers +------------------------- + +To find the list of target function drivers in the system:: + + # ls /sys/bus/i3c_target_func/drivers + tty + +If CONFIG_I3C_SLAVE_CONFIGFS is enabled:: + + # ls /sys/kernel/config/i3c_target/functions + tty + + +Creating i3c-target-tty Device +---------------------------- + +I3C target function device can be created using the configfs. To create +i3c-target-tty device, the following commands can be used:: + + # mount -t configfs none /sys/kernel/config + # cd /sys/kernel/config/i3c_target/ + # mkdir functions/tty/func1 + +The "mkdir func1" above creates the i3c-target-tty function device that will +be probed by i3c tty driver. + +The I3C target framework populates the directory with the following +configurable fields:: + + # ls functions/tty/func1 + bcr dcr ext_id instance_id max_read_len max_write_len + part_id vendor_id vendor_info + +The I3C target function driver populates these entries with default values when +the device is bound to the driver. The i3c-target-tty driver populates vendorid +with 0xffff and interrupt_pin with 0x0001:: + + # cat functions/tty/func1/vendor_id + 0x0 + +Configuring i3c-target-tty Device +------------------------------- + +The user can configure the i3c-target-tty device using configfs entry. In order +to change the vendorid, the following commands can be used:: + + # echo 0x011b > functions/tty/func1/vendor_id + # echo 0x1000 > functions/tty/func1/part_id + # echo 0x6 > functions/tty/t/bcr + +Binding i3c-target-tty Device to target Controller +------------------------------------------------ + +In order for the target function device to be useful, it has to be bound to a +I3C target controller driver. Use the configfs to bind the function device to +one of the controller driver present in the system:: + + # ln -s functions/tty/func1 controllers/44330000.i3c-target/ + +I3C Master Device +================ + +Check I3C tty device is probed + + # ls /sys/bus/i3c/devices/0-23610000000 + 0-23610000000:0 bcr dcr driver dynamic_address hdrcap + modalias pid power subsystem tty uevent + +Using Target TTY function Device +----------------------------------- + +Host side: + cat /dev/ttyI3C0 +Target side + echo abc >/dev/ttyI3C0 + +You will see "abc" show at console. + +You can use other tty tool to test I3C target tty device. diff --git a/Documentation/driver-api/i3c/target/index.rst b/Documentation/driver-api/i3c/target/index.rst new file mode 100644 index 0000000000000..56eabfae83aa4 --- /dev/null +++ b/Documentation/driver-api/i3c/target/index.rst @@ -0,0 +1,13 @@ +.. SPDX-License-Identifier: GPL-2.0 + +====================== +I3C Target Framework +====================== + +.. toctree:: + :maxdepth: 2 + + i3c-target + i3c-target-cfs + i3c-tty-howto + From patchwork Tue Jan 23 23:10:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765760 Received: from EUR05-AM6-obe.outbound.protection.outlook.com (mail-am6eur05on2067.outbound.protection.outlook.com [40.107.22.67]) (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 EC8EE55E57; Tue, 23 Jan 2024 23:11:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.22.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051481; cv=fail; b=qUruv1Vanbhrhd+a2H1vzi/ZtXMK8C4lywT2YaKCr6ekWo2hlgzjLxIWcIHjgkqg97EQB/2UXhRDwSBPl/ofpKydN9UGDL1gEzH5YastpUGyRxESDyevsQ5yfc3z2V+d89VSybPZnWA8Q4ryrTR2bonNy837rQAD7z2v1y/FCiU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051481; c=relaxed/simple; bh=CD5kjo9+4Dx/aNyWiQdbwnyptasEeCwpH/xSHn2yLWM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=DvUU5V+pLgShWW/ugYwSgJ18Kl3iCqTUprsSDVrkTcAYPBl9UwNNgxNrTRHGDsFxrCl4m92Bbw3YI2gYSHWhdK4x2xqaYiz3uUWEXbG1xGz1hfgnFaOfD2Zf7i3UEVleWZb9ZK8e1RgEtkq+qc9pan0eVZfNrPhggz2TmfZ2sac= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=OGfAuDTF; arc=fail smtp.client-ip=40.107.22.67 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="OGfAuDTF" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=dXxEN3SROqdxBDzPNpUegTjI6CdXdBheZuI9i+FYhbdizQbn/cUA2ph3Jcs/NIn5t/u2NOFDwrlK/FVUhhOQYSR6P65jdoGFPVNozhSy6uk/JX6uDDnky/q7SrVJ8s5F0eQHAbTIwqhEmYaJZHaIOLGdvC8nXAhDVw7jZrZU2NgAlITMJMYWpxIfzJk0jpntwa7shBZnV1yrWUYfhe3rtGkPN886CdFAgaodUv1wztaPerMR0ZYiluoaK/zqmQ/1XoeoevkIUFdIWjNS3x78eDCmI66zyydew6+HiLUMNaEJQQsULR+qXl36aX4V9Xjhqhmj/sw1rGd1MGK2oKvaHQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=i9UN7ujkdLSFL/UqlRYdVA1+ucq1lYc5jQjhqBg1C2g=; b=h6Rc6wAR+kzaZgAkiU3oYh2Z9ngKPDEf6dYTX4vyeWmy7ug+r3rD+TyIZaMZUbQwqNg5kR1pKMa8oNYNWCmeeInP1jdY3ApDORCGczIOK84N+NittxIEMLcJtNtClZZolHiC+MdtwGFbdYevgawq32ZTlBpBuwtsZfBQ5FMobbKwsWxR7EhpUumjt+/VpcoUY1ZLQt5OrhF6+yKNkEwB674cwXpeGmGgzmVC6Tt83RXY+MbYg7CD4EM3FzHH0UxdY0eXpsN+3T3nis+YzbPuwuHlMXzN49RJJtxoOvaQKAE1w4y0I5zpazlLJgScv5T3kLw2XLveJnWf7Sqj9Dk7Nw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=i9UN7ujkdLSFL/UqlRYdVA1+ucq1lYc5jQjhqBg1C2g=; b=OGfAuDTFF4zb4SivLSRPiEch5EmlHnd1pIePPB0sJPjQ1zhHpZzX1qDltRKA2wlzCqFayOHsPsirtRbh7/Ocifv4vSWMMx1Tkzz1FczLo6k5ZEzjdYPtlCXdiqqpTJtfLlFen9EJzJ1C8rdtss22N7dA3o+FfDWYySjztbPFTnM= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:16 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:16 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 4/8] i3c: svc: Add svc-i3c-main.c and svc-i3c.h Date: Tue, 23 Jan 2024 18:10:39 -0500 Message-Id: <20240123231043.3891847-5-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: 6171de60-6edd-4235-6059-08dc1c6899b9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: KEC8KBoV8pb9qz0paEdMr7k5/l7qUDhBM3eLXV8asSrq8m6dlxwlVDKhc/CsjvZaQVXu9jRP1c/X1la+sBGJfyohbM2RDNlG5mcGF5q2tSGItWvYIb6RAnPol3N2/RFjOJ252aH8PspHGpWV6tUi7EOtaCysJAikxoq4+E3Bili9DX6GooMawZh6OELCYeBl3yYOqeq+zMP0rNCJDTe2xN0XjPbueQBNADmZl2D4LbR7rtd+NdbA+EVxypaqYUwNh/7xA5FZw2VOVngNuC5mU95sm1x8uSh14pXg+NkmLeXTAg7VxhgO86pphJ5BKtOeM5qJyuDuNVsjlkSlnJElIq++snZIhvfMPSJ9QE+V2v+L/GJjXlKgs7yigo/bYulXUYKHLmGwktuQZK0dSeOkxo2xHPZlVWsifx7a1Mslf+AMwO7mv8a/H21uUynh5EzkLy6+vUQSfvBgOyl7+jPtEDbT1NJAxpjjyed2E/aYXlbLrztCjVf/EK5MXq2LYkpCkYytLA9nCDyW+TlRAfMCzOZUYS8csdxHewwNkV9ef2W4eP+i2MFUOXXyQx3VaJU6Fw55aB32ByMCgp7zATeCh1nZOxHISh346+vClGk5qCp87R2L3MjwR4tp0U0Td1Hw X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: RK0gNy4NOu0Dk4N7nZbiCxcF6qBe0oiKFexgxziQIhGa7R8Z/CiLQWKZb0DcvHIQMo6Q7rxJKo/QbugnjJsHPsuPthwvY1BrP1d8xwyve4sBeWHRCQMzsCH92P0ykjzdBTXqkDtcHsWAtuIN6Nv9FGCruNFXtB5lTjN2IgnAFuWSQRg1GxawMtchGEtNPsVusegjPd6LsGFbz7HlvbaxUeNMmHmqJUBzTQNIKhf4/yWhIySR8NTkVjof1wWzPXe5QGj06ajqTdEsegJRNtpQ6k5yKOPVHZB1NakSUWJU8bBW0vSF9clfPS5D89ZrSi5hNgfNoDGwts0Jxt3+/F25XciQA9nEvUiWZD2DwtR5LbHV/yY3IMrvIzSTMuijujoREFeJqFLlOO0QtBMp5qw0qs1ALhGd1VuUkhcJ5N2N3JfbPxzbb1oNUA9hRGU2mRGM/p13UIFaDmHhxRFf3+N4b5ZSchkd5YI4IQo9DgJd0Km8ugmmyMIQvvSlR+CZp0zLZowxPEyo/FlYjOg2A+XfYszehgh4nKWpWtfq757Chpj79gjZRrip+P9bZj4Y+2iv1Fk9rTRqWrHk76WYM1nx8qP7E2wZgZH5C6Mv9VTdgGiLG6H4Swt1mywr9rIGHCeh10KzLSuyKSSrnwRtgD6rvtzyqkmA62s9uwrLmqfPBW933IAA3eKggzje7Por1HIzwSPFZDqhtkTlrMmLAeWLpaSbNXXmQBmfPLj1i4oyzF/wuSi2TwKqhYgzbeb/E8TRApZYlJzbG18w/Yt5NNFk/wNRVAe2GnXK323UTQe1ixwK7bF7+6lCwAXJSToyVOnD7JwRpx+UR6FInwCQSls0IRAYu77FEnf9mPlRNs80awNcaq+cTCXlMsBTT/xsxu/RCeEDHNCURtmjWtKb4k82bkS12eNDHmBNiA02KaS47kjg+t0EhZ4eZN7cM0JhiEia9fUZB1D3MifBNs4bGrOMyTH5c+Gfe6+gYtmC+zdAyucO4LcNCSaxPFQof/aFTPxb6E/MPAHnFsAuArNTWqHWoljrdb3/G/zj1VlGAKM4n+qLSPt3JXFIY/iAbwUA3Y+wuFgKnvDHpanEXXDiMJWZ0HNfzcn8nIxptS+gyGYElw7VZQTjn6sz3nRaN9CijyxltFzMeBtJu6taR3oMGdhTmKc14UcDm52JMfu2cg6dzsZ6SwDpxdRzQI9MciifNMGFbdTNo3Mn5YC63jtPTAW6GohgYFEpkp1quk+TgAfrZfrFkB40p19wVpTa4LfnFKPRNgwX3xxMdnGktgatlp7JIbb8Vi+6afBT8642ro6Uafv5aLuvd6J8F1b5liI+T4sFpv0y+K6JbOfebn8I9msaqNO23sXSjKaqxPJfDC9ScrpYUjQltXBH0Uk7NssR49b/oD9dAiD8d/Ryk1oDgQWX07HEvJLuR/UzSGsbc2n39Cwcw5w39FkICDbJIrelDujUI8R3d7JYASW03mpGGdXb6xZVTpkAPHcW9oGAoO+r6pvOZPH9Xxb6L2LPechdf0xTWuptN3bYvmoG9C5k6AjiCxyuACrvNh5ZJffiG2ndhrBsixXouoDWN7hkvkjRV2Ln X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6171de60-6edd-4235-6059-08dc1c6899b9 X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:16.2231 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 9y9kIW4xJxFgmWfKRBYwDesJmfLR9Lu65SZmdHr1IU5yVKwsfqEwUzoCAA3fsU7UDrxeafjFsEDp4lwlTWZZXw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 SVC i3c is a dual role controller. Move probe() into svc-i3c-main.c. This prepares to support target probe depending on dts "mode" settings. Signed-off-by: Frank Li --- drivers/i3c/master/Makefile | 3 +- drivers/i3c/master/svc-i3c-main.c | 52 +++++++++++++++++++++++++++++ drivers/i3c/master/svc-i3c-master.c | 34 ++++--------------- drivers/i3c/master/svc-i3c.h | 11 ++++++ 4 files changed, 71 insertions(+), 29 deletions(-) create mode 100644 drivers/i3c/master/svc-i3c-main.c create mode 100644 drivers/i3c/master/svc-i3c.h diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile index 3e97960160bc8..484cb81f45821 100644 --- a/drivers/i3c/master/Makefile +++ b/drivers/i3c/master/Makefile @@ -2,5 +2,6 @@ obj-$(CONFIG_CDNS_I3C_MASTER) += i3c-master-cdns.o obj-$(CONFIG_DW_I3C_MASTER) += dw-i3c-master.o obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o -obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c-master.o +svc-i3c-objs += svc-i3c-main.o svc-i3c-master.o +obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c.o obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/ diff --git a/drivers/i3c/master/svc-i3c-main.c b/drivers/i3c/master/svc-i3c-main.c new file mode 100644 index 0000000000000..053b2bd9d8317 --- /dev/null +++ b/drivers/i3c/master/svc-i3c-main.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +#include "svc-i3c.h" + +static int svc_i3c_probe(struct platform_device *pdev) +{ + return svc_i3c_master_probe(pdev); +} + +static void svc_i3c_remove(struct platform_device *pdev) +{ + svc_i3c_master_remove(pdev); +} + +static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev) +{ + return svc_i3c_master_runtime_suspend(dev); +} + +static int __maybe_unused svc_i3c_runtime_resume(struct device *dev) +{ + return svc_i3c_master_runtime_resume(dev); +} + +static const struct dev_pm_ops svc_i3c_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(svc_i3c_runtime_suspend, + svc_i3c_runtime_resume, NULL) +}; + +static const struct of_device_id svc_i3c_master_of_match_tbl[] = { + { .compatible = "silvaco,i3c-master-v1"}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, svc_i3c_master_of_match_tbl); + +static struct platform_driver svc_i3c_master = { + .probe = svc_i3c_probe, + .remove_new = svc_i3c_remove, + .driver = { + .name = "silvaco-i3c-master", + .of_match_table = svc_i3c_master_of_match_tbl, + .pm = &svc_i3c_pm_ops, + }, +}; +module_platform_driver(svc_i3c_master); \ No newline at end of file diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index 5ee4db68988e2..4dfe85ab17fd2 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -21,6 +21,8 @@ #include #include +#include "svc-i3c.h" + /* Master Mode Registers */ #define SVC_I3C_MCONFIG 0x000 #define SVC_I3C_MCONFIG_MASTER_EN BIT(0) @@ -1613,7 +1615,7 @@ static void svc_i3c_master_unprepare_clks(struct svc_i3c_master *master) clk_disable_unprepare(master->sclk); } -static int svc_i3c_master_probe(struct platform_device *pdev) +int svc_i3c_master_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct svc_i3c_master *master; @@ -1706,7 +1708,7 @@ static int svc_i3c_master_probe(struct platform_device *pdev) return ret; } -static void svc_i3c_master_remove(struct platform_device *pdev) +void svc_i3c_master_remove(struct platform_device *pdev) { struct svc_i3c_master *master = platform_get_drvdata(pdev); @@ -1733,7 +1735,7 @@ static void svc_i3c_restore_regs(struct svc_i3c_master *master) } } -static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev) +int svc_i3c_master_runtime_suspend(struct device *dev) { struct svc_i3c_master *master = dev_get_drvdata(dev); @@ -1744,7 +1746,7 @@ static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused svc_i3c_runtime_resume(struct device *dev) +int svc_i3c_master_runtime_resume(struct device *dev) { struct svc_i3c_master *master = dev_get_drvdata(dev); @@ -1756,30 +1758,6 @@ static int __maybe_unused svc_i3c_runtime_resume(struct device *dev) return 0; } -static const struct dev_pm_ops svc_i3c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(svc_i3c_runtime_suspend, - svc_i3c_runtime_resume, NULL) -}; - -static const struct of_device_id svc_i3c_master_of_match_tbl[] = { - { .compatible = "silvaco,i3c-master-v1"}, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, svc_i3c_master_of_match_tbl); - -static struct platform_driver svc_i3c_master = { - .probe = svc_i3c_master_probe, - .remove_new = svc_i3c_master_remove, - .driver = { - .name = "silvaco-i3c-master", - .of_match_table = svc_i3c_master_of_match_tbl, - .pm = &svc_i3c_pm_ops, - }, -}; -module_platform_driver(svc_i3c_master); - MODULE_AUTHOR("Conor Culhane "); MODULE_AUTHOR("Miquel Raynal "); MODULE_DESCRIPTION("Silvaco dual-role I3C master driver"); diff --git a/drivers/i3c/master/svc-i3c.h b/drivers/i3c/master/svc-i3c.h new file mode 100644 index 0000000000000..0bd1f0112a071 --- /dev/null +++ b/drivers/i3c/master/svc-i3c.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef SVC_I3C_H +#define SVC_I3C_H + +int svc_i3c_master_probe(struct platform_device *pdev); +void svc_i3c_master_remove(struct platform_device *pdev); +int svc_i3c_master_runtime_suspend(struct device *dev); +int svc_i3c_master_runtime_resume(struct device *dev); + +#endif \ No newline at end of file From patchwork Tue Jan 23 23:10:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765327 Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05on2084.outbound.protection.outlook.com [40.107.21.84]) (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 76BD155C21; Tue, 23 Jan 2024 23:11:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.21.84 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051486; cv=fail; b=Jd+ihO7/nEDbFpC1GCfB6gSPCwKQAfhuDkE01s/gx8vkMG3RQbwu2qYRVm6d/dXcVifAQEqYcGNnE2vTbD2GkOfwHheaQ3gvRFan0newcGNlXd8AnMRqtquqmKUVaG/khGff6XuLWyIptNbmjFg35SgfMDCw/87c420wOG7Brco= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051486; c=relaxed/simple; bh=aFPOfC8o6TVPkgK9tJDSz3OHkxkHBGqRxh2jknv+gHs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=txnhHyr3kG/ccmlAoqT/vZb9TMRVUE95NnRrcrNw954KPRcdU5ZGyMEmR9fTmDGieLxPVtmwZCFRayb/crnejIXhGmRJ1EjKhGri58mvpYmocmgJv3FyTtcaBnBk47hdGOuqbNoGrOpHRxjReXWSVFvt0tbvUtdsnqHZHn5wNdI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=BVWniPr2; arc=fail smtp.client-ip=40.107.21.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="BVWniPr2" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ePTGC7DJI/Pul4BDfqMeZsMRYu+ue2Px0yk9rcUJOyRm8l95DJCVgsK+qAbdoEJCSW8RKo4k2N+WDRgQJF38D92tf8sxWi91JMNsYgpRNDGW5sljwban5o1fglPNs/EFhfSnIVno2yL5nMMq6bt6Huzg27JeZQVRoxKpnddEu06VDp6XjdP5LDRERAKWvQa/23Vda7hRXh26eP5NHYnKMCLp3V6/Bj++tHKSilRBrxj8Duoe0s62bHyj+4PdDNe9eBHSFBN0CTqqRlQHOrGPvPzPRu0anmai5yqcmxA7fCvOdGlsRQGy+zwOOj7/luE8IFnUR1y7LLNQheMLKbT8BA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Jv63bzvfpmi9X4WF+c0Nny0z07mV+I5l+14mQv4nxik=; b=Mi4AlJZDwrJjPiQtLzasNmj/0ZYbqndCtjcTdu1KwS0EoL9iww3GYvwk5xhs3YNPiM+3aztx8D82zwlPNUG/dpPz4QoriAo7TjEf5xucuOIj1q3bCbzkDx3wuaHevdXbvZn2rVYPacg4g97HuTA6CACq82Bn4brG7rvzRa0TKRHuFNIwaRVGz7RGhPvRqyvYqi64V5NxYZx68/Qx5GEUjpEc4PmAHNIrn61OU9VqKWXfQF9zI4woVu6GUtvw/BvU0vBbc3uMOnFG3528+fVMNzo+9Oq+q7Z6iyYNguK1OuVOgrXw2z3cNPGADuD5xCGEq4Da2edIxrWg6HRskytqDg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Jv63bzvfpmi9X4WF+c0Nny0z07mV+I5l+14mQv4nxik=; b=BVWniPr2ZSxKGJtjky4zmmm64vkzkPlnClMRo7onIPjMoc9j2u15OkApVkTfmfFhI+vb18DtvhdBuUd9hf1CWMcwKNMScQ7ligAv4KV18XLzjoZ9v/bETKaRqNjm6+e7NuAQxqg6hSw+L0pOi32jU0WXF2uKLcl6pxbqq5n3AiI= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:20 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:20 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 5/8] i3c: target: add svc target controller support Date: Tue, 23 Jan 2024 18:10:40 -0500 Message-Id: <20240123231043.3891847-6-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: de96b0d0-35f1-4fe9-1e97-08dc1c689bfd X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 9Vu4TH+U6x8qFekwClHr9mD+FL6sHmRuaCu2McjZ0UVrZbe+fU/zLD4kTWkfr7//mX0/DkrAZW9pi7o+/TIKkCI53zxcw1l41bulAlGKC8Nxul5Umfy6vfB05VSztfp9lOsK2losMuFg5foVX4dUtD4jkoovV2u6St54D++aC/2sx5Ee+cWuRh8Eh/Q3/2DBJCrIk3rcnhRSiwGX7SodAj9nol5fWxcdMiOS8Hpr4r5vPO5HLFMBxv6F0fd3Pb9VFiB3bLDQ5rrT6uVb5dUpWfz7p9ofKNMq2MspzMvPFkJ6Ztp54VRzNKlIErfqpDcy2t/5CJwOUoO9b97YzRWc0qg670IBIwQ9/picsfHhksgVhPfKoWoZROT/sSomoX102tFg/KuYV2hirJRnvjjHZdI82y6YOISYnLQDntNJ9ly15pXisg2N1PzTn+NEB38FmVJb+KTgES40awgZ5mji2QI4ay4yT3WXrZiN3LNCYqmurSmBt1XYIiCoJT3L2GW4aFFg3qL0TBwgw0g4R8qHgeEdV7YnE4mac3cfqO2mQhV4ZOn1rRw4MO9A6QbJGX3AuG03GyDsqIj5O3XyWhXwWAHVvEi/wBUS0dg0wqKbo+A9SUqE3wLuvRlkG5Y1J6U+1cUi3Dd9pV1RWa9begfroyA8dP2RMfniJEUm+Tu7okU= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230273577357003)(230173577357003)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(30864003)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: RSieNdyjvqq2BEpfEVvAKjv93Lk9K+pReIu66Om/g2uYqs/Gr/6JHiCg+oHp5ZFAo5GP2Fe8HxCYnsLOGbUG6xX8ItsN8hnfhazQZ6akY5mFsAherjbZNDtP0O6kNQqZPp1wgxvdDTTfTBuLBSiMT1GjBOE2Cgmc9E3GvcHGZieK8lM7kXdQT7RaKckZi9H1GfKGc/WVN4cNz8XAPTbX58O/qTrcq0BdiQgf/pHmhWDnzXpVxrAAc8Qj6oRPFxMVNmfWpz9L+KcDzbE6vPLdf7VAr4THFeHIA0cLC3onhs8r3j1EnuIM5PJAd2/P8OXjOQ0x4K4fVuTiVZdjhsfGNGaDi71yLNxZxUGy2mY44nu/gjGX2YpVaFTeRraTlPZXyrTHP4Z4urRtxYDQ1BcTkXW2hQOJIlPBHobd7NrP8Vio0BjzqewMYwq+BS/fB8asCeFPQ6MaFPWftXSjbrye9iPmFF/jZTkEj2+lf37UKKaIMSsGLaB/WrUTovUoLBWIm5RzHsJgtJsxMACV6GZvBKFYwiSuNrPSBv+lW3j35i+SanrXCHwrQpasBqnvt28X85vmGRYNzFYtm1WU0C9ScGaTi6qoUoDELMYTvb+H/0I+L+irPIrz+y7nB3MIPZwtyuxsf4phgjwBQimKg/QcxHeVAg8WM9kVTuqTTcytCAqRC1tEbn23igvhVJcDGXYhOuHbvcYl4P/qlabSLPQh8mNccl9t+bvcbnAJNiKpB1zQv+iYQHhTg9B1H4P99NR7ttpmLxhTE7JPCUb2L866huJ+7dCjag8bdO4n9gGz2YgQCAhCPxN4/1BdSt/1dO9PzqtoNgw07//2fZosn0nol52afvpj0gj9Nn8Z7yK7/kdHpuezuQua5OxstQ3njnAZDzwc91Pe4CZiR8BCyH9IhDVsHKHPC9w2cYa9vNzIj21uPHEW/n+96+AvODyH1n6/4/u2LgOPqnMYptc0E/5tERY8vuePRHoI9xM81j2sAmZpgLfdQHC78sP1Sn9jca2JQPm5dbhIrOyflX/ZEBHo1WH42GTEwqh0bjTLe0ZBV7ekHo8paMaRiH/KUv4fmOQBFsK8lrL9m2hL3iYWIpX9yv3tg1jJqzEqNKG+ikUddhDk2OQ15KE1rsPIDr271dpjaZmHjbDTFFzDzGXlBE0n/Fz5hBinA7jvv8dOIFXHF96zmVOc+W1j1gWH56jztJRRjY1qgoV2AGUPHS9G0u7p8ezXm4nxtD26sNKuwPQ/ntVg+23voKlBTK7PDwjFBz+P1pv+4GgTz5meLDGiM6cwUle/NnmjwKOw5xOosjtRh0zXwg9UxaS9ehvSLAcm8x0CVel0L/n0vM+euLSNQVRKdxZZhjT+dF03qTdtal0tfSB1mRckS3EdmBFzTZOgAtJrFcgbNB/UgWkI66PvILF7pdeF0ChCLN3K5vJRwzt/I+/+3G7Y38zAqPQUqN2JPjgA+VoExNnhDU5CBzP3YC1YLSJfzLz9GIkN4jWUpOEdMXW2LMCZ6tERli/WCnH+ztwfZ6mExicpBqz3bhmdtEg3jpZOBf774m6/8wPDWiYDRQctTfpnvN0kQysDmtcfUAiO X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: de96b0d0-35f1-4fe9-1e97-08dc1c689bfd X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:20.1782 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: ocAii78Ii4+Qa6ohvKb2ABAbll9Xrmjy0vqtVEuRIw1ki2Ud5htpNBGU7p2i1r/alCU9gLpzUfP6DeFJhJ6JGQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 Add Silvaco I3C target controller support Signed-off-by: Frank Li --- Notes: Change from v2 to v3 - fix build warning drivers/i3c/master/Makefile | 2 +- drivers/i3c/master/svc-i3c-main.c | 37 +- drivers/i3c/master/svc-i3c-target.c | 776 ++++++++++++++++++++++++++++ drivers/i3c/master/svc-i3c.h | 3 + 4 files changed, 812 insertions(+), 6 deletions(-) create mode 100644 drivers/i3c/master/svc-i3c-target.c diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile index 484cb81f45821..b9ed6c9e7be13 100644 --- a/drivers/i3c/master/Makefile +++ b/drivers/i3c/master/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_CDNS_I3C_MASTER) += i3c-master-cdns.o obj-$(CONFIG_DW_I3C_MASTER) += dw-i3c-master.o obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o -svc-i3c-objs += svc-i3c-main.o svc-i3c-master.o +svc-i3c-objs += svc-i3c-main.o svc-i3c-master.o svc-i3c-target.o obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c.o obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/ diff --git a/drivers/i3c/master/svc-i3c-main.c b/drivers/i3c/master/svc-i3c-main.c index 053b2bd9d8317..34d9f1e64b1c0 100644 --- a/drivers/i3c/master/svc-i3c-main.c +++ b/drivers/i3c/master/svc-i3c-main.c @@ -7,24 +7,51 @@ #include "svc-i3c.h" +static bool svc_i3c_is_master(struct device *dev) +{ + const char *mode = NULL; + + device_property_read_string(dev, "mode", &mode); + + if (!mode) + return true; + + if (strncmp(mode, "target", 6) == 0) + return false; + + return true; +} + static int svc_i3c_probe(struct platform_device *pdev) { - return svc_i3c_master_probe(pdev); + if (svc_i3c_is_master(&pdev->dev)) + return svc_i3c_master_probe(pdev); + + return svc_i3c_target_probe(pdev); } static void svc_i3c_remove(struct platform_device *pdev) { - svc_i3c_master_remove(pdev); + if (svc_i3c_is_master(&pdev->dev)) + return svc_i3c_master_remove(pdev); + + svc_i3c_target_remove(pdev); } static int __maybe_unused svc_i3c_runtime_suspend(struct device *dev) { - return svc_i3c_master_runtime_suspend(dev); + if (svc_i3c_is_master(dev)) + return svc_i3c_master_runtime_suspend(dev); + + return -EINVAL; } static int __maybe_unused svc_i3c_runtime_resume(struct device *dev) { - return svc_i3c_master_runtime_resume(dev); + if (svc_i3c_is_master(dev)) + return svc_i3c_master_runtime_resume(dev); + + return -EINVAL; } static const struct dev_pm_ops svc_i3c_pm_ops = { @@ -49,4 +76,4 @@ static struct platform_driver svc_i3c_master = { .pm = &svc_i3c_pm_ops, }, }; -module_platform_driver(svc_i3c_master); \ No newline at end of file +module_platform_driver(svc_i3c_master); diff --git a/drivers/i3c/master/svc-i3c-target.c b/drivers/i3c/master/svc-i3c-target.c new file mode 100644 index 0000000000000..094efb60cb404 --- /dev/null +++ b/drivers/i3c/master/svc-i3c-target.c @@ -0,0 +1,776 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2023 NXP. + * + * Author: Frank Li + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svc-i3c.h" + +enum i3c_clks { + PCLK, + FCLK, + SCLK, + MAXCLK, +}; + +struct svc_i3c_target { + struct device *dev; + void __iomem *regs; + int irq; + struct clk_bulk_data clks[MAXCLK]; + + struct list_head txq; + spinlock_t txq_lock; /* protect tx queue */ + struct list_head rxq; + spinlock_t rxq_lock; /* protect rx queue */ + struct list_head cq; + spinlock_t cq_lock; /* protect complete queue */ + + struct work_struct work; + struct workqueue_struct *workqueue; + + struct completion dacomplete; + struct i3c_target_ctrl_features features; + + spinlock_t ctrl_lock; /* protext access SCTRL register */ +}; + +#define I3C_SCONFIG 0x4 +#define I3C_SCONFIG_SLVENA_MASK BIT(0) +#define I3C_SCONFIG_OFFLINE_MASK BIT(9) +#define I3C_SCONFIG_SADDR_MASK GENMASK(31, 25) + +#define I3C_SSTATUS 0x8 +#define I3C_SSTATUS_STNOTSTOP_MASK BIT(0) +#define I3C_SSTATUS_STOP_MASK BIT(10) +#define I3C_SSTATUS_RX_PEND_MASK BIT(11) +#define I3C_SSTATUS_TXNOTFULL_MASK BIT(12) +#define I3C_SSTATUS_DACHG_MASK BIT(13) +#define I3C_SSTATUS_EVDET_MASK GENMASK(21, 20) +#define I3C_SSTATUS_EVDET_ACKED 0x3 +#define I3C_SSTATUS_IBIDIS_MASK BIT(24) +#define I3C_SSTATUS_HJDIS_MASK BIT(27) + +#define I3C_SCTRL 0xc +#define I3C_SCTRL_EVENT_MASK GENMASK(1, 0) +#define I3C_SCTRL_EVENT_IBI 0x1 +#define I3C_SCTRL_EVENT_HOTJOIN 0x3 +#define I3C_SCTRL_EXTDATA_MASK BIT(3) +#define I3C_SCTRL_IBIDATA_MASK GENMASK(15, 8) + +#define I3C_SINTSET 0x10 +#define I3C_SINTCLR 0x14 +#define I3C_SINT_START BIT(8) +#define I3C_SINT_MATCHED BIT(9) +#define I3C_SINT_STOP BIT(10) +#define I3C_SINT_RXPEND BIT(11) +#define I3C_SINT_TXSEND BIT(12) +#define I3C_SINT_DACHG BIT(13) +#define I3C_SINT_CCC BIT(14) +#define I3C_SINT_ERRWARN BIT(15) +#define I3C_SINT_DDRMAATCHED BIT(16) +#define I3C_SINT_CHANDLED BIT(17) +#define I3C_SINT_EVENT BIT(18) +#define I3C_SINT_SLVRST BIT(19) + +#define I3C_SDATACTRL 0x2c +#define I3C_SDATACTRL_RXEMPTY_MASK BIT(31) +#define I3C_SDATACTRL_TXFULL_MASK BIT(30) +#define I3C_SDATACTRL_RXCOUNT_MASK GENMASK(28, 24) +#define I3C_SDATACTRL_TXCOUNT_MASK GENMASK(20, 16) +#define I3C_SDATACTRL_FLUSHFB_MASK BIT(1) +#define I3C_SDATACTRL_FLUSHTB_MASK BIT(0) + +#define I3C_SWDATAB 0x30 +#define I3C_SWDATAB_END_ALSO_MASK BIT(16) +#define I3C_SWDATAB_END_MASK BIT(8) + +#define I3C_SWDATAE 0x34 +#define I3C_SRDATAB 0x40 + +#define I3C_SCAPABILITIES 0x60 +#define I3C_SCAPABILITIES_FIFOTX_MASK GENMASK(27, 26) +#define I3C_SCAPABILITIES_FIFORX_MASK GENMASK(29, 28) + +#define I3C_SMAXLIMITS 0x68 +#define I3C_SMAXLIMITS_MAXRD_MASK GENMASK(11, 0) +#define I3C_SMAXLIMITS_MAXWR_MASK GENMASK(27, 16) + +#define I3C_SIDPARTNO 0x6c + +#define I3C_SIDEXT 0x70 +#define I3C_SIDEXT_BCR_MASK GENMASK(23, 16) +#define I3C_SIDEXT_DCR_MASK GENMASK(15, 8) +#define I3C_SVENDORID 0x74 + +#define I3C_SMAPCTRL0 0x11c +#define I3C_SMAPCTRL0_ENA_MASK BIT(0) +#define I3C_SMAPCTRL0_DA_MASK GENMASK(7, 1) + +#define I3C_IBIEXT1 0x140 +#define I3C_IBIEXT1_CNT_MASK GEN_MASK(2, 0) +#define I3C_IBIEXT1_MAX_MASK GEN_MASK(4, 6) +#define I3C_IBIEXT1_EXT1_SHIFT 8 +#define I3C_IBIEXT1_EXT2_SHIFT 16 +#define I3C_IBIEXT1_EXT3_SHIFT 24 + +#define I3C_IBIEXT2 0x144 +#define I3C_IBIEXT2_EXT4_SHIFT 0 +#define I3C_IBIEXT2_EXT5_SHIFT 8 +#define I3C_IBIEXT2_EXT6_SHIFT 16 +#define I3C_IBIEXT2_EXT7_SHIFT 24 + +static int svc_i3c_target_enable(struct i3c_target_ctrl *ctrl) +{ + struct svc_i3c_target *svc; + u32 val; + + svc = dev_get_drvdata(&ctrl->dev); + + val = readl_relaxed(svc->regs + I3C_SCONFIG); + val |= I3C_SCONFIG_SLVENA_MASK; + writel_relaxed(val, svc->regs + I3C_SCONFIG); + + return 0; +} + +static int svc_i3c_target_disable(struct i3c_target_ctrl *ctrl) +{ + struct svc_i3c_target *svc; + u32 val; + + svc = dev_get_drvdata(&ctrl->dev); + + val = readl_relaxed(svc->regs + I3C_SCONFIG); + val &= ~I3C_SCONFIG_SLVENA_MASK; + writel_relaxed(val, svc->regs + I3C_SCONFIG); + + return 0; +} + +static int svc_i3c_target_set_config(struct i3c_target_ctrl *ctrl, struct i3c_target_func *func) +{ + struct svc_i3c_target *svc; + u32 val; + u32 wm, rm; + + svc = dev_get_drvdata(&ctrl->dev); + + if (func->static_addr > 0x7F) + return -EINVAL; + + val = readl_relaxed(svc->regs + I3C_SCONFIG); + val &= ~I3C_SCONFIG_SLVENA_MASK; + val |= FIELD_PREP(I3C_SCONFIG_SADDR_MASK, func->static_addr); + writel_relaxed(val, svc->regs + I3C_SCONFIG); + + if (func->part_id) + writel_relaxed((func->part_id << 16) | + ((func->instance_id << 12) & GENMASK(15, 12)) | + (func->ext_id & GENMASK(11, 0)), svc->regs + I3C_SIDPARTNO); + + writel_relaxed(FIELD_PREP(I3C_SIDEXT_BCR_MASK, func->bcr) | + FIELD_PREP(I3C_SIDEXT_DCR_MASK, func->dcr), + svc->regs + I3C_SIDEXT); + + wm = func->max_write_len == 0 ? + FIELD_GET(I3C_SMAXLIMITS_MAXWR_MASK, I3C_SMAXLIMITS_MAXWR_MASK) : func->max_write_len; + + wm = max_t(u32, val, 8); + + rm = func->max_read_len == 0 ? + FIELD_GET(I3C_SMAXLIMITS_MAXRD_MASK, I3C_SMAXLIMITS_MAXRD_MASK) : func->max_read_len; + rm = max_t(u32, val, 16); + + val = FIELD_PREP(I3C_SMAXLIMITS_MAXRD_MASK, rm) | FIELD_PREP(I3C_SMAXLIMITS_MAXWR_MASK, wm); + writel_relaxed(val, svc->regs + I3C_SMAXLIMITS); + + writel_relaxed(func->vendor_id, svc->regs + I3C_SVENDORID); + return 0; +} + +static const struct i3c_target_ctrl_features *svc_i3c_get_features(struct i3c_target_ctrl *ctrl) +{ + struct svc_i3c_target *svc; + + svc = dev_get_drvdata(&ctrl->dev); + + if (!svc) + return NULL; + + return &svc->features; +} + +static void svc_i3c_queue_complete(struct svc_i3c_target *svc, struct i3c_request *complete) +{ + unsigned long flags; + + spin_lock_irqsave(&svc->cq_lock, flags); + list_add_tail(&complete->list, &svc->cq); + spin_unlock_irqrestore(&svc->cq_lock, flags); + queue_work(svc->workqueue, &svc->work); +} + +static void svc_i3c_fill_txfifo(struct svc_i3c_target *svc) +{ + struct i3c_request *req, *complete = NULL; + unsigned long flags; + int val; + + spin_lock_irqsave(&svc->txq_lock, flags); + while ((!!(req = list_first_entry_or_null(&svc->txq, struct i3c_request, list))) && + !((readl_relaxed(svc->regs + I3C_SDATACTRL) & I3C_SDATACTRL_TXFULL_MASK))) { + while (!(readl_relaxed(svc->regs + I3C_SDATACTRL) + & I3C_SDATACTRL_TXFULL_MASK)) { + val = *(u8 *)(req->buf + req->actual); + + if (req->actual + 1 == req->length) + writel_relaxed(val, svc->regs + I3C_SWDATAE); + else + writel_relaxed(val, svc->regs + I3C_SWDATAB); + + req->actual++; + + if (req->actual == req->length) { + list_del(&req->list); + complete = req; + spin_unlock_irqrestore(&svc->txq_lock, flags); + + svc_i3c_queue_complete(svc, complete); + return; + + spin_lock_irqsave(&svc->txq_lock, flags); + break; + } + } + } + spin_unlock_irqrestore(&svc->txq_lock, flags); +} + +static int svc_i3c_target_queue(struct i3c_request *req, gfp_t gfp) +{ + struct svc_i3c_target *svc; + struct list_head *q; + unsigned long flags; + spinlock_t *lk; + + svc = dev_get_drvdata(&req->ctrl->dev); + if (!svc) + return -EINVAL; + + if (req->tx) { + q = &svc->txq; + lk = &svc->txq_lock; + } else { + q = &svc->rxq; + lk = &svc->rxq_lock; + } + + spin_lock_irqsave(lk, flags); + list_add_tail(&req->list, q); + spin_unlock_irqrestore(lk, flags); + + if (req->tx) + svc_i3c_fill_txfifo(svc); + + if (req->tx) + writel_relaxed(I3C_SINT_TXSEND, svc->regs + I3C_SINTSET); + else + writel_relaxed(I3C_SINT_RXPEND, svc->regs + I3C_SINTSET); + + return 0; +} + +static int svc_i3c_dequeue(struct i3c_request *req) +{ + struct svc_i3c_target *svc; + unsigned long flags; + spinlock_t *lk; + + svc = dev_get_drvdata(&req->ctrl->dev); + if (!svc) + return -EINVAL; + + if (req->tx) + lk = &svc->txq_lock; + else + lk = &svc->rxq_lock; + + spin_lock_irqsave(lk, flags); + list_del(&req->list); + spin_unlock_irqrestore(lk, flags); + + return 0; +} + +static void svc_i3c_target_fifo_flush(struct i3c_target_ctrl *ctrl, bool tx) +{ + struct svc_i3c_target *svc; + u32 val; + + svc = dev_get_drvdata(&ctrl->dev); + + val = readl_relaxed(svc->regs + I3C_SDATACTRL); + + val |= tx ? I3C_SDATACTRL_FLUSHTB_MASK : I3C_SDATACTRL_FLUSHFB_MASK; + + writel_relaxed(val, svc->regs + I3C_SDATACTRL); +} + +static int +svc_i3c_target_raise_ibi(struct i3c_target_ctrl *ctrl, void *p, u8 size) +{ + struct svc_i3c_target *svc; + unsigned long flags; + u8 *ibidata = p; + u32 ext1 = 0, ext2 = 0; + u32 val; + int ret; + + svc = dev_get_drvdata(&ctrl->dev); + + if (size && !p) + return -EINVAL; + + if (size > 8) + return -EINVAL; + + val = readl_relaxed(svc->regs + I3C_SSTATUS); + if (val & I3C_SSTATUS_IBIDIS_MASK) + return -EINVAL; + + ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val, + !(val & I3C_SCTRL_EVENT_MASK), 0, 10000); + if (ret) { + dev_err(&ctrl->dev, "Timeout when polling for NO event pending"); + val &= ~I3C_SCTRL_EVENT_MASK; + writel_relaxed(val, svc->regs + I3C_SCTRL); + return -ENAVAIL; + } + + spin_lock_irqsave(&svc->ctrl_lock, flags); + + val = readl_relaxed(svc->regs + I3C_SCTRL); + + val &= ~I3C_SCTRL_EVENT_MASK | I3C_SCTRL_IBIDATA_MASK; + val |= FIELD_PREP(I3C_SCTRL_EVENT_MASK, I3C_SCTRL_EVENT_IBI); + + if (size) { + val |= FIELD_PREP(I3C_SCTRL_IBIDATA_MASK, *ibidata); + ibidata++; + + if (size > 1) + val |= I3C_SCTRL_EXTDATA_MASK; + + size--; + if (size > 0) { + ext1 |= (size + 2); + ext1 |= (*ibidata++) << I3C_IBIEXT1_EXT1_SHIFT; + size--; + } + + if (size > 0) { + ext1 |= (*ibidata++) << I3C_IBIEXT1_EXT2_SHIFT; + size--; + } + + if (size > 0) { + ext1 |= (*ibidata++) << I3C_IBIEXT1_EXT3_SHIFT; + size--; + } + + writel_relaxed(ext1, svc->regs + I3C_IBIEXT1); + + if (size > 0) { + ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT4_SHIFT; + size--; + } + + if (size > 0) { + ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT5_SHIFT; + size--; + } + + if (size > 0) { + ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT6_SHIFT; + size--; + } + + if (size > 0) { + ext2 |= (*ibidata++) << I3C_IBIEXT2_EXT7_SHIFT; + size--; + } + + writeb_relaxed(ext2, svc->regs + I3C_IBIEXT2); + } + + /* Issue IBI*/ + writel_relaxed(val, svc->regs + I3C_SCTRL); + spin_unlock_irqrestore(&svc->ctrl_lock, flags); + + ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val, + !(val & I3C_SCTRL_EVENT_MASK), 0, 1000000); + if (ret) { + dev_err(&ctrl->dev, "Timeout when polling for IBI finish\n"); + + //clear event to above hang bus + spin_lock_irqsave(&svc->ctrl_lock, flags); + val = readl_relaxed(svc->regs + I3C_SCTRL); + val &= ~I3C_SCTRL_EVENT_MASK; + writel_relaxed(val, svc->regs + I3C_SCTRL); + spin_unlock_irqrestore(&svc->ctrl_lock, flags); + + return -ENAVAIL; + } + + return 0; +} + +static void svc_i3c_target_complete(struct work_struct *work) +{ + struct svc_i3c_target *svc = container_of(work, struct svc_i3c_target, work); + struct i3c_request *req; + unsigned long flags; + + spin_lock_irqsave(&svc->cq_lock, flags); + while (!list_empty(&svc->cq)) { + req = list_first_entry(&svc->cq, struct i3c_request, list); + list_del(&req->list); + spin_unlock_irqrestore(&svc->cq_lock, flags); + req->complete(req); + + spin_lock_irqsave(&svc->cq_lock, flags); + } + spin_unlock_irqrestore(&svc->cq_lock, flags); +} + +static irqreturn_t svc_i3c_target_irq_handler(int irq, void *dev_id) +{ + struct i3c_request *req, *complete = NULL; + struct svc_i3c_target *svc = dev_id; + unsigned long flags; + u32 statusFlags; + + statusFlags = readl(svc->regs + I3C_SSTATUS); + writel(statusFlags, svc->regs + I3C_SSTATUS); + + if (statusFlags & I3C_SSTATUS_DACHG_MASK) + complete_all(&svc->dacomplete); + + if (statusFlags & I3C_SSTATUS_RX_PEND_MASK) { + spin_lock_irqsave(&svc->rxq_lock, flags); + req = list_first_entry_or_null(&svc->rxq, struct i3c_request, list); + + if (!req) { + writel_relaxed(I3C_SINT_RXPEND, svc->regs + I3C_SINTCLR); + } else { + while (!(readl_relaxed(svc->regs + I3C_SDATACTRL) & + I3C_SDATACTRL_RXEMPTY_MASK)) { + *(u8 *)(req->buf + req->actual) = + readl_relaxed(svc->regs + I3C_SRDATAB); + req->actual++; + + if (req->actual == req->length) { + complete = req; + list_del(&req->list); + break; + } + } + + if (req->actual != req->length && (statusFlags & I3C_SSTATUS_STOP_MASK)) { + complete = req; + list_del(&req->list); + } + } + spin_unlock_irqrestore(&svc->rxq_lock, flags); + + if (complete) { + spin_lock_irqsave(&svc->cq_lock, flags); + list_add_tail(&complete->list, &svc->cq); + spin_unlock_irqrestore(&svc->cq_lock, flags); + queue_work(svc->workqueue, &svc->work); + complete = NULL; + } + } + + if (statusFlags & I3C_SSTATUS_TXNOTFULL_MASK) { + svc_i3c_fill_txfifo(svc); + spin_lock_irqsave(&svc->txq_lock, flags); + if (list_empty(&svc->txq)) + writel_relaxed(I3C_SINT_TXSEND, svc->regs + I3C_SINTCLR); + spin_unlock_irqrestore(&svc->txq_lock, flags); + } + + return IRQ_HANDLED; +} + +static void svc_i3c_cancel_all_reqs(struct i3c_target_ctrl *ctrl, bool tx) +{ + struct svc_i3c_target *svc; + struct i3c_request *req; + struct list_head *q; + unsigned long flags; + spinlock_t *lk; + + svc = dev_get_drvdata(&ctrl->dev); + if (!svc) + return; + + if (tx) { + q = &svc->txq; + lk = &svc->txq_lock; + } else { + q = &svc->rxq; + lk = &svc->rxq_lock; + } + + spin_lock_irqsave(lk, flags); + while (!list_empty(q)) { + req = list_first_entry(q, struct i3c_request, list); + list_del(&req->list); + spin_unlock_irqrestore(lk, flags); + + req->status = I3C_REQUEST_CANCEL; + req->complete(req); + spin_lock_irqsave(lk, flags); + } + spin_unlock_irqrestore(lk, flags); +} + +static int svc_i3c_hotjoin(struct i3c_target_ctrl *ctrl) +{ + struct svc_i3c_target *svc; + int ret; + u32 val; + u32 cfg; + + svc = dev_get_drvdata(&ctrl->dev); + if (!svc) + return -EINVAL; + + reinit_completion(&svc->dacomplete); + + val = readl_relaxed(svc->regs + I3C_SSTATUS); + if (val & I3C_SSTATUS_HJDIS_MASK) { + dev_err(&ctrl->dev, "Hotjoin disabled by i3c master\n"); + return -EINVAL; + } + + ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val, + !(val & I3C_SCTRL_EVENT_MASK), 0, 10000); + if (ret) { + dev_err(&ctrl->dev, "Timeout when polling for none event pending"); + return -ENAVAIL; + } + + cfg = readl_relaxed(svc->regs + I3C_SCONFIG); + cfg |= I3C_SCONFIG_OFFLINE_MASK; + writel_relaxed(cfg, svc->regs + I3C_SCONFIG); + + val &= ~(I3C_SCTRL_EVENT_MASK | I3C_SCTRL_IBIDATA_MASK); + val |= FIELD_PREP(I3C_SCTRL_EVENT_MASK, I3C_SCTRL_EVENT_HOTJOIN); + /* Issue hotjoin*/ + writel_relaxed(val, svc->regs + I3C_SCTRL); + + ret = readl_relaxed_poll_timeout(svc->regs + I3C_SCTRL, val, + !(val & I3C_SCTRL_EVENT_MASK), 0, 100000); + if (ret) { + val &= ~FIELD_PREP(I3C_SCTRL_EVENT_MASK, I3C_SCTRL_EVENT_MASK); + writel_relaxed(val, svc->regs + I3C_SCTRL); + dev_err(&ctrl->dev, "Timeout when polling for HOTJOIN finish\n"); + return -EINVAL; + } + + val = readl_relaxed(svc->regs + I3C_SSTATUS); + val = FIELD_GET(I3C_SSTATUS_EVDET_MASK, val); + if (val != I3C_SSTATUS_EVDET_ACKED) { + dev_err(&ctrl->dev, "Master NACKED hotjoin request\n"); + return -EINVAL; + } + + writel_relaxed(I3C_SINT_DACHG, svc->regs + I3C_SINTSET); + ret = wait_for_completion_timeout(&svc->dacomplete, msecs_to_jiffies(100)); + writel_relaxed(I3C_SINT_DACHG, svc->regs + I3C_SINTCLR); + if (!ret) { + dev_err(&ctrl->dev, "wait for da assignment timeout\n"); + return -EIO; + } + + val = readl_relaxed(svc->regs + I3C_SMAPCTRL0); + val = FIELD_GET(I3C_SMAPCTRL0_DA_MASK, val); + dev_info(&ctrl->dev, "Get dynamtic address 0x%x\n", val); + return 0; +} + +static int svc_i3c_set_status_format1(struct i3c_target_ctrl *ctrl, u16 status) +{ + struct svc_i3c_target *svc; + unsigned long flags; + u32 val; + + svc = dev_get_drvdata(&ctrl->dev); + + spin_lock_irqsave(&svc->ctrl_lock, flags); + val = readl_relaxed(svc->regs + I3C_SCTRL); + val &= 0xFFFF; + val |= status << 16; + writel_relaxed(val, svc->regs + I3C_SCTRL); + spin_unlock_irqrestore(&svc->ctrl_lock, flags); + + return 0; +} + +static u16 svc_i3c_get_status_format1(struct i3c_target_ctrl *ctrl) +{ + struct svc_i3c_target *svc; + + svc = dev_get_drvdata(&ctrl->dev); + + return readl_relaxed(svc->regs + I3C_SCTRL) >> 16; +} + +static u8 svc_i3c_get_addr(struct i3c_target_ctrl *ctrl) +{ + struct svc_i3c_target *svc; + int val; + + svc = dev_get_drvdata(&ctrl->dev); + + val = readl_relaxed(svc->regs + I3C_SMAPCTRL0); + + if (val & I3C_SMAPCTRL0_ENA_MASK) + return FIELD_GET(I3C_SMAPCTRL0_DA_MASK, val); + + return 0; +} + +static int svc_i3c_fifo_status(struct i3c_target_ctrl *ctrl, bool tx) +{ + struct svc_i3c_target *svc; + int val; + + svc = dev_get_drvdata(&ctrl->dev); + + val = readl_relaxed(svc->regs + I3C_SDATACTRL); + + if (tx) + return FIELD_GET(I3C_SDATACTRL_TXCOUNT_MASK, val); + else + return FIELD_GET(I3C_SDATACTRL_RXCOUNT_MASK, val); +} + +static struct i3c_target_ctrl_ops svc_i3c_target_ops = { + .set_config = svc_i3c_target_set_config, + .enable = svc_i3c_target_enable, + .disable = svc_i3c_target_disable, + .queue = svc_i3c_target_queue, + .dequeue = svc_i3c_dequeue, + .raise_ibi = svc_i3c_target_raise_ibi, + .fifo_flush = svc_i3c_target_fifo_flush, + .cancel_all_reqs = svc_i3c_cancel_all_reqs, + .get_features = svc_i3c_get_features, + .hotjoin = svc_i3c_hotjoin, + .fifo_status = svc_i3c_fifo_status, + .set_status_format1 = svc_i3c_set_status_format1, + .get_status_format1 = svc_i3c_get_status_format1, + .get_addr = svc_i3c_get_addr, +}; + +int svc_i3c_target_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct i3c_target_ctrl *target; + struct svc_i3c_target *svc; + int ret; + u32 val; + + svc = devm_kzalloc(dev, sizeof(*svc), GFP_KERNEL); + if (!svc) + return -ENOMEM; + + svc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(svc->regs)) + return PTR_ERR(svc->regs); + + svc->clks[PCLK].id = "pclk"; + svc->clks[FCLK].id = "fast_clk"; + svc->clks[SCLK].id = "slow_clk"; + + ret = devm_clk_bulk_get(dev, MAXCLK, svc->clks); + if (ret < 0) { + dev_err(dev, "fail get clks: %d\n", ret); + return ret; + } + + ret = clk_bulk_prepare_enable(MAXCLK, svc->clks); + if (ret < 0) { + dev_err(dev, "fail enable clks: %d\n", ret); + return ret; + } + + svc->irq = platform_get_irq(pdev, 0); + if (svc->irq < 0) + return svc->irq; + + INIT_LIST_HEAD(&svc->txq); + INIT_LIST_HEAD(&svc->rxq); + INIT_LIST_HEAD(&svc->cq); + spin_lock_init(&svc->txq_lock); + spin_lock_init(&svc->rxq_lock); + spin_lock_init(&svc->cq_lock); + spin_lock_init(&svc->ctrl_lock); + + init_completion(&svc->dacomplete); + + INIT_WORK(&svc->work, svc_i3c_target_complete); + svc->workqueue = alloc_workqueue("%s-cq", 0, 0, dev_name(dev)); + if (!svc->workqueue) + return -ENOMEM; + + /* Disable all IRQ */ + writel_relaxed(0xFFFFFFFF, svc->regs + I3C_SINTCLR); + + val = readl_relaxed(svc->regs + I3C_SCAPABILITIES); + svc->features.tx_fifo_sz = FIELD_GET(I3C_SCAPABILITIES_FIFOTX_MASK, val); + svc->features.tx_fifo_sz = 2 << svc->features.tx_fifo_sz; + + svc->features.rx_fifo_sz = FIELD_GET(I3C_SCAPABILITIES_FIFORX_MASK, val); + svc->features.rx_fifo_sz = 2 << svc->features.rx_fifo_sz; + + ret = devm_request_irq(dev, svc->irq, svc_i3c_target_irq_handler, 0, "svc-i3c-irq", svc); + if (ret) + return -ENOENT; + + target = devm_i3c_target_ctrl_create(dev, &svc_i3c_target_ops); + if (!target) + return -ENOMEM; + + dev_set_drvdata(&target->dev, svc); + + return 0; +} + +void svc_i3c_target_remove(struct platform_device *pdev) +{ +} diff --git a/drivers/i3c/master/svc-i3c.h b/drivers/i3c/master/svc-i3c.h index 0bd1f0112a071..634837f146b2e 100644 --- a/drivers/i3c/master/svc-i3c.h +++ b/drivers/i3c/master/svc-i3c.h @@ -8,4 +8,7 @@ void svc_i3c_master_remove(struct platform_device *pdev); int svc_i3c_master_runtime_suspend(struct device *dev); int svc_i3c_master_runtime_resume(struct device *dev); +int svc_i3c_target_probe(struct platform_device *pdev); +void svc_i3c_target_remove(struct platform_device *pdev); + #endif \ No newline at end of file From patchwork Tue Jan 23 23:10:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765759 Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05on2084.outbound.protection.outlook.com [40.107.21.84]) (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 770645B1F5; Tue, 23 Jan 2024 23:11:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.21.84 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051488; cv=fail; b=UpJiuMPnM1ejAAGfiXvI19DihMaZXU6p3+meZb0geDRlmucwaRzkHVnH1AkMOngzgEUkweZ8dmmrr4BSZxoYfdzSMdmBAcm6xwEPKRf46HQieAefr5oYKlvvjwFdyIPXoaHAulUTihmKMDgTrT4oaIBdNyOFNIZUPXv22MpFmC4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051488; c=relaxed/simple; bh=23Zrugn41ufadFybEsxMIRXjfH4sZn99V7/xL4FkvrU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=QR/VDTvuxU++l1QyZv8CV+7L8T+Iz+H/ims5anXnrN+RXvjc5ikss44/vlVVX/Mz1Hv+1MZ6NWWUnR/K1Wgg6+kbcQZCUqviw1WsLoBgU1Bh5elOKqUCy7Hyh9z7hKqeP+gQYJFCoPLs104pzMtsL9RlsV1KJ3dk37dII7NItgI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=kn54h7qB; arc=fail smtp.client-ip=40.107.21.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="kn54h7qB" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=GvKQv3W+mKZc+LCG7Fa2D7OvbyFtzSmS39yqzaDJ7rCS/L6pAIVeYukVTsVrfSvBAT1sjczAcp0G4C5vVXd5b6dXnTqCacwyY7Mj+TpW6ZmS6aT+6c2V1hYkFUwCORp7HyTq9rmNHj5IyeXbSujJ4n6xmcVAxKyPhzJPOMtskI4dCC8J3i6DudCuSWRAn5swGtjBA7QY2UfP1if9Mw4htyxPosri9o6yRlkuaqxS/90+v204YxhutBcic24uYLUGG4VbfyzNvz9+DTcBeNfOUfi/2W3uh/f0sKZUrBPTjAQ8yL03u9V/BIltgP5z/DlIYnF2e2piMO4FpDMvdqQ0hg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=elXeixqm9OIPId/PL+W1dlakQnATLdA4uJRwdF4nyGo=; b=A+CCq8dC4C8I7n0jJL4adJcuJ+hs1rdjG1Xa/3HQXuFZJ8XT0o3aUzsHjz/VbSeP8C52nLy5GwTohXrszzVQwy6FrJL5wD0uuJZv6S6KciP9Hw5VOOGMHKNwq0mINLVXLPduWBqG/YWfScG2aJu8M2aDcKzet9mNkeXkCkvaM+o+agQk3LK3qq5Cd3KRfOFwAJsQ+36Whq0efUuwspE9ET6oL8YYMBuey6h7KAtdqes9MVGmZ4tz2SAN4DIdsRymVq7/Isdb5jhENHs+sbP9EjoJ5wZkgR8Zj2nSy5oyOilIC7/JDbN5eFe9AoTD2sFt6CNxyYO1/FZ85bN5oFic/A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=elXeixqm9OIPId/PL+W1dlakQnATLdA4uJRwdF4nyGo=; b=kn54h7qBkgL/06hw7lX9QSbP6SFvf8FUUQr2G1ESCy3NXHDBKkVljpsTx8ZV1W6UyuYMLQ3REeg3LOLfounbcRwU+qBptwupjF1rz9UOYCD+9JQ3epqRODDFP42f7dcfmHbKLLl7+bC5itztxvyPhXygxw7SQu1FREqc/xAw8a8= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:24 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:24 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 6/8] i3c: target: func: add tty driver Date: Tue, 23 Jan 2024 18:10:41 -0500 Message-Id: <20240123231043.3891847-7-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: 50a431b9-2f00-4374-1574-08dc1c689e5d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: LyxIHKdIyjl3gUUEE1JqHbGwMjsNPdEGmcxgQL5FLrudj3/Xxn2CM39uCkLRvK2D8LmBWzx0v0R+/Iw2kRZd3mF3YXH72lnzNdze5eRV111dh1h0q5stbqB1b6Ce98ffoTr1q6vnwA+7fQ0vdqld3qysI9FQ/FauSGkmrYLb6wKi643E3PLh2nVsRfIbmqdB8z5hAgJgGipi5K7fQXiNosiZfCIaHpcJ6dHyNfbiKmKCVy251l63dfrqPeKQ75Y23VVu3/jC5yQJoZOO2NyBf0rInIk9po8q7h+0yznwt0J0XFoU5e5/TKl7uDBLpQeqEGNTzrQKNKnkiV4Fm7LfZhbaKnnINQ11VSandpBxGqFBXW7MYpcKT7YvxDOeQsW2ZpJ6LgYis0oWq7gyycUeKldUA/W0zai68F8PpapKRtXCQ3ZurlmeY4OBQgQkUJfQJSVSeacy6oCEbx+4iwtFoQ/6rmOwhBvum8VX5hvjVGKso+S6+aCT4Y1ahp6xq1sAZwp8piDOaWzQonLivoXhiMK91GA3meZPeZv3sQVpgk8ovhJ4hP651XqX6GlvmiDNeULsTX/IRYMVicbvloH/4giNKoceg477vKarXyt8JDdeAT2/3mub3kU9t1OF94nG X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(30864003)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 9/vEF8zrihrwL6yIcR7UC6a3vUfpduTNZzAQetk6pFIO7PT20QrOq+KTsNBCIG/m5TVsyZfS/Tf3w7fAj/dm6CIu7Eeczpyo7YAnYujcS9vsvCNtXwY8efE76OPu1lY2+Vt6LxtutKn7jLpdS9Yfh74ZR5EPyGs+yIyCTYwnHnAb2r2GG/8V587/3hqz1+6JxP0D2MjOtrlnkpHW2t9x+Acms2ZG8ZCWqq/Ho/p3JmGHSQHCZIZUxcoK22m7V5q7bCFIK87GFzj9hZ0iiq2OiWuVIyD3bCFsfVycdfITagC5G/ISRcYShIlRANReeGxDAohlNpEAidiTbiakN0YG4eOUrJgXAjvBPmYxnnN1nZjRLqUjHv8hLQfY/xo+4ympwoggIFJUlN93xpFiKZHAcu5nejBEEcHUzAG8ni+dUhFrsCfaApwDF2yFvIM8WpV50JUoyfsVL4Y/Y2y1gzqrsSvKGPkLgZU50/n1Grlq3EUDlhajNjakicMGbHBaxugyZg9FrjOiCmDmQufWH57gSXXmFRBNX9F3tXX5HZ16p+J6q/yDvdBNwYHkFDI2oAFNsrl5RRtyr3hBoYQBpZpP5CEjrjPh8hbN2fvNKdgpdrdzHg/TfGcQZg4Qa46DOt+u++w/FGHawQHkOOYIFVeLPGO5Yb7ALfXgDxbMXdkx0ywpMlKDoBR9a6sSXP0+zRrE8rIhh0EDQyQK7+Z9D3SjnxgM/mkQZdURV70EX2HV9WEcVwdLrPmP+Bd6j8UIceAAJ3DzCUci++KF8VMLn4X+e2sKIh2szy9uTipnU8pS6Ax84hnj3NtVxrebVzIn5dqe0Aq+0lQcC656qw6//7cltiCBXePI0DgJk2TKMjSEsPQP6Tngyb5JqbCjoc7FxqaXbhWddzjyWcS16umshSaDD3lQvt2UPVeM8PbU5jBFi5Ib0neyQ7hp1AiiejinlFSZJtTTb02DMH0L9sv55cdFbwvCv7QhrjznbPjc7k0ouCk4BqLc+dGHCLi8YHdB1pX3AF5Yc1aTag5iTzTGZGWHXd7nDaRK0vpYJPcU9iY0Wg2+Eg9LzpUmrWDsyWfmDRlrR50pXHxVgUSmfwuIMBLji+4TS7oSTRaQAwa+QTlJ+JDrhotAh6UrJH0KzDM2C7639B2otCAXX+QgXovHT927zTjn57WtyH75CgYPLNCUj9EDfcwTSpgKnhxv1emswcuC12oi6bZ22JYdiyYYNMAYmveZgL6nqhFpq3Gpl0LAeAPqmzXzEZJS1nC9xhVKTkF8+Noq8pKO/kDeqSEplTzqCBTSanq3g1L2Bh783ALpLQOwp2EHajFMUp1iFjh+jaZDOr1jT52U8VfgFWzqH71WKCTbXE8Nsr6nOFhtcCtA2uj0O7fuR7y+RM6dUyEAG7SVdk0TIe59UcuHapnx4DvVuSVz/ODm3ZzgUW35PULzulDuDyssXZy+GnSL5mky0bmtv7l4DqLg+lifM0KWcqlAPGIcpaG3c4YiNOw40i8XrGos5pBVpMe9K5S9Ja6AfSdSssjQQwyD4dFcOOllJVkvHOxVWGgZ/n1OTj8SfOy4oUOTRUE4ssdTvVWb8c3luRbn X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 50a431b9-2f00-4374-1574-08dc1c689e5d X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:24.0241 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: q39h5xzwwj0kS/eYNt36FJHguFGyJqWejgn/DepoDRcX83yH34JQA7AOqD7aLI2Ic9RjcBe4LuWt+IQ9vaLdVg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 Add tty over I3C target function driver. Signed-off-by: Frank Li --- drivers/i3c/Kconfig | 3 + drivers/i3c/Makefile | 1 + drivers/i3c/func/Kconfig | 9 + drivers/i3c/func/Makefile | 3 + drivers/i3c/func/tty.c | 475 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 491 insertions(+) create mode 100644 drivers/i3c/func/Kconfig create mode 100644 drivers/i3c/func/Makefile create mode 100644 drivers/i3c/func/tty.c diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig index d59a7eb83d13a..fca808cda87b3 100644 --- a/drivers/i3c/Kconfig +++ b/drivers/i3c/Kconfig @@ -48,3 +48,6 @@ config I3C_TARGET_CONFIGFS the target function and used to bind the function with a target controller. +if I3C_TARGET +source "drivers/i3c/func/Kconfig" +endif # I3C_TARGET diff --git a/drivers/i3c/Makefile b/drivers/i3c/Makefile index c275aeae8970c..11f026d6876fe 100644 --- a/drivers/i3c/Makefile +++ b/drivers/i3c/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_I3C) += i3c.o obj-$(CONFIG_I3C_TARGET) += target.o obj-$(CONFIG_I3C_TARGET_CONFIGFS) += i3c-cfs.o obj-$(CONFIG_I3C) += master/ +obj-$(CONFIG_I3C_TARGET) += func/ diff --git a/drivers/i3c/func/Kconfig b/drivers/i3c/func/Kconfig new file mode 100644 index 0000000000000..7115129eb7d5a --- /dev/null +++ b/drivers/i3c/func/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +config I3C_TARGET_FUNC_TTY + tristate "I3C target tty driver" + depends on I3C_TARGET + help + I3C Target TTY Function Driver. + + General TTY over I3C target controller function drivers. diff --git a/drivers/i3c/func/Makefile b/drivers/i3c/func/Makefile new file mode 100644 index 0000000000000..16b3b9301496b --- /dev/null +++ b/drivers/i3c/func/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_I3C_TARGET_FUNC_TTY) += tty.o diff --git a/drivers/i3c/func/tty.c b/drivers/i3c/func/tty.c new file mode 100644 index 0000000000000..bad99c08be0ac --- /dev/null +++ b/drivers/i3c/func/tty.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 NXP + * Author: Frank Li + */ + +#include +#include +#include +#include +#include + +static DEFINE_IDR(i3c_tty_minors); + +static struct tty_driver *i3c_tty_driver; + +#define I3C_TTY_MINORS 8 + +#define I3C_TX_NOEMPTY BIT(0) +#define I3C_TTY_TRANS_SIZE 16 +#define I3C_TTY_IBI_TX BIT(0) + +struct ttyi3c_port { + struct tty_port port; + int minor; + struct i3c_target_func *i3cdev; + struct completion txcomplete; + spinlock_t xlock; + void *buffer; + struct work_struct work; + u16 status; + struct i3c_request *req; +}; + +static void i3c_target_tty_rx_complete(struct i3c_request *req) +{ + struct ttyi3c_port *port = req->context; + + if (req->status == I3C_REQUEST_CANCEL) { + i3c_target_ctrl_free_request(req); + return; + } + + tty_insert_flip_string(&port->port, req->buf, req->actual); + tty_flip_buffer_push(&port->port); + + req->actual = 0; + req->status = 0; + i3c_target_ctrl_queue(req, GFP_KERNEL); +} + +static void i3c_target_tty_tx_complete(struct i3c_request *req) +{ + struct ttyi3c_port *sport = req->context; + unsigned long flags; + + if (req->status == I3C_REQUEST_CANCEL) { + i3c_target_ctrl_free_request(req); + return; + } + + spin_lock_irqsave(&sport->xlock, flags); + kfifo_dma_out_finish(&sport->port.xmit_fifo, req->actual); + sport->req = NULL; + + if (kfifo_is_empty(&sport->port.xmit_fifo)) + complete(&sport->txcomplete); + else + queue_work(system_unbound_wq, &sport->work); + + if (kfifo_len(&sport->port.xmit_fifo) < WAKEUP_CHARS) + tty_port_tty_wakeup(&sport->port); + spin_unlock_irqrestore(&sport->xlock, flags); + + i3c_target_ctrl_free_request(req); +} + +static void i3c_target_tty_i3c_work(struct work_struct *work) +{ + struct ttyi3c_port *sport = container_of(work, struct ttyi3c_port, work); + struct i3c_request *req = sport->req; + struct scatterlist sg[1]; + unsigned int nents; + u8 ibi; + + if (kfifo_is_empty(&sport->port.xmit_fifo)) + return; + + if (!req) { + req = i3c_target_ctrl_alloc_request(sport->i3cdev->ctrl, GFP_KERNEL); + if (!req) + return; + + sg_init_table(sg, ARRAY_SIZE(sg)); + nents = kfifo_dma_out_prepare(&sport->port.xmit_fifo, sg, ARRAY_SIZE(sg), + UART_XMIT_SIZE); + if (!nents) + goto err; + + req->length = sg->length; + req->buf = sg_virt(sg); + + req->complete = i3c_target_tty_tx_complete; + req->context = sport; + req->tx = true; + + if (i3c_target_ctrl_queue(req, GFP_KERNEL)) + goto err; + + sport->req = req; + } + + ibi = I3C_TTY_IBI_TX; + i3c_target_ctrl_raise_ibi(sport->i3cdev->ctrl, &ibi, 1); + + return; + +err: + i3c_target_ctrl_free_request(req); +} + +static int i3c_port_activate(struct tty_port *port, struct tty_struct *tty) +{ + struct ttyi3c_port *sport = container_of(port, struct ttyi3c_port, port); + const struct i3c_target_ctrl_features *feature; + struct i3c_target_func *func = sport->i3cdev; + struct i3c_request *req; + int rxfifo_size; + int offset = 0; + int ret; + + feature = i3c_target_ctrl_get_features(func->ctrl); + if (!feature) + return -EINVAL; + + ret = tty_port_alloc_xmit_buf(port); + if (ret) + return ret; + + sport->buffer = (void *)get_zeroed_page(GFP_KERNEL); + if (!sport->buffer) + goto err_alloc_rx_buf; + + rxfifo_size = feature->rx_fifo_sz; + + if (!rxfifo_size) + rxfifo_size = I3C_TTY_TRANS_SIZE; + + do { + req = i3c_target_ctrl_alloc_request(func->ctrl, GFP_KERNEL); + if (!req) + goto err_alloc_req; + + req->buf = (void *) (sport->buffer + offset); + req->length = rxfifo_size; + req->context = sport; + req->complete = i3c_target_tty_rx_complete; + offset += rxfifo_size; + + if (i3c_target_ctrl_queue(req, GFP_KERNEL)) + goto err_alloc_req; + } while (req && (offset + rxfifo_size) < UART_XMIT_SIZE); + + reinit_completion(&sport->txcomplete); + + return 0; + +err_alloc_req: + i3c_target_ctrl_cancel_all_reqs(func->ctrl, false); + free_page((unsigned long)sport->buffer); +err_alloc_rx_buf: + tty_port_free_xmit_buf(port); + return -ENOMEM; +} + +static void i3c_port_shutdown(struct tty_port *port) +{ + struct ttyi3c_port *sport = + container_of(port, struct ttyi3c_port, port); + + cancel_work_sync(&sport->work); + + i3c_target_ctrl_cancel_all_reqs(sport->i3cdev->ctrl, true); + i3c_target_ctrl_cancel_all_reqs(sport->i3cdev->ctrl, false); + + i3c_target_ctrl_fifo_flush(sport->i3cdev->ctrl, true); + i3c_target_ctrl_fifo_flush(sport->i3cdev->ctrl, false); + + tty_port_free_xmit_buf(port); + free_page((unsigned long)sport->buffer); +} + +static void i3c_port_destruct(struct tty_port *port) +{ + struct ttyi3c_port *sport = + container_of(port, struct ttyi3c_port, port); + + idr_remove(&i3c_tty_minors, sport->minor); +} + +static const struct tty_port_operations i3c_port_ops = { + .shutdown = i3c_port_shutdown, + .activate = i3c_port_activate, + .destruct = i3c_port_destruct, +}; + +static int i3c_target_tty_bind(struct i3c_target_func *func) +{ + struct ttyi3c_port *sport; + struct device *tty_dev; + int minor; + int ret; + + sport = dev_get_drvdata(&func->dev); + + if (i3c_target_ctrl_set_config(func->ctrl, func)) { + dev_err(&func->dev, "failure set i3c config\n"); + return -EINVAL; + } + + spin_lock_init(&sport->xlock); + init_completion(&sport->txcomplete); + + ret = minor = idr_alloc(&i3c_tty_minors, sport, 0, I3C_TTY_MINORS, GFP_KERNEL); + + if (minor < 0) + goto err_idr_alloc; + + tty_port_init(&sport->port); + sport->port.ops = &i3c_port_ops; + + tty_dev = tty_port_register_device(&sport->port, i3c_tty_driver, minor, + &func->dev); + if (IS_ERR(tty_dev)) { + ret = PTR_ERR(tty_dev); + goto err_register_port; + } + + sport->minor = minor; + ret = i3c_target_ctrl_enable(func->ctrl); + if (ret) + goto err_ctrl_enable; + + return 0; + +err_ctrl_enable: + tty_port_unregister_device(&sport->port, i3c_tty_driver, sport->minor); +err_register_port: + idr_remove(&i3c_tty_minors, sport->minor); +err_idr_alloc: + i3c_target_ctrl_cancel_all_reqs(func->ctrl, false); + dev_err(&func->dev, "bind failure\n"); + + return ret; +} + +static void i3c_target_tty_unbind(struct i3c_target_func *func) +{ + struct ttyi3c_port *sport; + + sport = dev_get_drvdata(&func->dev); + + cancel_work_sync(&sport->work); + + i3c_target_ctrl_disable(func->ctrl); + i3c_target_ctrl_cancel_all_reqs(func->ctrl, 0); + i3c_target_ctrl_cancel_all_reqs(func->ctrl, 1); + + tty_port_unregister_device(&sport->port, i3c_tty_driver, sport->minor); + + free_page((unsigned long)sport->buffer); +} + +static struct i3c_target_func_ops i3c_func_ops = { + .bind = i3c_target_tty_bind, + .unbind = i3c_target_tty_unbind, +}; + +static int i3c_tty_probe(struct i3c_target_func *func) +{ + struct device *dev = &func->dev; + struct ttyi3c_port *port; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->i3cdev = func; + dev_set_drvdata(&func->dev, port); + + INIT_WORK(&port->work, i3c_target_tty_i3c_work); + + return 0; +} + +static ssize_t i3c_write(struct tty_struct *tty, const unsigned char *buf, size_t count) +{ + struct ttyi3c_port *sport = tty->driver_data; + unsigned long flags; + bool is_empty; + int ret = 0; + + spin_lock_irqsave(&sport->xlock, flags); + ret = kfifo_in(&sport->port.xmit_fifo, buf, count); + is_empty = kfifo_is_empty(&sport->port.xmit_fifo); + i3c_target_ctrl_set_status_format1(sport->i3cdev->ctrl, sport->status | I3C_TX_NOEMPTY); + spin_unlock_irqrestore(&sport->xlock, flags); + + if (!is_empty) + queue_work(system_unbound_wq, &sport->work); + + return ret; +} + +static int i3c_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct ttyi3c_port *sport = tty->driver_data; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&sport->xlock, flags); + ret = kfifo_put(&sport->port.xmit_fifo, ch); + spin_unlock_irqrestore(&sport->xlock, flags); + + return ret; +} + +static void i3c_flush_chars(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + unsigned long flags; + + spin_lock_irqsave(&sport->xlock, flags); + if (!kfifo_is_empty(&sport->port.xmit_fifo)) + queue_work(system_unbound_wq, &sport->work); + spin_unlock_irqrestore(&sport->xlock, flags); +} + +static unsigned int i3c_write_room(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + + return kfifo_avail(&sport->port.xmit_fifo); +} + +static void i3c_throttle(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + + i3c_target_ctrl_cancel_all_reqs(sport->i3cdev->ctrl, false); +} + +static void i3c_unthrottle(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + + i3c_port_activate(&sport->port, tty); +} + +static int i3c_open(struct tty_struct *tty, struct file *filp) +{ + struct ttyi3c_port *sport = container_of(tty->port, struct ttyi3c_port, port); + int ret; + + tty->driver_data = sport; + + if (!i3c_target_ctrl_get_addr(sport->i3cdev->ctrl)) { + dev_dbg(&sport->i3cdev->dev, "No target addr assigned, try hotjoin"); + ret = i3c_target_ctrl_hotjoin(sport->i3cdev->ctrl); + if (ret) { + dev_err(&sport->i3cdev->dev, "Hotjoin failure, check connection"); + return ret; + } + } + + return tty_port_open(&sport->port, tty, filp); +} + +static void i3c_close(struct tty_struct *tty, struct file *filp) +{ + tty_port_close(tty->port, tty, filp); +} + +static void i3c_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct ttyi3c_port *sport = tty->driver_data; + int val; + int ret; + u8 ibi = I3C_TTY_IBI_TX; + int retry = 100; + + if (!kfifo_is_empty(&sport->port.xmit_fifo)) { + do { + ret = wait_for_completion_timeout(&sport->txcomplete, timeout / 100); + if (ret) + break; + i3c_target_ctrl_raise_ibi(sport->i3cdev->ctrl, &ibi, 1); + } while (retry--); + + reinit_completion(&sport->txcomplete); + } + + read_poll_timeout(i3c_target_ctrl_fifo_status, val, !val, 100, timeout, false, + sport->i3cdev->ctrl, true); + + i3c_target_ctrl_set_status_format1(sport->i3cdev->ctrl, sport->status & (~I3C_TX_NOEMPTY)); +} + +static const struct tty_operations i3c_tty_ops = { + .open = i3c_open, + .close = i3c_close, + .write = i3c_write, + .put_char = i3c_put_char, + .flush_chars = i3c_flush_chars, + .write_room = i3c_write_room, + .throttle = i3c_throttle, + .unthrottle = i3c_unthrottle, + .wait_until_sent = i3c_wait_until_sent, +}; + +DECLARE_I3C_TARGET_FUNC(tty, i3c_tty_probe, NULL, &i3c_func_ops); + +static int __init i3c_tty_init(void) +{ + int ret; + + i3c_tty_driver = tty_alloc_driver( + I3C_TTY_MINORS, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + + if (IS_ERR(i3c_tty_driver)) + return PTR_ERR(i3c_tty_driver); + + i3c_tty_driver->driver_name = "ttySI3C", i3c_tty_driver->name = "ttySI3C", + i3c_tty_driver->minor_start = 0, + i3c_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, + i3c_tty_driver->subtype = SERIAL_TYPE_NORMAL, + i3c_tty_driver->init_termios = tty_std_termios; + i3c_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | + CLOCAL; + i3c_tty_driver->init_termios.c_lflag = 0; + + tty_set_operations(i3c_tty_driver, &i3c_tty_ops); + + ret = tty_register_driver(i3c_tty_driver); + if (ret) + goto err_register_tty_driver; + + ret = i3c_target_func_register_driver(&ttyi3c_func); + if (ret) + goto err_register_i3c_driver; + + return 0; + +err_register_i3c_driver: + tty_unregister_driver(i3c_tty_driver); + +err_register_tty_driver: + tty_driver_kref_put(i3c_tty_driver); + + return ret; +} + +static void __exit i3c_tty_exit(void) +{ + i3c_target_func_unregister_driver(&ttyi3c_func); + tty_unregister_driver(i3c_tty_driver); + tty_driver_kref_put(i3c_tty_driver); + idr_destroy(&i3c_tty_minors); +} + +module_init(i3c_tty_init); +module_exit(i3c_tty_exit); + +MODULE_LICENSE("GPL"); + From patchwork Tue Jan 23 23:10:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765326 Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05on2084.outbound.protection.outlook.com [40.107.21.84]) (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 194D65B5A4; Tue, 23 Jan 2024 23:11:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.21.84 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051492; cv=fail; b=fu59QGUjqFi1qlWvZE9GP3SSn5DRh1nisAjg7bi8ZdzsO2eg9xybLcpL5hmdty+VNpfhnvxv4RVuFkiOhmN3ci5L+UvsfeMVkzGzUBpdw8qeqAHgAPX2CMMghtb1191SGjcrRcsyhFRaZZElalqLPIILVWz66XTsaU84tjDk04E= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051492; c=relaxed/simple; bh=qW3xZSPxV69HhCqaxH4lMTpKrUoMPbR7IONE/5QS6Vk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=cM8KMycpCrflgQ6YJXH4Q9slPuhqHx1LUIMnaWiIfmrgeeslq0AAhR3Ij2eT1eISAySooMa2HKGR5CjInLwjND/0rys4mkK5AHfHTlgNDRW20jhgZQaGZaQ0OQ/1U5xC+IgQSnLOPD6pO/HLhtGXEANn45TTz5IxM9ThbSUlzxI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=o6djDPLc; arc=fail smtp.client-ip=40.107.21.84 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="o6djDPLc" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=JvCyuhp1M6Fpl6z3ERyyy+J2fuVttXt/I8f/dNJ9U9nx3Rsa1NJPetXpzU35NShltkgD0gHyxcoTcQFUvQmEqnUXduGBpuYM0/HkCZ9pbEjb2+CC6kNEcMOFXxtxKBNZBajewUIDoap8ChrUvsVpd8Ut9sInn2W5FvMxvlBOEIGdIcYxMQN3ZO28jwzc76ct8PG8qPcqFpNLHY4v4hc7cagAGjp2zK8+91//eka1Dxv9V6BFeanvpWhFEG6W5kHtZBFqfw9XTkRfhyMcU/TlMdI/LU5aN2GNeRPvN80rqzpQ7FDKy5X3wcMBV654WcNi4D6ysH6BfE328pm/zdIo2g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=m6ARtUV31Aw0WkrJm4RAXeC+QYXs6+F2YjWwVs9OYOM=; b=gGplKMk66GaTweVFF4futDGQXoLj3fNk9Gx8JTRiLvAnjNq6AabCa5ae+3uPm7R+2+/2dB/f8AVluKNGT+vmtxA56d8EZED3xQUFN5BchDUHBBWkxdK3SbMzNSvX7Q/o/KMQivlHsKI5ys7AN9keGrMoujNKCMsS8jKqdxrAXUM00cp5CVToHyp8n7jDCh0CXd5K1gFOpiVdodwPlbmOqANhCLwGSdMPIb8J7BaKcr1bA0zIxqTxv3CLgqQGE70OvbeDBtlcjxX72BZMSv7PNDDUjw3hN6dwicAm890a6KjVh8PyltU9qkVg+ahtgBiSsDiu/QKue4JPiIEDaVn/iw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=m6ARtUV31Aw0WkrJm4RAXeC+QYXs6+F2YjWwVs9OYOM=; b=o6djDPLcg3Iy+MZV6n+rXtSxmQcr5SKNpH4+AR1MOgqxfIZoDetIje3QswF7f57V40hKy6vFldcCKf93hcDuBvzA948oD2OUd3fszcpWzkr7tFVTDyg75hLqNKFUiGodevHYehnEo4JW0tAqa6qLAIGP9NChEpwLRAE2OAj+0xE= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:28 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:27 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 7/8] i3c: add API i3c_dev_gettstatus_format1() to get target device status Date: Tue, 23 Jan 2024 18:10:42 -0500 Message-Id: <20240123231043.3891847-8-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: 16094cb2-92e2-44e8-f7fe-08dc1c68a0ab X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Htne0ajP4IMNXAZ6lfasz3D+XF/CZN5yFMSI9tlNxqSR9DrWZWMQtlko0OY3XuJiqXV1v28LYlkHH2u/odw5hevBU8S2p/RNF4+iWaoTz/QsyDGmZkcjIg5lkOksSPApq7u5WQOymPKsOfmDHyDaE51+UgdIZf/BNMBPNQL/f25Pjkh/dBSFDRquSEv9wAgrmUmmUWID3CjEgLCMqu9d4t3xU95945ob6b7eGKArmkugqEns3J0RKQoqmBEz/b71KGXOJyd1BRiJImm6z2Q0ugmNTVnC0oJjOLQlDVHv9HDU5V4uxyGgqv3mrY8B6B6NPjdDgnYSHjjuDqR591UHjL/bB64o0AQTHwkll64Y9r25PuufCcowGhBeymWOuXVegLSlUTC4V5FWT8VwTejmDZ0fKd7YvTIjkMkm0+SIMsTn2hnGiGf+VsRNLEFVtzf4NRCc9jJ1KFaD8+DpcGjPw06R88PbPBq+cjGi2TKlvQPzJyP7Q1oeFQB8Ck9IebIb8sOLzzPal6lrvTPXMHK1yiqORdQLFBjd3GH9J180Lcb6Qb0l4NT7aMTVCh+S1fZgs3N4gx8gR3evBqF9yZ0dQLngAvPTiIebSv7n4pekkf0fotuLc3hdhO7k2hAISefP X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: JQ0Asx+ws/CFcKCI49iioicjK8+wCX+mNMUVNtHgo+B7LIMZmIW0lZCAe5hyAi4v0idJxQ8pBlHiXS74ZXD9LXCzj+z+koGm1YyBwEPQqmuAKdqmHYB8fSPgBKJ7U2IaSo7r68XuOARZglcpXPpefuwRIOtjvts0lYWxWMnMwMyiGa/7DWcBX4iIaAXuEcIiUkVDSkvkitq0zp1znqwOc0EjJsqCUCU0RaESLfFEQdjEYopvt0JJ5TYd7F+/n00C8bE05XWLljjnumx9I0kUxx3XUkgDc6Uw1sRXd7nJDZaK0el1vrbL2M4Ud0j3LSXt0jzsch0Tda+vNpsfNrGH0yd/8mYOnBG8WdyvxNgLZI2yB+9hF011AkyuB8QkI2DJuheyYEmhtHjWEa701CdaGpEYygCkTwjltmmy9qtA8LpYfeWp22SQMmvhlBXwHUHNaC0jzTrU+OODiUXNFDCfh/Z/eP8A0UZos3RFmTuX46M1iV4VxNIJZPTOJvq5PNT+nmI6SmgKX18ouYzZ+yd3Ks8cVP9YeVFSsShOXPUWYvTB/2BMCfZldtU6rLCsgL6lCIS69G5xpbSSXZFkunMObFPNzkY1VWe8Gc+JvYhdZI4hDdAlwAXsju3FZo/EcxpHWmH6cbWnlL8dUhDEcUKA0ftEp+q6X86p9gssj/gcxbhQGnNCc61+tXzfkMv3H2ERCQuiHXtVyN5S6s9EJyYJSQmO0HLnCMq7/mwu4MANkz0Zj3clMPVVYIh6Uj8xLoKZaPmoUdq+91FVqtOOkdGF/lQ2dWN7niYT968ZZE3I45+NgZ9qxYXoDjUUpGKx2X7FskNzGeIKGDpknzGyG1zhjEInEbaKogQGx+hX8NWE1HxV1QyqjK4bQFtJlaHSlj9aCL3tvQ9jBrpRI9JJ50zNFGqTHhersL7fnRdxcOFJiVxCPA9whghx4058BSx3Nw4OK8jWZu5wRbqPdRHr15c/xt3eNqg4vS5hLadrN4xxkBCoyQ6NtHhCu+VxFAVrU4OpNAeF6j0NLIXHLnQnVhSioOJNRri60TszGWJShDT0NYIlN8bycexTBBIs2f7SqHpxFwGLqEiKpYpcSM2lCYzHsCNdGJOyLDJHO3TkWujJ7eSyaqud+b54yF0TXKcdoBMFkzjL5JlLPLrMOnYn7XTn+WfeZlTzYR+0PJG4fxgNxXVp+r102018lxPhBGxzqE4dhwhtL5Ydc17vyr1UNhRFe6dK9VsAn7Zt53WkoPRdmJIvuEcXAid+CdaaMFq+8gTz1I9Kv/9BLAJOfMkccAbqpC+xeI2pOrEBT9ZkyG/XtvJ1iPSfCI0UNUVPXCWhkJDN40HNOurwrY/k7Yj8Z1SLubtLy/WEyZaSuvEnNBxn7qvUUFX287RF3DZpJGL4Zjce24I1wbXio13+MIYyw90Gh0NgeqJiccHpIIWat3uGdz5jP1uRzX6o/QwiPbnj//LCu56ymkwBlxlyvgKu1FlkQeV6QnNKr8Ha251uRpJ0EpA/h0yta4c/7xht8mVAkm6gNWbC1DaJXpu2dGzs2i1elP11FOwsB7KFtVEIR+nSn01iZaN2tO0x+1+s3wiKBOGj X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 16094cb2-92e2-44e8-f7fe-08dc1c68a0ab X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:27.8777 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: bISyMDA6DxCy9H3LddpE7lLHA+ARrDlZA6RLJdXlw+9EQyxy8mlyFTz4JKcddR40B0ORwnpLyRalwALvOKQm3g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 I3C standard 5.1.9.3.15 Get Device Status (GETSTATUS): Get request for one I3C Target Device to return its current status. Add API to fetch it with format1. Signed-off-by: Frank Li --- drivers/i3c/device.c | 24 ++++++++++++++++++++++++ drivers/i3c/internals.h | 1 + drivers/i3c/master.c | 26 ++++++++++++++++++++++++++ include/linux/i3c/device.h | 1 + 4 files changed, 52 insertions(+) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index 1a6a8703dbc3a..aa26cf50ab9c6 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -196,6 +196,30 @@ void i3c_device_free_ibi(struct i3c_device *dev) } EXPORT_SYMBOL_GPL(i3c_device_free_ibi); +/** + * i3c_device_getstatus_format1() - Get device status with format 1. + * @dev: device for which you want to get status. + * @status: I3C status format 1 + * + * Return: 0 in case of success, a negative error core otherwise. + */ +int i3c_device_getstatus_format1(struct i3c_device *dev, u16 *status) +{ + int ret = -EINVAL; + + if (!status) + return -EINVAL; + + i3c_bus_normaluse_lock(dev->bus); + if (dev->desc) + ret = i3c_dev_getstatus_format1_locked(dev->desc, status); + + i3c_bus_normaluse_unlock(dev->bus); + + return ret; +} +EXPORT_SYMBOL_GPL(i3c_device_getstatus_format1); + /** * i3cdev_to_dev() - Returns the device embedded in @i3cdev * @i3cdev: I3C device diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h index 908a807badaf9..976ad26ca79c2 100644 --- a/drivers/i3c/internals.h +++ b/drivers/i3c/internals.h @@ -24,4 +24,5 @@ int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev); int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev, const struct i3c_ibi_setup *req); void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev); +int i3c_dev_getstatus_format1_locked(struct i3c_dev_desc *dev, u16 *status); #endif /* I3C_INTERNAL_H */ diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 3afa530c5e322..ff61a218bcc6d 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -2988,6 +2988,32 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev) dev->ibi = NULL; } +int i3c_dev_getstatus_format1_locked(struct i3c_dev_desc *dev, u16 *status) +{ + struct i3c_master_controller *master = i3c_dev_get_master(dev); + struct i3c_ccc_getstatus *format1; + struct i3c_ccc_cmd_dest dest; + struct i3c_ccc_cmd cmd; + int ret; + + format1 = i3c_ccc_cmd_dest_init(&dest, dev->info.dyn_addr, sizeof(*format1)); + if (!format1) + return -ENOMEM; + + i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETSTATUS, &dest, 1); + + ret = i3c_master_send_ccc_cmd_locked(master, &cmd); + if (ret) + goto out; + + *status = be16_to_cpu(format1->status); + +out: + i3c_ccc_cmd_dest_cleanup(&dest); + + return ret; +} + static int __init i3c_init(void) { int res; diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index e119f11948efe..66920045ff042 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -345,4 +345,5 @@ void i3c_device_free_ibi(struct i3c_device *dev); int i3c_device_enable_ibi(struct i3c_device *dev); int i3c_device_disable_ibi(struct i3c_device *dev); +int i3c_device_getstatus_format1(struct i3c_device *dev, u16 *status); #endif /* I3C_DEV_H */ From patchwork Tue Jan 23 23:10:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 765758 Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05on2075.outbound.protection.outlook.com [40.107.21.75]) (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 555DB5B5CE; Tue, 23 Jan 2024 23:11:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.21.75 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051497; cv=fail; b=IrfoVBypyUBJZs3JqXbv4ipZG4LgQqEEzK+l8nvNlisDF2T/ameH6DX5yE6Owsg14UdBIcJX38nUNHNs82BSfEFPYqCnHGDn72j0PtO8fMyQ1ZRYBvMLyLEjY/HanxkY5xAoJ1m04acXYVUMawPdLTli/PWptWwdOkpM/mS6LHM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706051497; c=relaxed/simple; bh=GgWaEjqGud+YQnlG3ty4TBCvboewGfd5FHGckNA9FL8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=E0mxEschs8AKTm++lhEp5fEvnU5dd+iJpzeXCTDc652pdh+0FWz3v7jGkegYz1Z+vcnd+WCjaDaG/DBc9xmSjnlmp3LMjAb8HiUhd28awofFqTkfZHc1od4BPEd7QvBnlNZ+RORS9ehDPdRyE8X4RT2fKvQBasq8GHL3I85rtco= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=Csgbe2h5; arc=fail smtp.client-ip=40.107.21.75 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="Csgbe2h5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=KPkiRN6Gw1WVuMGhPMK0jLaM2cU3sfwC1GCLAlI2EEg0RM8ClpvkTStsQAK2sM0cLNx/LHUpU7NIvCvKvKABdZ6K8OXF5e9GmZmQlSY8FQeyXwCkG7L/YAw5DxUkA0tw2L0QcQd51V9E5JjVpP1aC3p8+8ayR/im1vB5GrxvJlN32CWFDu/mfqpKd261Cy9D3skRqkJH1WTeob1lvhKcmYykyCpRQWpOO0R4xvCI++URSrRcc+q8ZcACwbJZj5anuq9PmTKdqWcMCjqecinKbcHO3DQTbj5c415RatZjHQ4y5zSyh4xSXdJNxeJRWTDDDCNw1M5fjnZj2kmqCsNN/Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Mu0S6GRYTbxmlSGFLNUhga5x469crBrGWJ3PygNzKRg=; b=gOwgf+nR0WThd+bWO9bGQpUMXSU6r/MqlZD2QaWc8uyImQxPFX7w64Rpo2af0xCUpH1G0VitEJLHbuQzoelqJ5Iib/bpN0om9lHRRush3ZX9bbpV2tZAzZjqj3nx80R2poJnvVT4l4nvJTbKcd9sCpHM0I+SxY5vTGCbZ0jNX1bxUTAGlc54jjxymIZyGGp22OINYyyp9XXX3EICYjNriybjmG8ZrUz3Xm1mT8PVBvjcy/hZfCBfB7D6EHdHql4lGY8g80VnCCH2HqqcE2vvgV94uw8/2OwizaQSaQuoCUGbKFlml6SJcwcYpwMVQouyZexbG7FVpeWSofewKcG9BQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Mu0S6GRYTbxmlSGFLNUhga5x469crBrGWJ3PygNzKRg=; b=Csgbe2h5o2ettTgi8Y+1LpE72IouOkeSMurRlUEc/Pdewt1w4bsHlB2ILBOKHbFOlm3LBDt+8YfsnmR/ZkN5ft5KAvLgWNVEoexKIm8bq9Lb+dlR8qJXzCgCrWpMWmTvD1Y4wl2FYSIPjB5AkhMCr7gdx4IKKivW9hE9E6By45g= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by DB9PR04MB9475.eurprd04.prod.outlook.com (2603:10a6:10:367::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7202.32; Tue, 23 Jan 2024 23:11:32 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::c8b4:5648:8948:e85c%3]) with mapi id 15.20.7202.035; Tue, 23 Jan 2024 23:11:31 +0000 From: Frank Li To: frank.li@nxp.com Cc: alexandre.belloni@bootlin.com, conor.culhane@silvaco.com, devicetree@vger.kernel.org, gregkh@linuxfoundation.org, imx@lists.linux.dev, jirislaby@kernel.org, joe@perches.com, krzysztof.kozlowski+dt@linaro.org, krzysztof.kozlowski@linaro.org, linux-i3c@lists.infradead.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, miquel.raynal@bootlin.com, robh@kernel.org, zbigniew.lukwinski@linux.intel.com Subject: [PATCH v4 8/8] tty: i3c: add TTY over I3C master support Date: Tue, 23 Jan 2024 18:10:43 -0500 Message-Id: <20240123231043.3891847-9-Frank.Li@nxp.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240123231043.3891847-1-Frank.Li@nxp.com> References: <20240123231043.3891847-1-Frank.Li@nxp.com> X-ClientProxiedBy: SJ0PR03CA0371.namprd03.prod.outlook.com (2603:10b6:a03:3a1::16) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|DB9PR04MB9475:EE_ X-MS-Office365-Filtering-Correlation-Id: cde15d8b-9ee7-4026-f8bd-08dc1c68a2ef X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 98lRyFRo5/A+x9m82HtvUkepFrf6wrW2/dyARDpDzZiHhwNPycJod+HiINTZ1/ODsyKlPmpFitCKPe+DnU4tEUAbeM1f15A6camTrhArAV0P5eE3CvbSeSnuMVenCYLasIb5J+Buk1XuoGNO/5LPz37LfVZdxrxbwzPR6THIdH61ebbYBqTtQfiRMnJ6pVRljn+0og5QHsgjZsaibT5ozVmFXoHwz6ZFyzucYRU/Rdg6RSCL1obuT1dmg+4V1+9K6W/PgLQ634eeXNQdya9fzzqEYYBqTB6/wXrWOwu8aEmvp44kRvriqDwdqew7PImk4bFpi/DcwrIrlVWqz7mLcFQe0AGpLJMZJcAyNoOdHPZ9IbFpzBLWa4cJ8/mJoZwUH/VcXQdZwzLMZILPg8TdUxkarBCEqxbfkh3rSen4JyxR7ZLFXXl80KR4KpgZFCm1Cp7NM9gm85asDjLHCw9Y66jcEoj0NTQIdoH7OAUI/Phrh8wK2N9plkDll+hQ6xevDVHssK90kU0Fr+cmuNriqe7zOy5yz9DxxlwL+LJBkx+ugaymVDlJTJperCUpG0VcHDpy1QLAFzYmaa1O044ZkqM8Y0d8AKvjURGaadLm3qY4+yzXhR6QQ9oezrR8+iDB X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230031)(136003)(376002)(396003)(346002)(366004)(39860400002)(230922051799003)(1800799012)(451199024)(64100799003)(186009)(1076003)(83380400001)(66946007)(2616005)(26005)(6506007)(6512007)(38100700002)(478600001)(2906002)(8676002)(30864003)(34206002)(8936002)(4326008)(7416002)(37006003)(52116002)(5660300002)(66476007)(6486002)(66556008)(316002)(6666004)(36756003)(38350700005)(86362001)(41300700001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: UspkrnoFy42Lll/QgNvVXftWl7d6SCE9YKFHnAd853E4qj0XBx8+PLOiqibW7MvS7EXfQIIf8irI0ynMGoEfJfGXvHLe+wvsGkMaKcldKf72Fhgu7DBJbRtm1tOF3OOD84t5ndVvTH3r8E3JseTr1ZDGZPmXxhNFS7z6WpYEzpryB6u1H9kNZRuW0mXaSBmwRQssXTvrP6o0iHA3qZtr5SUcICIFJihePpVdH+nQnm7J6TD58MU3X0AvfNn7gp2tUfTURxH4NteIdgc7L5Wm43ecnGTZjRP2sxfHCUv0/FGVo5ucUYiRTItfz92HvY0G0dKLAz3YD7fWFGildK2q4ds7ZtkzSUlHvl8KuDowSbMJ+/wDuFqYcbTw+Y6EZd8LnEHRWM7rZB31hQ83t1BoeNVl/Pe3dTbhxcHZ2ozv74h561qcU7KWzCrq5ah9EoyxpwyTOgabZKoXGwGCJEN6oNdbZLTFLWjKNEVLshtsmnBiy4CzRr+wZhWheOgRFnUTY616pgiQLCU9FHnOaS9ios20WNnBpPmIVPeZ/x4fG9E24pkL7CIuCJ9OoemjERaj0y+eAloyaVkenOb07CaBR3ljBK9Oox0vhyBy7twQH6qa7rd58UVPAi4Vl02r7eG4wxjFKbrZfY4fsBWl/PBIfCNcwrYjpF6CrSJnLBKCZjF0dsLSmqj20Dgc9DNOjr6YKflva+VLN4/N6XBzpqKbD3uWFVOD4Ii4DF1EUJS6JoXLfe2u4HKRtHlNUHzZ73Bhdi06OwiWOs3qpp3aRlQdtJLt3X8kulj1RNutOy3dwIdUTbBDnk5f57Y5AUZ9PWYgjQrmkzV03AifSKSNA7xQ0/ZXsjnpCTDzmp+h6TpEUmEu+B0UNbq+HMAOHmwSUFNmbd4zsb1BuGgTObhPROvFXR7ZitTyK0IxcLEiF3w+YMGAakiqr6Khezt2RYJXzVBc8e6Myig6dYsMv07BMEw25zDnTiqPSyd2gfE8K2HcMxAXlxwPQ4/UCKr1eVcG5iQ54/LQB7+ntFTYXgTCW2qF9jRZT6hiu+A0bnJKBI1YlZpaN9rr2MQ5V3pLT+AkJvCgHKX9hxycWx2nBflPRxx9HVTTWgDhpGymQsb9QMXsgnV/0TV7r6NG3g6x0fckQvTvQjgqkkUGzpxogxbn+kUEy4XiurXy5loNxClE54pKZhLsyvCeOu/UfsdaZ0qBFdlg3qVVJj63fs+vi4IbYX/lxZhtdlFYC344smpxYNHA7mrdz1kJt1qUJ2xjXSKuXGGA+rt7V6GHOCsYeJHSwpmE34e0/SwI5NFLfWZANlSdMjQLEvLwLWsF1mOcbR6Uq/LaoM1NUQKmj0A+97Et6jn9kG7Fq24Nio4+PCpn0IB8+CvK4R+WEi3EtIPOqQAUJIUFRY6g9ukQntcaajT5IxSmvxCS8i5O2zDOROxN5fAJqWqpLrj4LYLNVHgp+t8UHDAwDAVVT6MU+gYPuQdZ3Kf7WpqDUlXf2uZnrKfpd87yoKENrk5EXGistR3k8G2LnbLhpbAQuRnOw8kk2eJ+COOD1CsvLcx80gLTJatx4p8zlPDX+GMayPd3nyAV9+AqHQKB X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: cde15d8b-9ee7-4026-f8bd-08dc1c68a2ef X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jan 2024 23:11:31.8784 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: zgltaZICnirCzwU4Hqxam7huxdtKzZbKAhdhuqOrF7WTYKI5XIY1afmDcjh3BkVJarF/e799sHV0QNCnoxo0BA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR04MB9475 In typical embedded Linux systems, UART consoles require at least two pins, TX and RX. In scenarios where I2C/I3C devices like sensors or PMICs are present, we can save these two pins by using this driver. Pins is crucial resources, especially in small chip packages. This introduces support for using the I3C bus to transfer console tty data, effectively replacing the need for dedicated UART pins. This not only conserves valuable pin resources but also facilitates testing of I3C's advanced features, including early termination, in-band interrupt (IBI) support, and the creation of more complex data patterns. Additionally, it aids in identifying and addressing issues within the I3C controller driver. Signed-off-by: Frank Li --- Notes: Notes: Version number use i3c target patches. Change from v3 to v4 - add static at i3c_remove() Change v2 - using system_unbound_wq working queue - fixed accoring to Jiri Slaby's comments Change before send with i3c target support Change from v4 to v5 - send in i3c improvememtn patches. Change from v2 to v4 - none Change from v1 to v2 - update commit message. - using goto for err handle - using one working queue for all tty-i3c device - fixed typo found by js - update kconfig help - using kfifo Still below items not be fixed (according to Jiri Slaby's comments) - rxwork thread: need trigger from two position. - common thread queue: need some suggestion drivers/tty/Kconfig | 13 ++ drivers/tty/Makefile | 1 + drivers/tty/i3c_tty.c | 426 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 440 insertions(+) create mode 100644 drivers/tty/i3c_tty.c diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 5646dc6242cd9..9ab4cd480e9f8 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -412,6 +412,19 @@ config RPMSG_TTY To compile this driver as a module, choose M here: the module will be called rpmsg_tty. +config I3C_TTY + tristate "TTY over I3C" + depends on I3C + help + Select this option to use TTY over I3C master controller. + + This makes it possible for user-space programs to send and receive + data as a standard tty protocol. I3C provide relatively higher data + transfer rate and less pin numbers, SDA/SCL are shared with other + devices. + + If unsure, say N + endif # TTY source "drivers/tty/serdev/Kconfig" diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 07aca5184a55d..f329f9c7d308a 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -27,5 +27,6 @@ obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o obj-$(CONFIG_VCC) += vcc.o obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o +obj-$(CONFIG_I3C_TTY) += i3c_tty.o obj-y += ipwireless/ diff --git a/drivers/tty/i3c_tty.c b/drivers/tty/i3c_tty.c new file mode 100644 index 0000000000000..8f4e87dfa01cd --- /dev/null +++ b/drivers/tty/i3c_tty.c @@ -0,0 +1,426 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2023 NXP. + * + * Author: Frank Li + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDR(i3c_tty_minors); +static DEFINE_MUTEX(i3c_tty_minors_lock); + +static struct tty_driver *i3c_tty_driver; + +#define I3C_TTY_MINORS 8 +#define I3C_TTY_TRANS_SIZE 16 +#define I3C_TTY_RX_STOP 0 +#define I3C_TTY_RETRY 20 +#define I3C_TTY_YIELD_US 100 + +struct ttyi3c_port { + struct tty_port port; + int minor; + spinlock_t xlock; /* protect xmit */ + u8 tx_buff[I3C_TTY_TRANS_SIZE]; + u8 rx_buff[I3C_TTY_TRANS_SIZE]; + struct i3c_device *i3cdev; + struct work_struct txwork; + struct work_struct rxwork; + struct completion txcomplete; + unsigned long status; + u32 buf_overrun; +}; + +static const struct i3c_device_id i3c_ids[] = { + I3C_DEVICE(0x011B, 0x1000, NULL), + { /* sentinel */ }, +}; + +static int i3c_port_activate(struct tty_port *port, struct tty_struct *tty) +{ + struct ttyi3c_port *sport = container_of(port, struct ttyi3c_port, port); + int ret; + + ret = tty_port_alloc_xmit_buf(port); + if (ret < 0) + return ret; + + sport->status = 0; + + ret = i3c_device_enable_ibi(sport->i3cdev); + if (ret) { + tty_port_free_xmit_buf(port); + return ret; + } + + return 0; +} + +static void i3c_port_shutdown(struct tty_port *port) +{ + struct ttyi3c_port *sport = + container_of(port, struct ttyi3c_port, port); + + i3c_device_disable_ibi(sport->i3cdev); + tty_port_free_xmit_buf(port); +} + +static void i3c_port_destruct(struct tty_port *port) +{ + struct ttyi3c_port *sport = + container_of(port, struct ttyi3c_port, port); + + mutex_lock(&i3c_tty_minors_lock); + idr_remove(&i3c_tty_minors, sport->minor); + mutex_unlock(&i3c_tty_minors_lock); +} + +static const struct tty_port_operations i3c_port_ops = { + .shutdown = i3c_port_shutdown, + .activate = i3c_port_activate, + .destruct = i3c_port_destruct, +}; + +static ssize_t i3c_write(struct tty_struct *tty, const unsigned char *buf, size_t count) +{ + struct ttyi3c_port *sport = tty->driver_data; + unsigned long flags; + bool is_empty; + int ret; + + spin_lock_irqsave(&sport->xlock, flags); + ret = kfifo_in(&sport->port.xmit_fifo, buf, count); + is_empty = kfifo_is_empty(&sport->port.xmit_fifo); + spin_unlock_irqrestore(&sport->xlock, flags); + + if (!is_empty) + queue_work(system_unbound_wq, &sport->txwork); + + return ret; +} + +static int i3c_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct ttyi3c_port *sport = tty->driver_data; + unsigned long flags; + int ret; + + spin_lock_irqsave(&sport->xlock, flags); + ret = kfifo_put(&sport->port.xmit_fifo, ch); + spin_unlock_irqrestore(&sport->xlock, flags); + + return ret; +} + +static void i3c_flush_chars(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + + queue_work(system_unbound_wq, &sport->txwork); +} + +static unsigned int i3c_write_room(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + + return kfifo_avail(&sport->port.xmit_fifo); +} + +static void i3c_throttle(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + + clear_bit(I3C_TTY_RX_STOP, &sport->status); +} + +static void i3c_unthrottle(struct tty_struct *tty) +{ + struct ttyi3c_port *sport = tty->driver_data; + + set_bit(I3C_TTY_RX_STOP, &sport->status); + + queue_work(system_unbound_wq, &sport->rxwork); +} + +static int i3c_open(struct tty_struct *tty, struct file *filp) +{ + struct ttyi3c_port *sport = container_of(tty->port, struct ttyi3c_port, port); + + tty->driver_data = sport; + + return tty_port_open(&sport->port, tty, filp); +} + +static void i3c_close(struct tty_struct *tty, struct file *filp) +{ + tty_port_close(tty->port, tty, filp); +} + +static const struct tty_operations i3c_tty_ops = { + .open = i3c_open, + .close = i3c_close, + .write = i3c_write, + .put_char = i3c_put_char, + .flush_chars = i3c_flush_chars, + .write_room = i3c_write_room, + .throttle = i3c_throttle, + .unthrottle = i3c_unthrottle, +}; + +static void i3c_controller_irq_handler(struct i3c_device *dev, + const struct i3c_ibi_payload *payload) +{ + struct ttyi3c_port *sport = dev_get_drvdata(&dev->dev); + + /* i3c_unthrottle also queue the work to fetch pending data in target side */ + queue_work(system_unbound_wq, &sport->rxwork); +} + +static void tty_i3c_rxwork(struct work_struct *work) +{ + struct ttyi3c_port *sport = container_of(work, struct ttyi3c_port, rxwork); + struct i3c_priv_xfer xfers; + u32 retry = I3C_TTY_RETRY; + u16 status = BIT(0); + int ret; + + memset(&xfers, 0, sizeof(xfers)); + xfers.data.in = sport->rx_buff; + xfers.len = I3C_TTY_TRANS_SIZE; + xfers.rnw = 1; + + do { + if (test_bit(I3C_TTY_RX_STOP, &sport->status)) + break; + + i3c_device_do_priv_xfers(sport->i3cdev, &xfers, 1); + + if (xfers.actual_len) { + ret = tty_insert_flip_string(&sport->port, sport->rx_buff, + xfers.actual_len); + if (ret < xfers.actual_len) + sport->buf_overrun++; + + retry = I3C_TTY_RETRY; + continue; + } + + status = BIT(0); + i3c_device_getstatus_format1(sport->i3cdev, &status); + /* + * Target side needs some time to fill data into fifo. Target side may not + * have hardware update status in real time. Software update status always + * needs some delays. + * + * Generally, target side have circular buffer in memory, it will be moved + * into FIFO by CPU or DMA. 'status' just show if circular buffer empty. But + * there are gap, especially CPU have not response irq to fill FIFO in time. + * So xfers.actual will be zero, wait for little time to avoid flood + * transfer in i3c bus. + */ + usleep_range(I3C_TTY_YIELD_US, 10 * I3C_TTY_YIELD_US); + retry--; + + } while (retry && (status & BIT(0))); + + tty_flip_buffer_push(&sport->port); +} + +static void tty_i3c_txwork(struct work_struct *work) +{ + struct ttyi3c_port *sport = container_of(work, struct ttyi3c_port, txwork); + struct i3c_priv_xfer xfers; + u32 retry = I3C_TTY_RETRY; + unsigned long flags; + int ret; + + xfers.rnw = 0; + xfers.data.out = sport->tx_buff; + + while (!kfifo_is_empty(&sport->port.xmit_fifo)) { + spin_lock_irqsave(&sport->xlock, flags); + xfers.len = kfifo_out_peek(&sport->port.xmit_fifo, sport->tx_buff, + I3C_TTY_TRANS_SIZE); + spin_unlock_irqrestore(&sport->xlock, flags); + ret = i3c_device_do_priv_xfers(sport->i3cdev, &xfers, 1); + if (ret) { + /* + * Target side may not move data out of FIFO. delay can't resolve problem, + * just reduce some possiblity. Target can't end I3C SDR mode write + * transfer, discard data is reasonable when FIFO overrun. + */ + usleep_range(I3C_TTY_YIELD_US, 10 * I3C_TTY_YIELD_US); + retry--; + } else { + retry = I3C_TTY_RETRY; + } + + if (ret == 0 || retry == 0) { + /* when retry == 0, means need discard the data */ + spin_lock_irqsave(&sport->xlock, flags); + ret = kfifo_out(&sport->port.xmit_fifo, sport->tx_buff, xfers.len); + spin_unlock_irqrestore(&sport->xlock, flags); + } + } + + spin_lock_irqsave(&sport->xlock, flags); + if (kfifo_len(&sport->port.xmit_fifo) < WAKEUP_CHARS) + tty_port_tty_wakeup(&sport->port); + spin_unlock_irqrestore(&sport->xlock, flags); +} + +static int i3c_probe(struct i3c_device *i3cdev) +{ + struct ttyi3c_port *sport; + struct device *tty_dev; + struct i3c_ibi_setup req; + int minor; + int ret; + + sport = devm_kzalloc(&i3cdev->dev, sizeof(*sport), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + sport->i3cdev = i3cdev; + + dev_set_drvdata(&i3cdev->dev, sport); + + req.max_payload_len = 8; + req.num_slots = 4; + req.handler = &i3c_controller_irq_handler; + + ret = i3c_device_request_ibi(i3cdev, &req); + if (ret) + return -EINVAL; + + mutex_lock(&i3c_tty_minors_lock); + minor = idr_alloc(&i3c_tty_minors, sport, 0, I3C_TTY_MINORS, GFP_KERNEL); + mutex_unlock(&i3c_tty_minors_lock); + + if (minor < 0) { + ret = -EINVAL; + goto err_idr_alloc; + } + + spin_lock_init(&sport->xlock); + INIT_WORK(&sport->txwork, tty_i3c_txwork); + INIT_WORK(&sport->rxwork, tty_i3c_rxwork); + init_completion(&sport->txcomplete); + + tty_port_init(&sport->port); + sport->port.ops = &i3c_port_ops; + + tty_dev = tty_port_register_device(&sport->port, i3c_tty_driver, minor, + &i3cdev->dev); + if (IS_ERR(tty_dev)) { + ret = PTR_ERR(tty_dev); + goto err_tty_port_register; + } + + sport->minor = minor; + + return 0; + +err_tty_port_register: + tty_port_put(&sport->port); + + mutex_lock(&i3c_tty_minors_lock); + idr_remove(&i3c_tty_minors, minor); + mutex_unlock(&i3c_tty_minors_lock); + +err_idr_alloc: + i3c_device_free_ibi(i3cdev); + + return ret; +} + +static void i3c_remove(struct i3c_device *dev) +{ + struct ttyi3c_port *sport = dev_get_drvdata(&dev->dev); + + tty_port_unregister_device(&sport->port, i3c_tty_driver, sport->minor); + cancel_work_sync(&sport->txwork); + + tty_port_put(&sport->port); + + mutex_lock(&i3c_tty_minors_lock); + idr_remove(&i3c_tty_minors, sport->minor); + mutex_unlock(&i3c_tty_minors_lock); + + i3c_device_free_ibi(sport->i3cdev); +} + +static struct i3c_driver i3c_driver = { + .driver = { + .name = "ttyi3c", + }, + .probe = i3c_probe, + .remove = i3c_remove, + .id_table = i3c_ids, +}; + +static int __init i3c_tty_init(void) +{ + int ret; + + i3c_tty_driver = tty_alloc_driver(I3C_TTY_MINORS, + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + + if (IS_ERR(i3c_tty_driver)) + return PTR_ERR(i3c_tty_driver); + + i3c_tty_driver->driver_name = "ttyI3C"; + i3c_tty_driver->name = "ttyI3C"; + i3c_tty_driver->minor_start = 0, + i3c_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, + i3c_tty_driver->subtype = SERIAL_TYPE_NORMAL, + i3c_tty_driver->init_termios = tty_std_termios; + i3c_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | + CLOCAL; + i3c_tty_driver->init_termios.c_lflag = 0; + + tty_set_operations(i3c_tty_driver, &i3c_tty_ops); + + ret = tty_register_driver(i3c_tty_driver); + if (ret) + goto err_tty_register_driver; + + ret = i3c_driver_register(&i3c_driver); + if (ret) + goto err_i3c_driver_register; + + return 0; + +err_i3c_driver_register: + tty_unregister_driver(i3c_tty_driver); + +err_tty_register_driver: + tty_driver_kref_put(i3c_tty_driver); + + return ret; +} + +static void __exit i3c_tty_exit(void) +{ + i3c_driver_unregister(&i3c_driver); + tty_unregister_driver(i3c_tty_driver); + tty_driver_kref_put(i3c_tty_driver); + idr_destroy(&i3c_tty_minors); +} + +module_init(i3c_tty_init); +module_exit(i3c_tty_exit); + +MODULE_LICENSE("GPL");