From nobody Sun May 24 21:38:04 2026 Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2128.outbound.protection.partner.outlook.cn [139.219.17.128]) (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 D2AA732B115; Thu, 21 May 2026 03:59:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=139.219.17.128 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779335981; cv=fail; b=mulrgm2QdvOIGOmwaYbdjMa03k3mBUZcnfAJUW/i2HR0YBsFrrm+4iQPHFae7rih/QLz23ZmBazMzGPI3Z6SzJtphEOBVo8kpu3/kFok5NlOFEc7dXxrETqOlSUTPot+hYHaq2ZBnjlpLc7GTpZjpetSWe6inwduxOUCvODRibE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779335981; c=relaxed/simple; bh=d3fLM8WesRqb6mHhnu3lXFocusW2u1iExxED7b/j6Xo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=NxztgRZZBG28b8nJx0yaWtOub5C0FwjjLxytbfsYxYIahPhEmWJY4onw82z3AYOvj2nypmJQcO15r+GI4R1gOPXA2uQDpyuKpnW0c8wW3RfK3Sg8+a29sN6uqq/vPIvdlwxe2lYWxY0v8ABV1NjJISkN/WlTwlb/GjtUJohlUHY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com; spf=pass smtp.mailfrom=starfivetech.com; arc=fail smtp.client-ip=139.219.17.128 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=starfivetech.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=KmA2ArsiMovjvCz1Yyw9aSdr+Tu4oD6BNZIH2LaesCt09fCCCZ0bL2g7KWShtuC6iDHhmqrIbvTzn2LJ5gEiA9KkkJcycT2+z+lehLOYutXtn31czzANYbP97ocHgea5XZLmpCq9m7vqxUldQXQdXeRjXrna1rVnBpXXjWGwVr7YAvoTle5KuuP35q+IQKccAbnOy4r2tHOOzTxh+x/zRdQ0Bgc4d5F+ae2l2gO27ktYPb/qdzptHzSa0e4bEoB9qVHcK7SnOaFoQ8PERmKD3ybceRzoB2o1OwXtTi6g6P/KU36Jqf6RofnKtewsKzxxSD0wJjzGG44ooKOphHXlJg== 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=jtn0HAw0y7yUTZkb75DRK9RFYgrClQV2ckLQ5IS7Nn0=; b=Ner/z2yHEIKO3yFOo8YdkoBGBn4fAUQqm6AlJ3BXpffofQ3yvR7wz5pDXFg5SNeRrmMzuz8knbTgs5KJ3tH92Sx+eauVQJMYrz7HS5rjgXiFX4/x165RRxWJ87CIaM3mgzaMwhmlipCq6UB2oP/9re4mEizLM0kLXCqw405Aa3Ec0gP+bhGWn53iFvw81M2lBR+ZRwWdB7RRKL8VZ4T9LF9JgxqHLD+NmHy1RGpHOWG5Kp45dQ2N4DKJ6oc4FpkCartSAaLZpR6DasDXu368SNBbV0uyVPWLbHl0uu08N6IfGyodc0URm/Fj/kSxFbY4ydGqXicSaXIbEdGpgHEqEg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:18::6) by ZQ0PR01MB1302.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:1b::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.48.17; Thu, 21 May 2026 03:43:48 +0000 Received: from ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn ([fe80::973:272c:ab11:7570]) by ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn ([fe80::973:272c:ab11:7570%6]) with mapi id 15.21.0048.016; Thu, 21 May 2026 03:43:48 +0000 From: "lianfeng.ouyang" To: Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Mika Westerberg , Andy Shevchenko , Jan Dabros Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Lianfeng Ouyang Subject: [PATCH v1 1/3] dt-bindings: i2c: snps,dwc-i2c: Add StarFive JHB100 bindings Date: Thu, 21 May 2026 11:43:38 +0800 Message-Id: <20260521034340.27837-2-lianfeng.ouyang@starfivetech.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260521034340.27837-1-lianfeng.ouyang@starfivetech.com> References: <20260521034340.27837-1-lianfeng.ouyang@starfivetech.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BJXPR01CA0067.CHNPR01.prod.partner.outlook.cn (2406:e500:c211:12::34) To ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:18::6) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1269:EE_|ZQ0PR01MB1302:EE_ X-MS-Office365-Filtering-Correlation-Id: 2ec3ff07-8d3d-4a07-d9b8-08deb6eb2a97 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|52116014|366016|3023799007|22082099003|18002099003|56012099003|38350700014; X-Microsoft-Antispam-Message-Info: qQ0ShVvRBeZiw3+it/rE4CYOW0hXHqntOrysX1zBn9UVKkvxfQpMXt9TnOvaulWQg6bokUHzMNlOEcNuzaRcI2vRxj6bC7Kb0F9eqScTcfYR9RWp0cxS46ztj0mANoM9I8pdlCNIfthrYh7RkNzm70ZC5ke9JHwM77nL8vhNHbtU8Ht1d8HZNOIBIiTjRkFniwPk/+eH+ojNF3nYXbTHf7iKJ2YhlMFQjOvrQp0gADM/hb8SZ5O7ry9kyZLvy3cP0ck5SlqYMgpcbLIoSXXYBea9FaScECm1c1VE3eQgHQvXmlZtLKvFPx1m4raU6gV3xFxGNnKvwrFBDrS+5hbm963hMlwU1HY+eoljLqbltmPzOuzaNjIxJrRxc3Z5yB3dLY01W9vfmjiRxIpEMCozCl0RkOoABSnwHw6ZyOOrHc6sdeN+IXX4rZgjDdhk5iqoiAMYd34Eyhj/4sv0D6tlMCjLvOva+dZptMnYyoEkBUMcSRYrrPiui7Pqxrl/bFOR+CIOWE00KBA83IbGVpQIZsR8w954O85/ecOWIEDEQnbB6lgvNRHGPd+X+ixCp2xV X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(376014)(7416014)(52116014)(366016)(3023799007)(22082099003)(18002099003)(56012099003)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?wlTZ2KGF68+oHRPaeVOLESEqd1USY4A8DYxjaXHjDzE7MDK6WII0bRRWQSpS?= =?us-ascii?Q?XB91Wsy9oe1kytG7BM7XBAgReQe2SEK6L4hHz+w7xfYijBwuDFGHLV7QZDEK?= =?us-ascii?Q?KEt/iq17QO+XEf+s3/A0gEurmD7b/bQiPbWL5FGUdoGIsMT2GJ4l3U4Pq0yO?= =?us-ascii?Q?ETzEMEXponEWFT+20e2b6xponzjqTslfikbDiHaGz7491L+xDVxijMq8pevF?= =?us-ascii?Q?+Pyqv42bUTaEP4mB1QDRxF3TXRVGdG18iRCP9+gZXZ0vYgd+B9K5Bocyfo6Y?= =?us-ascii?Q?QCS7ALp2nKlT9KakMiJXCO0uvb6mgXawx4OxKrbzDHtxEskJpPd86rwC6at3?= =?us-ascii?Q?eW81JM+UN15WglBZbpL6YFlLZHZTgvPAmtfh/vPpFV5jvjqzNctGzhPD52Se?= =?us-ascii?Q?0EolUH+zfvWYOn57nQ4Cyd0cudDb4xjsxbxUtsNEcDowmzejIKeAytfUYy+o?= =?us-ascii?Q?WLlNhjvviMbQNMwaSs465XWpIU5iocwM5PjxZepZiYFGtuze3bBn9syn96Jp?= =?us-ascii?Q?pDaMaBDe64q3yKNw6DDHPna+J2QDqUngYpG4vTwIMHVkeiqlNWUYgf/nAVYh?= =?us-ascii?Q?TMmRmLUGiRW+kF6LWXHAb6oGoMLSttU977zxICaqLnkVe7aPxCfCoG4Zdq8z?= =?us-ascii?Q?v13R0ShxToTU1POcFg58+Ts+yFDWVH2+Ir3i6qpTwliRQn13yQ9VbY817Cgr?= =?us-ascii?Q?w3IrrIj/C4bNtOlTlfooOMAD2gwuXYqnCYi3UtbAuNIaI/K+W9VaHifcBUe0?= =?us-ascii?Q?cG9F7O8n/1nRGA0SXujrlz26T5MgmDOUGkWVq9tpjazk+2J50GA/EEYs8/rM?= =?us-ascii?Q?1V2FVDjv+7XjF92y0qaW6V/d6k27Mq65pXLfAkpx97PqE6MGFakcgK7JfcSQ?= =?us-ascii?Q?qgFbAz+LhQ91JA7ZwQvfB0/UPiomVirf5JU03TWl19rP9sEaXLw843yZ/zG3?= =?us-ascii?Q?vzXDLnSGVD/sKhstw5HFKJdKw76Utmt6pGcg6enCYu2ee2CMVIBYZygZpZ5c?= =?us-ascii?Q?cf9fr1jfueZmgUmysu/BOR91vYFLoh/984CACm5UwSwZzGtZ2lg/PfkNcNvf?= =?us-ascii?Q?CscvuA2sdbTqwHv00wW6dw1zrWJTUJsZTTZ9yTF2oY884xL2ZsDb2veuVLm9?= =?us-ascii?Q?f/Uaciq6aKCBuftcVFbyTxDHvrmS5FzQD0YN1VXLxgojGs+pAcrCJtR2X8Fm?= =?us-ascii?Q?DW0GVMt9dQ3L+uCpPEPr+7G0IDjKCXOBzx6FMcOhzZFOiY/LrO+cjpUwFne2?= =?us-ascii?Q?q5/bRkWjRqYPnwaOnTM+ccRyIlmNGL3TsjKqUXa6bgmmOkKXt4yBGEUxLndg?= =?us-ascii?Q?0Y6QKtQ4KdPRpghzPcWu4CingubZ3n8KO2PWzK+wmnPYbtNGWdl9OMn0zd4J?= =?us-ascii?Q?wTKtG/eQHa2yyMMEi1HplMfgqNlBT8aqPGXuTwAKwrrr7hxqlCVChgq1Ft9z?= =?us-ascii?Q?B5kGSe/XttdD1Ay5AXlI0FRyJFhHPU3AGnjBm0QFuVSV+3dQ8F5qFsjN3BeJ?= =?us-ascii?Q?6ZJUMAFRsfDUqi4xWzMJ6c1t9z6wcvuF+3fRD2Ng7iqNokwi9bCDRtYX+dcE?= =?us-ascii?Q?o2EsYqP6QSfkdn0bPFlVWd4cwWfNkjaecL/KDzAjyp5W+o/Ouz9evcjKoKQS?= =?us-ascii?Q?wZe3J7kS/6zmX5qc5l8zNAEp1thn6P+GmidXQmxS19YuuEPySU8V71+9IkPP?= =?us-ascii?Q?a1gLqoVYpPh7cz3fbynakfPpMRovRoATDoAPFBttooh2hVoeGjSxARizJfN5?= =?us-ascii?Q?S61sKl8YqB1ZuKhQiLL9c+mUF3u9PZbIIjUApthFvTRjAW43SObz?= X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: 2ec3ff07-8d3d-4a07-d9b8-08deb6eb2a97 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2026 03:43:48.2626 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: dEauTZ66TljJ5adcgKr6kYD4O3+Uy4jjCJ5N6z3t2oTV4ypCgV5bJhnRR9pPQtzAxX/9kOW9Dgf/c1GPR0F/6arje2bXbGkapDHLq9W6rYk1rHvkmXyjewCp3j7z70GZ X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1302 Content-Type: text/plain; charset="utf-8" From: Lianfeng Ouyang Add device tree bindings for the Synopsys DesignWare Core (DWC) I2C controller and its StarFive JHB100 implementation The binding introduces a new compatible string: "snps,dwc-i2c", intended for the generic IP. It also defines two platform-specific compatibles for the StarFive JHB100 implementation: - "starfive,jhb100-dwc-i2c-master" - "starfive,jhb100-dwc-i2c-slave" The controller supports standard I2C and SMBus protocols, programmable FIFO depths, and optional SMBus Alert routing. The binding documents the necessary clocks, resets, and timing properties. Signed-off-by: Lianfeng Ouyang --- .../devicetree/bindings/i2c/snps,dwc-i2c.yaml | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/snps,dwc-i2c.yaml diff --git a/Documentation/devicetree/bindings/i2c/snps,dwc-i2c.yaml b/Docu= mentation/devicetree/bindings/i2c/snps,dwc-i2c.yaml new file mode 100644 index 000000000000..7227f24f7cbe --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/snps,dwc-i2c.yaml @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2024 StarFive Technology Co., Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/snps,dwc-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys DWC I2C Controller + +maintainers: + - Lianfeng Ouyang + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + oneOf: + - description: Generic Synopsys DWC I2C controller + const: snps,dwc-i2c + - description: StarFive JHB100 I2C master controller + items: + - const: starfive,jhb100-dwc-i2c-master + - const: snps,dwc-i2c + - description: StarFive JHB100 I2C slave controller + items: + - const: starfive,jhb100-dwc-i2c-slave + - const: snps,dwc-i2c + + reg: + description: DWC I2C controller memory mapped registers + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + items: + - description: I2C controller reference clock source + - description: APB interface clock source + + clock-names: + minItems: 1 + items: + - const: ref + - const: pclk + + resets: + maxItems: 1 + + clock-frequency: + description: Desired I2C bus clock frequency in Hz + enum: [100000, 400000, 1000000, 3400000] + default: 400000 + + i2c-sda-hold-time-ns: + description: | + The property should contain the SDA hold time in nanoseconds. + This value is used to compute value written into DW_IC_SDA_HOLD regi= ster. + + i2c-scl-falling-time-ns: + description: | + The property should contain the SCL falling time in nanoseconds. + This value is used to compute the tLOW period. + default: 300 + + i2c-sda-falling-time-ns: + description: | + The property should contain the SDA falling time in nanoseconds. + This value is used to compute the tHIGH period. + default: 300 + + starfive,mctp-i2c-ms: + description: | + The property should contain reference to the master node associated = with the slave. + This value is only used in slave mode, especially for MCTP applicati= on. + + dwc-i2c-tx-fifo-depth: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The property describes the tx fifo depth. + default: 8 + + dwc-i2c-rx-fifo-depth: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The property describes the rx fifo depth. + default: 8 + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + +examples: + - | + i2c@f0000 { + compatible =3D "snps,dwc-i2c"; + reg =3D <0xf0000 0x1000>; + interrupts =3D <11>; + clock-frequency =3D <400000>; + }; + - | + i2c@2000 { + compatible =3D "snps,dwc-i2c"; + reg =3D <0x2000 0x100>; + #address-cells =3D <1>; + #size-cells =3D <0>; + clock-frequency =3D <400000>; + clocks =3D <&i2cclk>; + interrupts =3D <0>; + + eeprom@64 { + compatible =3D "atmel,24c02"; + reg =3D <0x64>; + }; + }; +... --=20 2.43.0 From nobody Sun May 24 21:38:04 2026 Received: from CHN02-BJS-obe.outbound.protection.partner.outlook.cn (mail-bjschn02on2128.outbound.protection.partner.outlook.cn [139.219.17.128]) (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 B512F385D6A; Thu, 21 May 2026 03:59:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=139.219.17.128 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779335986; cv=fail; b=N78GdLTg2UtubayJZEg4VrmV4Be3plIMNO1RyVmmHoO3SY7wdD1alBE7Z41E0ncHYbQVG3sx+1dajVZV6I05ugp++JoTKQa2EVAM4vgWZYNgu853eEGyNO9Jc6f4dK7nfHNyv/HaXgNtCp4MB9sNWD1Ln99qbU0qP64NnO9u2UE= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779335986; c=relaxed/simple; bh=2sXTknih1DN+NnE7lpUY5hzvo/PXuM6EBbDzXwj4VaY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=liQOUISd1qJNfKXlDyIuauC+3xS9q4gPgPemy+YeEvaGMTi0bFL4I8Y7JmoH4jJ5o6OWAZqB7C4ag5djRZWMJy56z+8dj+8SSr/nyMyIST3nqndL4yzjlBrq5eZkFcxnwWisvLRwhCCfNzhXegsYmODFIZugBjoHB4wB5BuLPXo= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com; spf=pass smtp.mailfrom=starfivetech.com; arc=fail smtp.client-ip=139.219.17.128 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=starfivetech.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=dzBHTr3AujT+jCcpOH3+rulN70DVea/sOwbIPF820i5JiHGpZxeHf78qqnSFp4jvAg8O5MDDE5TFk3MUOPybV8aYuWySUR8IVn2GC3kHpDMvgv9dNtqU8yziyV27TjsIEF7rQh/hcG4ns4CM2vYFgnY/tD0ihepty8z5mV6o+vupyY+h+Mf5hYLFp8ebRoOZZDhFU0yN8pxMA+WYdooXAH/vtVPME4OlXIjlpq72Lr+F755fgSC92cv8jDmu1qKTjnc0Keq66FU+CInzsBIKtcT762BXlm1FzFPk8qspAnOq+KJVJMvaFPnVhi6diAWFtEXZW5YtzMkseskSrh5wTw== 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=fEdy0aoLOHoNAbd4hyI9FRnLnF/WSLLtj+61xTMbWYo=; b=fM6aFHlKZk9gdxm66Cdt3HGc31NyUGjSmdBW4YULWgOxtVnN24RudmM5iYk6a4hKZWnJI1kZcKo1ndbPeaAKXIZKOFuHIyVuV+jB2VXOnxzegAqvXAWgTKEdYgMMY+M4qWHuI7Jw5BAaMnbIflmHbY5CK7OWoiJjirXFW/48tdEpQeAgSRP1+qUqO0ZifgiWgB6RZP4IoYVmEBBXOraLLdlf9ImjSiayoaKgjpbElXv52CuTThRBWp97NpGAaIBSDSkL8UcMA4yXRqPzC5eNIctevTWkIQj4D/YQp500pCaE0TbFFN1hXzOv/oSRBsDgHvnpNTuVAfO3SCIrTZv/qA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:18::6) by ZQ0PR01MB1302.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:1b::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.48.17; Thu, 21 May 2026 03:43:49 +0000 Received: from ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn ([fe80::973:272c:ab11:7570]) by ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn ([fe80::973:272c:ab11:7570%6]) with mapi id 15.21.0048.016; Thu, 21 May 2026 03:43:49 +0000 From: "lianfeng.ouyang" To: Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Mika Westerberg , Andy Shevchenko , Jan Dabros Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Lianfeng Ouyang Subject: [PATCH v1 2/3] i2c: designware: Export symbols and add __weak for DWC I2C driver Date: Thu, 21 May 2026 11:43:39 +0800 Message-Id: <20260521034340.27837-3-lianfeng.ouyang@starfivetech.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260521034340.27837-1-lianfeng.ouyang@starfivetech.com> References: <20260521034340.27837-1-lianfeng.ouyang@starfivetech.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BJXPR01CA0067.CHNPR01.prod.partner.outlook.cn (2406:e500:c211:12::34) To ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:18::6) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1269:EE_|ZQ0PR01MB1302:EE_ X-MS-Office365-Filtering-Correlation-Id: 69149620-8bb1-4ed8-40f0-08deb6eb2b16 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|52116014|366016|22082099003|18002099003|56012099003|38350700014|6133799003; X-Microsoft-Antispam-Message-Info: yeVSoywKMp6zwCzMhtNR6pNAOaQUd5yXX0eBh9ZQ6dyrEbv0Q4KevoGw+A8W3ilCj1wtc2SZAar2QHfH9Xifq32NDbWdqdbdEGb8y4mOV9bUiQQuXSyZVOD8eSst9Px3RlsVn5YOlNqrMGP6NZrKmUMZraHftJT3ioJeUmZ1f0L3py8iTKGhyZ6fjvJKfFHTBT4VZCPAFK6+nbiAPl4xe1b/pI1ErPeoa8uMWB+IGh5fzpVI4be04mHut4vKn0WSN8dQm5cg6UgzDiZOhDx37GhltNyMn7uqubntag/D1tO/l4auhbkjXZmx3+zigsCi67nsW+bCJLZEdl3gte70V+iayg9QoYA2QIr5xdXyb9DMjOcmZghl/gQUDRuUcx2xMscq9qeTNmhPB/GGeCWj8aqlAHBHty7un1e+Ve8i4w1wBWpCO+MW44NsTD/BWEpsEmZOlHkZGDFbG0S1wdzK8AOwj77jL0th9Z6Xj+dhcn41ZMY7DRj+FwMVdk6DTvp6BNKGVl5H1fgwvw3PSC24dpM9TSKEHluRcknVlsXsmDEv+ge5zw+HccQxe3JdifY3 X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(376014)(7416014)(52116014)(366016)(22082099003)(18002099003)(56012099003)(38350700014)(6133799003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Bbo6GNUKCyEYHXx/2HkWJBZRPN2ejeJY0AWeIT1lcsbdrkNfGfrrsn/bd+0r?= =?us-ascii?Q?kP9iFPiuaqVJgtGtEL/iT0s7AjWjv+YaKtr0ncW9BqyBPCBLL6bMQVyrgnK9?= =?us-ascii?Q?lRGARlE6KbG+/iMb8Xja0ndRDhbTJxKuyUqsKwOYW7YZcrrJj4wlhjf25MRK?= =?us-ascii?Q?lU1GQboPLRb76umYYzOFEedowc+9mdGolgGdQnqa/TRBdI5h5L/zNwMsQ3aJ?= =?us-ascii?Q?BDrvKjZPCTjsabu2Wa7R4lDMeKvDSYgzpWTY2abru87dHYmwZ+lYtGU/O16Z?= =?us-ascii?Q?lcBFfAekC6u6ulMIi1baT8Y5Tn22qxT8rkmNxGYVOiRofQ9nQ1S2sS0dYxrP?= =?us-ascii?Q?Cc/U7/PL4VFBOTBMr3aLxLjRJyWicFhfp2sWcuHKEkD9StM8OoBKlZ7R0+1k?= =?us-ascii?Q?POkR3VpXSSjlOzuIHLMWNFIKKZNm3xT6D9On9BwczpGE1Gsigl9yNn9V7seA?= =?us-ascii?Q?Q6c89egvPXYyG0L+8aUKsVnrE0ISbVZFWbB3eAuqVJ+KREmf6CdzRrnJuw9K?= =?us-ascii?Q?PaKpecS5jAeqv/T/diKKQ9vhEAMaOcRK7eLyyJ4h4YT9JlmUJXKCNf4ld7Zk?= =?us-ascii?Q?My2RhcjZ/bRaWdcsYLgDfZBiz0wg3RzT8ZxzG9er+bnjphoMGXotOhFhFLcv?= =?us-ascii?Q?MNXczUEFlfbSfODWxvSwwqkvFli7j08t1nBJmEtiWX6ur+rM3qkrAmomrs+x?= =?us-ascii?Q?8vrkMVO1tn5wQODONw3xlekdUNmUPrxij2IPh1VN6tiwa7fNqrNTlWpotl1J?= =?us-ascii?Q?L2LzVixM0d9XMKgiBcwtey4CgwaInS48DCdS0ak89dcOsJkOgvL5H9bhEC5b?= =?us-ascii?Q?SUYWxtojn6FzW5cuFdhHvHZhuoKddNRNves/2JGSC1ByzEd0GkFG+qtCG2Er?= =?us-ascii?Q?ChsG+LoS90H/gEEYdyxEAiI4CnlRjXm2v7qUVqzTgpESyl7ElZDnr0eZos/w?= =?us-ascii?Q?ofygdPOxU9pwjHgpsoqLGeeR5DzDuAMIL00JU5ICiTTpM0TB7kE5o3W8d6H9?= =?us-ascii?Q?ffE5Br5X/GsJNRdWQKcsHU9+9+yWv+ZsBrfMTy0NeCrs6EuIL+yyu2kHqlDB?= =?us-ascii?Q?92d7AZEUgmbV4cRmU4AdfGrsVW8YSyuCkXdyKLR3fweaK4VWWQca3MqWpiBu?= =?us-ascii?Q?NK0HLLuNVRnG0QVwSLM5nEuSDa7aw+HWD6kilGfvAYSwBMG3Jw8AkZybFkDY?= =?us-ascii?Q?MuxM3EWvmZbNF+nCttOdBxzjH6rJZuqPr8QaJ3tApR0eCev6WoRqP2jxtZZt?= =?us-ascii?Q?n4bbuWEfkmby8wWAekpwf0r4AawEDPiHnntZSHCDR28kpqRVyv2Sra65i/0D?= =?us-ascii?Q?QLSuumEF6X8zBUSvyWC5MQ1iLbKpjXt3xNKGNbdEYFenXTJH7c9vJ5ZeymDe?= =?us-ascii?Q?0KFF+C1YhI2O31l3qQn6B/GUENXO13cG1DaxxMNHMEOeJOYcD4xVZQm4e3YK?= =?us-ascii?Q?cr06jIeQdASeqIYy/HR3+SIn6Vz05qHtKRqTbZCm57bvNp87kEy/fKTFanR/?= =?us-ascii?Q?e9/dGvww+HugpTiethQxDFDDuzCK6g2I7xbWVhWBbALr0JUu1TV/oN6jriT+?= =?us-ascii?Q?7Ov2W8ABWCteznTyxqP1fCpCBROKC8d+r0o7PSb09CCMYxYSVX7ryVhzxtxK?= =?us-ascii?Q?/1WyL29l3YFZdNQQTtDWxbZlebInov7DRp/NscBZj6loBARA7cMuq2OdYkfQ?= =?us-ascii?Q?9WRZF49lpf1OVpeET10Ck2955CWClLI2+RsUysh8XRQ6gxN+J/pMMhyfw1sa?= =?us-ascii?Q?gpot2ZbT0LbY9559V/7kcooTUVx1nomeTyWRGIWd8C+1abxvPmne?= X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: 69149620-8bb1-4ed8-40f0-08deb6eb2b16 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2026 03:43:49.1116 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: RpS4f5cs99wNmHHuqu4NZ/RwHQiEthMR3TOEn7v9xbVqIcYNmpM04N8nL8/f0TMJke3xO8w9HeXowcl9zBO1XPEYHzoOQc3V1cXKxLIUct6PrNhEb7UWaxJQj62yFn7x X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1302 Content-Type: text/plain; charset="utf-8" From: Lianfeng Ouyang The upcoming StarFive DWC I2C driver is based on the DesignWare I2C core but requires its own probe and configuration routines due to register layout differences. Export several key functions (i2c_dw_probe_master, i2c_dw_init, i2c_dw_xfer_init, i2c_dw_read_clear_intrbits, etc.) and mark them as __weak. This allows the DWC driver to reuse the common infrastructure while overriding the implementations where needed, promoting code sharing without sacrificing flexibility for the DWC variant. Additionally, extend the register map configuration and introduce the MODEL_STARFIVE flag to accommodate the DWC IP's different register space. Signed-off-by: Lianfeng Ouyang --- drivers/i2c/busses/i2c-designware-common.c | 57 ++++++++++++++++++--- drivers/i2c/busses/i2c-designware-core.h | 25 +++++++++ drivers/i2c/busses/i2c-designware-master.c | 14 +++-- drivers/i2c/busses/i2c-designware-platdrv.c | 6 +++ drivers/i2c/busses/i2c-designware-slave.c | 4 +- 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busse= s/i2c-designware-common.c index 4dc57fd56170..cfeec5d338bb 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -167,6 +167,11 @@ static int i2c_dw_init_regmap(struct dw_i2c_dev *dev) if ((dev->flags & MODEL_MASK) =3D=3D MODEL_AMD_NAVI_GPU) map_cfg.max_register =3D AMD_UCSI_INTR_REG; =20 +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) + if ((dev->flags & MODEL_MASK) =3D=3D MODEL_STARFIVE) + map_cfg.max_register =3D DWC_IC_SMBUS_INTR_CLR; +#endif + if (reg =3D=3D swab32(DW_IC_COMP_TYPE_VALUE)) { map_cfg.reg_read =3D dw_reg_read_swab; map_cfg.reg_write =3D dw_reg_write_swab; @@ -411,7 +416,7 @@ static void i2c_dw_write_timings(struct dw_i2c_dev *dev) * * The controller must be disabled before this function is called. */ -void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode) +__weak void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode) { if (mode =3D=3D DW_IC_SLAVE && !dev->slave) mode =3D DW_IC_MASTER; @@ -430,7 +435,7 @@ void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode) * * Return: 0 on success, or negative errno otherwise. */ -int i2c_dw_init(struct dw_i2c_dev *dev) +__weak int i2c_dw_init(struct dw_i2c_dev *dev) { int ret; =20 @@ -806,10 +811,25 @@ static int i2c_dw_set_fifo_size(struct dw_i2c_dev *de= v) if (ret) return ret; =20 +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) + u32 tx_fifo_cfg =3D 8, rx_fifo_cfg =3D 8; + +#ifdef CONFIG_OF + ret =3D of_property_read_u32(dev->dev->of_node, "dwc-i2c-tx-fifo-depth", = &tx_fifo_cfg); + if (!ret && (tx_fifo_cfg < 2 || tx_fifo_cfg > 256)) + tx_fifo_cfg =3D 8; + + ret =3D of_property_read_u32(dev->dev->of_node, "dwc-i2c-rx-fifo-depth", = &rx_fifo_cfg); + if (!ret && (rx_fifo_cfg < 2 || rx_fifo_cfg > 256)) + rx_fifo_cfg =3D 8; +#endif + param =3D rx_fifo_cfg << 8 | tx_fifo_cfg << 16; +#else ret =3D regmap_read(dev->map, DW_IC_COMP_PARAM_1, ¶m); i2c_dw_release_lock(dev); if (ret) return ret; +#endif =20 tx_fifo_depth =3D FIELD_GET(DW_IC_FIFO_TX_FIELD, param) + 1; rx_fifo_depth =3D FIELD_GET(DW_IC_FIFO_RX_FIELD, param) + 1; @@ -835,7 +855,9 @@ u32 i2c_dw_func(struct i2c_adapter *adap) =20 void i2c_dw_disable(struct dw_i2c_dev *dev) { +#if !IS_ENABLED(CONFIG_I2C_DWC_CORE) unsigned int dummy; +#endif int ret; =20 ret =3D i2c_dw_acquire_lock(dev); @@ -847,7 +869,12 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) =20 /* Disable all interrupts */ __i2c_dw_write_intr_mask(dev, 0); + +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_CLR_INTR); +#else regmap_read(dev->map, DW_IC_CLR_INTR, &dummy); +#endif =20 i2c_dw_release_lock(dev); } @@ -896,6 +923,12 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) if (ret) return ret; =20 +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) + if (dev->mode =3D=3D DW_IC_SLAVE) + i2c_dw_probe_slave(dev); + else + i2c_dw_probe_master(dev); +#else ret =3D i2c_dw_probe_master(dev); if (ret) return ret; @@ -906,10 +939,16 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) =20 if (!adap->name[0]) strscpy(adap->name, "Synopsys DesignWare I2C adapter"); +#endif =20 adap->retries =3D 3; adap->algo =3D &i2c_dw_algo; +#if IS_ENABLED(CONFIG_I2C_DWC_SLAVE) + if (dev->mode =3D=3D DW_IC_SLAVE) + adap->algo =3D &i2c_dw_slave_algo; +#else adap->quirks =3D &i2c_dw_quirks; +#endif adap->dev.parent =3D dev->dev; i2c_set_adapdata(adap, dev); =20 @@ -938,16 +977,18 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) if (!dev->emptyfifo_hold_master) irq_flags |=3D IRQF_NO_THREAD; =20 - ret =3D i2c_dw_acquire_lock(dev); - if (ret) - return ret; + if (!IS_ENABLED(CONFIG_I2C_DWC_CORE) || dev->mode =3D=3D DW_IC_MASTER) { + ret =3D i2c_dw_acquire_lock(dev); + if (ret) + return ret; =20 - __i2c_dw_write_intr_mask(dev, 0); - i2c_dw_release_lock(dev); + __i2c_dw_write_intr_mask(dev, 0); + i2c_dw_release_lock(dev); + } =20 if (!(dev->flags & ACCESS_POLLING)) { ret =3D devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, - irq_flags, dev_name(dev->dev), dev); + irq_flags, dev_name(dev->dev), dev); if (ret) return ret; } diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/= i2c-designware-core.h index 9d8d104cc391..263bff23dd3b 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -321,6 +321,11 @@ struct dw_i2c_dev { u32 bus_capacitance_pF; bool clk_freq_optimized; bool emptyfifo_hold_master; +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) + u16 scl_hcnt; + u16 scl_lcnt; + struct i2c_adapter *ms_adapter; /* Bind another I2C master controller */ +#endif }; =20 #define ACCESS_INTR_MASK BIT(0) @@ -328,6 +333,7 @@ struct dw_i2c_dev { #define ARBITRATION_SEMAPHORE BIT(2) #define ACCESS_POLLING BIT(3) =20 +#define MODEL_STARFIVE BIT(9) #define MODEL_AMD_NAVI_GPU BIT(10) #define MODEL_WANGXUN_SP BIT(11) #define MODEL_MASK GENMASK(11, 8) @@ -359,8 +365,16 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev); u32 i2c_dw_func(struct i2c_adapter *adap); irqreturn_t i2c_dw_isr_master(struct dw_i2c_dev *dev); =20 +void i2c_dw_xfer_init(struct dw_i2c_dev *dev); +int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev); +u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev); +u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev); + extern const struct dev_pm_ops i2c_dw_dev_pm_ops; =20 +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) +#include "i2c-dwc-core.h" +#else static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) { dev->status |=3D STATUS_ACTIVE; @@ -372,6 +386,7 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2= c_dev *dev) regmap_write(dev->map, DW_IC_ENABLE, 0); dev->status &=3D ~STATUS_ACTIVE; } +#endif =20 static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev, unsigned int intr_mask) @@ -409,11 +424,21 @@ static inline void i2c_dw_configure_slave(struct dw_i= 2c_dev *dev) { } static inline irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev) { retur= n IRQ_NONE; } #endif =20 +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) +static inline void i2c_dw_configure(struct dw_i2c_dev *dev) +{ + if (device_is_compatible(dev->dev, "starfive,jhb100-dwc-i2c-slave")) + i2c_dw_configure_slave(dev); + else + i2c_dw_configure_master(dev); +} +#else static inline void i2c_dw_configure(struct dw_i2c_dev *dev) { i2c_dw_configure_slave(dev); i2c_dw_configure_master(dev); } +#endif =20 int i2c_dw_probe(struct dw_i2c_dev *dev); int i2c_dw_init(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busse= s/i2c-designware-master.c index de929b91d5ea..ef15f590ac5c 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -185,7 +185,7 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev = *dev) return 0; } =20 -static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) +__weak void i2c_dw_xfer_init(struct dw_i2c_dev *dev) { struct i2c_msg *msgs =3D dev->msgs; u32 ic_con =3D 0, ic_tar =3D 0; @@ -397,8 +397,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) * IC_RESTART_EN are set, we must manually * set restart bit between messages. */ +#if IS_ENABLED(CONFIG_I2C_DWC_CORE) + if (dev->msg_write_idx > 0) +#else if ((dev->master_cfg & DW_IC_CON_RESTART_EN) && (dev->msg_write_idx > 0)) +#endif need_restart =3D true; } =20 @@ -570,7 +574,7 @@ i2c_dw_read(struct dw_i2c_dev *dev) } } =20 -static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) +__weak u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { unsigned int stat, dummy; =20 @@ -921,7 +925,7 @@ int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_ms= g *msgs, int num) return i2c_dw_xfer_common(dev, msgs, num); } =20 -void i2c_dw_configure_master(struct dw_i2c_dev *dev) +__weak void i2c_dw_configure_master(struct dw_i2c_dev *dev) { struct i2c_timings *t =3D &dev->timings; =20 @@ -967,7 +971,7 @@ static void i2c_dw_unprepare_recovery(struct i2c_adapte= r *adap) i2c_dw_init(dev); } =20 -static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) +int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) { struct i2c_bus_recovery_info *rinfo =3D &dev->rinfo; struct i2c_adapter *adap =3D &dev->adapter; @@ -1006,7 +1010,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_de= v *dev) return 0; } =20 -int i2c_dw_probe_master(struct dw_i2c_dev *dev) +__weak int i2c_dw_probe_master(struct dw_i2c_dev *dev) { unsigned int ic_con; int ret; diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/buss= es/i2c-designware-platdrv.c index 426ffec06e22..a637c5ab0ea4 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -151,6 +151,10 @@ static int dw_i2c_plat_probe(struct platform_device *p= dev) if (device_property_present(device, "wx,i2c-snps-model")) flags =3D MODEL_WANGXUN_SP | ACCESS_POLLING; =20 + if (device_is_compatible(device, "starfive,jhb100-dwc-i2c-master") || + device_is_compatible(device, "starfive,jhb100-dwc-i2c-slave")) + flags |=3D MODEL_STARFIVE; + dev->dev =3D device; dev->irq =3D irq; dev->flags =3D flags; @@ -255,6 +259,8 @@ static const struct of_device_id dw_i2c_of_match[] =3D { { .compatible =3D "mobileye,eyeq6lplus-i2c" }, { .compatible =3D "mscc,ocelot-i2c" }, { .compatible =3D "snps,designware-i2c" }, + { .compatible =3D "starfive,jhb100-dwc-i2c-master" }, + { .compatible =3D "starfive,jhb100-dwc-i2c-slave" }, {} }; MODULE_DEVICE_TABLE(of, dw_i2c_of_match); diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses= /i2c-designware-slave.c index ad0d5fbfa6d5..7b03dc88286a 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -61,7 +61,7 @@ int i2c_dw_unreg_slave(struct i2c_client *slave) return 0; } =20 -static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev) +__weak u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev) { unsigned int stat, dummy; =20 @@ -176,7 +176,7 @@ irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev) return IRQ_HANDLED; } =20 -void i2c_dw_configure_slave(struct dw_i2c_dev *dev) +__weak void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { if (dev->flags & ACCESS_POLLING) return; --=20 2.43.0 From nobody Sun May 24 21:38:04 2026 Received: from CHN02-SH0-obe.outbound.protection.partner.outlook.cn (mail-sh0chn02on2127.outbound.protection.partner.outlook.cn [139.219.146.127]) (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 5A3D0379C39; Thu, 21 May 2026 04:00:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=139.219.146.127 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779336052; cv=fail; b=pZXgRiPsrlWDzBnGnWiiorxStQ58pe9S99bqsRAUv7mfopAeAfnTu80bk0FQFZF6/Z0Z4iwyni/gjPIA3auC5ZjtxHhHgSVsXiS/WXbztMvYPuQtJskfY70VK8ydNKobMS8FMyctDwNaAtIchDWHTxE5o5c7R1Xv9est35gDdU8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779336052; c=relaxed/simple; bh=WaheKzyxMBZbiSxBOvTnMo8vvP4eb+kcXy5U3SRBzDA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=Cw1ubi/Ap2KEDbJbFUW9TL1Q8mSQyFnaydH4ZCe34r5IXOM3WDuU7abAPHDqMtmNC3ATi030fZBK0jY4/yoDnai0gsfjJzdjzi5vFZIQUSpTQdsxJB4PVhKK3Q+pqL6TS/eC/oGkcjkD5nVzCq6f/96TwwpeHmUgTa+gpKvB9no= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com; spf=pass smtp.mailfrom=starfivetech.com; arc=fail smtp.client-ip=139.219.146.127 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=starfivetech.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=etQVQuwW/YEHyP6LLfmjG4+s8qKz0C1VW7UHO/MtSBlzlW397ucEYvLtSzM5MEmA8Q9NCTZK1YeOU6zCGA5qlz3Qg92uzOYDVL067z9Fh85vjxddR98DKAn5Qr4Vr0g/RmWiLsrma8arrvJniAPu5MjVCpg6+MQBgGyy5gj/boejL1Tl0flyeyW9lDmCAKOBCziRz7z2Vt8HVLcbv3d0uOihWy1a8edSBPLbb8ZhcS5006IwifGR2xsT5uRULSal3jq0KZEolLG4+T/IGtA3Aw132f27LdFoI6YTsfQ5eu3BOYxSqQWoovAz1ei0ZZEidLjANkoCvPmTCi3noOQSnw== 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=OsGJpLtL4cafCS7zh89iiwUcKzWCmtD1jm0AUi8PhP0=; b=n8b1/ZqXZOXtyacM02qoROURKl5CiFhE1GeyNiO6vnE85yHSZly242f3PlXBSoQYO8YcokEDTYgyQFTW7yANx3lfDVNcBgSNvbuexgbkTc0984i5NiBHNjaPDT2h/FJ3SRFeaeaOjgAieXREkWCEqKoEDRg0MXX7lTPpQfyQqw5/lAkbslHbT2Zh74STr0dfHsvAiyNGKmr5Q9KQqQ1vVwZQJzAPjFREEQMuLahdI7ltL15cOgcdFz8wDbcVeIR4JBgKjL4CIW9IaxZ23wdo3m+2+jcpfUmmjfrXYxNKl75O4rdsJx0izw/QICjKcMKHeLtXAix1h+Z5YBwKbcJWTg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=starfivetech.com; dmarc=pass action=none header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=starfivetech.com; Received: from ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:18::6) by ZQ0PR01MB1302.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:1b::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.48.17; Thu, 21 May 2026 03:43:50 +0000 Received: from ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn ([fe80::973:272c:ab11:7570]) by ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn ([fe80::973:272c:ab11:7570%6]) with mapi id 15.21.0048.016; Thu, 21 May 2026 03:43:50 +0000 From: "lianfeng.ouyang" To: Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Mika Westerberg , Andy Shevchenko , Jan Dabros Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Lianfeng Ouyang Subject: [PATCH v1 3/3] i2c: dwc: Add StarFive JHB100 I2C master/slave support Date: Thu, 21 May 2026 11:43:40 +0800 Message-Id: <20260521034340.27837-4-lianfeng.ouyang@starfivetech.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260521034340.27837-1-lianfeng.ouyang@starfivetech.com> References: <20260521034340.27837-1-lianfeng.ouyang@starfivetech.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BJXPR01CA0067.CHNPR01.prod.partner.outlook.cn (2406:e500:c211:12::34) To ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn (2406:e500:c550:18::6) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: ZQ0PR01MB1269:EE_|ZQ0PR01MB1302:EE_ X-MS-Office365-Filtering-Correlation-Id: c3754cc2-70df-4136-8c28-08deb6eb2b99 X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|52116014|366016|3023799007|22082099003|18002099003|56012099003|38350700014|6133799003; X-Microsoft-Antispam-Message-Info: R+vZ9lz2AsT+KlL1vnJBl/+yjd5tm5M2Mg6zUgT3NsldRnKHpDxMwsduDbh8/QYPrtESGZO6U4Ctl+14O5S+aBoY3is5YwUKnI+ELQxnu0b4A2yJn+DCvl7eltLQZoIKfZZ292Fi4POn3rRKdmZ3OMme3uZpb6nik9gj0/sCTql7ILYutrduZMeCB5agWmXCu7nftnS25L22nyLPPIAYAiK+igVIofaoJBrnSI1AYr6330cS9/wgwGgJnyfQgIuAtREQlwrOFoPO+WUgFfPATpfe+NzQhH585zm4lbHa2seB3aHl1yB1apOoWSGXavG72yBOE83IhIPRIawXoelCi+52Cj5R+WXOMZFMgd8yS4JQ51wR1mbmn3kDdmaAtKB3uVuLFKaEYxYtlPkOlbAPVmxzdqHFNAWr2RgV1x+ne4HIl1Lw0NfUy3xPEuyxBVizG0xvdeA67zccRpv+l7k5y5rX8Wq6bEZagydBXd04ORgOZTdzK4khXFov+2wNqhlKGGmj3hM2tDn2SXX+2o6KchlON58ke/zbo+6MEeyNOwCiRVlBaRH+W5QtcRRUZhGQ X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(376014)(7416014)(52116014)(366016)(3023799007)(22082099003)(18002099003)(56012099003)(38350700014)(6133799003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?6U3MZ1HIO1fkfOcYWJ8IiMcgi4o+Ta3O21HflMB1+aQm/i+S2lGXGm/1Px56?= =?us-ascii?Q?jSbaajp/n+t4pc6Rgy6ZIXYrUuB3uJJKtlWNnaDbDMI1lK9o0LVma9Ltb/b/?= =?us-ascii?Q?wuKXHViihh/OjOo126/WQngYayoJALwvrg6Hun/gxB748GylRkL5feFhd9my?= =?us-ascii?Q?tA4qf3MFTdxkNiVqeOtGp97cgcWGl+aWqOdDCYL/cII9QcTBdobv8pdapl04?= =?us-ascii?Q?neSPpc8BMgnVZf8D2ox8bOtjDX9+kc6FY3FECyTXtFy96FCYq/TGK9tBMdnj?= =?us-ascii?Q?cGbmhXItH+rbM+CAQspipLjZfQch/SyssqWY8RpBV6AYQB/1xFq0UX/t70Yo?= =?us-ascii?Q?rx1TMOrXUXieLh+Fy5EqajTQ4R/UCVqHibDbGYZS3EleO+7qhmN8v0FxWt9g?= =?us-ascii?Q?3tflrVm+zbaMrfu5AAhSngBX+dSLWB+7P4CKNcfLJYFBfnafI/CpWJL7pCYH?= =?us-ascii?Q?a1WmEAKvfZSyDMIrLWUyROjTQhWU2abKhDz0RlVSOGPu4pdwWquVyMHlRls/?= =?us-ascii?Q?1zn6gkhZhKfLOAxJXJqj+CI753ug3QUbE4QIYzedG/ilEFpzLlPGOdWeQKb4?= =?us-ascii?Q?VN8MRUgBXBok53+/c9IYNDZsu+MP0oDMLFIXwdHmkYV+qw7mLhQ96c3E0oRc?= =?us-ascii?Q?Xui26uatEc4hWAYaDE1rE9P0acVgwwZ3E+8oWeXhYZROC1J2C7EbcPneAVpQ?= =?us-ascii?Q?dqc6r/uQmnAuSiGdlRKYCmiTSPrJRlxY2kdqJAbZdpYFwkhlyHSEEr5dJqPX?= =?us-ascii?Q?pxmzhpuWIo+wmS1CyRhp22QBmkIEdWrM+wotpM+rs4tZzKFhVZBBF9cMjQiG?= =?us-ascii?Q?DZ3+37qDw4FXov0zBadGvU4tN9MjFqIIS0AFN8XywpGyYjXijmBuebk0ttOK?= =?us-ascii?Q?Wr3enluSEmKCqJKWDZao/omxVbcm4+IXeLDSCcyBBVBAyHGqwXyRelcFQY2Q?= =?us-ascii?Q?yPFNbs2uWCnCa0mCGvcBZEHPvBNfQ2ZzzONU+uNkpRsoTkNqKZqBNi4ZdcC3?= =?us-ascii?Q?xeSQloJT8djuHTM0U20SOcPlG3tVuQ/C7FtHrg7OB3qXnZuFOOi6cFe/ex0D?= =?us-ascii?Q?N5LHQ7kVHKTMjAUEawoNDrcTenNWYhLPs+emDMlaYXwyu0tKHmqMUeS4LPZK?= =?us-ascii?Q?NKbLd8OLsXw32A0pGeNlg+koLmMuxE+xAEXK38xft3iwDuA7gAJyDWwSmVTv?= =?us-ascii?Q?2QjDhgRYvyk34XTl9CunonFiH1Kzs3pzK+LaGUy8oWkabiXFEF0doibdJQDK?= =?us-ascii?Q?9ASNWu61XZOOJxCrh8LPD79uMoF4GIkcSZAvC3LBSi2G97qVi0IsW1/yV6GM?= =?us-ascii?Q?6MgXQWBY1iQuRT528F+edAX6FqDiVM6Xmq/7/amt8Q/1D9ByTrU+bxsrPybH?= =?us-ascii?Q?wElB2xDhwZiOyEJtyhdeD3kdc0bW9toDVAmm7fY636SI/qYWHkvblnFI/9TW?= =?us-ascii?Q?rZI6HbeDgXO4LKmbv7M27MTDjm5QMdNrIvdcvWLQ3O1LFZBRwC2WCZHtJBuL?= =?us-ascii?Q?gUr2oM61Wk8tE0O+knLVcdxIdUsef0upTjxHt/PciUcT2h7VxQrNQJXe3XLa?= =?us-ascii?Q?hoG2imCdlwL3+2xtCTOltmkXQ6D0nsgzp2Ec+ijKDyo5rFF79vHzH7bZWgQO?= =?us-ascii?Q?JUHtTQ/Xs9zuDc4qDcl2vPPeRcEZhzdDE6ScM2KUE8TyhPgCQv4HPAtRO+UW?= =?us-ascii?Q?1rRWoS/ktasDm53IS5Le33922tnWfxlGwmvcbbNJFta8l/aJMaeEBE5HtScX?= =?us-ascii?Q?kSaOW2jpYvhCeM+1o439ly0wNuRKba0syIOEsDFR0/UWGPI+2CBn?= X-OriginatorOrg: starfivetech.com X-MS-Exchange-CrossTenant-Network-Message-Id: c3754cc2-70df-4136-8c28-08deb6eb2b99 X-MS-Exchange-CrossTenant-AuthSource: ZQ0PR01MB1269.CHNPR01.prod.partner.outlook.cn X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 May 2026 03:43:50.0684 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 06fe3fa3-1221-43d3-861b-5a4ee687a85c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Qoc2+uRuFv0Ea1frkiJC8P8IZrFFUQlMyK2y045B7cd+zcYmEJP7oqybBcXB4Kpr/AzYhr+HnQgsvoAWh2GMMYvIo6S5TJ2fTwYb1ovnjDybN1uliPQ2WeDwSVGEuvWp X-MS-Exchange-Transport-CrossTenantHeadersStamped: ZQ0PR01MB1302 Content-Type: text/plain; charset="utf-8" From: Lianfeng Ouyang Add support for the Synopsys DesignWare Core (DWC) I2C controller found on the StarFive JHB100 platform. The controller supports both master and slave modes and uses a different register layout compared to the standard DesignWare I2C IP. Key differences handled by this driver: 1. All key registers have different offsets. The driver redefines these offsets in i2c-dwc-core.h. 2. Interrupts are cleared by writing to a separate INTR_CLR register (write-1-to-clear), unlike the read-to-clear scheme of the standard IP. 3. The IC_ENABLE register has an additional TX_CMD_BLOCK control bit which must be managed during enable/disable sequences. 4. Master and slave require separate probe callbacks and cannot rely solely on the runtime mode switching provided by i2c_dw_set_mode(). The driver leverages the common i2c-designware-core infrastructure exported by the previous patch, while implementing its own timing calculation, FIFO configuration, and interrupt handling to accommodate the DWC register offsets and bit definitions. Signed-off-by: Lianfeng Ouyang --- MAINTAINERS | 7 + drivers/i2c/busses/Kconfig | 34 +++ drivers/i2c/busses/Makefile | 3 + drivers/i2c/busses/i2c-dwc-core.h | 184 ++++++++++++ drivers/i2c/busses/i2c-dwc-master.c | 441 ++++++++++++++++++++++++++++ drivers/i2c/busses/i2c-dwc-slave.c | 180 ++++++++++++ 6 files changed, 849 insertions(+) create mode 100644 drivers/i2c/busses/i2c-dwc-core.h create mode 100644 drivers/i2c/busses/i2c-dwc-master.c create mode 100644 drivers/i2c/busses/i2c-dwc-slave.c diff --git a/MAINTAINERS b/MAINTAINERS index d3a6b3f6b6a0..730388b94e56 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25677,6 +25677,13 @@ L: linux-i2c@vger.kernel.org S: Supported F: drivers/i2c/busses/i2c-designware-* =20 +SYNOPSYS DWC I2C DRIVER +M: Lianfeng Ouyang +L: linux-i2c@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/i2c/snps,dwc-i2c.yaml +F: drivers/i2c/busses/i2c-dwc-* + SYNOPSYS DESIGNWARE I2C DRIVER - AMDISP M: Nirujogi Pratap M: Bin Du diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7cb6b9b864a7..7775b4f40d88 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -640,6 +640,40 @@ config I2C_DESIGNWARE_PCI =20 endif =20 +config I2C_DWC_CORE + tristate "Synopsys DWC I2C adapter" + select REGMAP + help + This is a driver for the Synopsys DesignWare CORE (DWC) I2C controller, + a variant of the DesignWare I2C IP with a different register layout. + It shares common infrastructure with the standard DesignWare I2C + driver (I2C_DESIGNWARE_CORE) + +if I2C_DWC_CORE + +config I2C_DWC_SLAVE + bool "Synopsys DWC Slave" + default I2C_DWC_CORE + select I2C_SLAVE + help + If you say yes to this option, support will be included for the + Synopsys DWC I2C slave adapter. + + This is not a standalone module, this module compiles together with + i2c-dwc-core. + +config I2C_DWC_PLATFORM + tristate "Synopsys DWC Platform" + default I2C_DWC_CORE + help + If you say yes to this option, support will be included for the + Synopsys DWC I2C adapter. + + This driver can also be built as a module. If so, the module + will be called i2c-dwc-platform. + +endif + config I2C_DIGICOLOR tristate "Conexant Digicolor I2C driver" depends on ARCH_DIGICOLOR || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 547123ab351f..3ed593011578 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -61,6 +61,9 @@ i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL)= +=3D i2c-designware-bayt obj-$(CONFIG_I2C_DESIGNWARE_AMDISP) +=3D i2c-designware-amdisp.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) +=3D i2c-designware-pci.o i2c-designware-pci-y :=3D i2c-designware-pcidrv.o +obj-$(CONFIG_I2C_DWC_CORE) +=3D i2c-dwc-core.o +i2c-dwc-core-y +=3D i2c-dwc-master.o +i2c-dwc-core-$(CONFIG_I2C_DWC_SLAVE) +=3D i2c-dwc-slave.o obj-$(CONFIG_I2C_DIGICOLOR) +=3D i2c-digicolor.o obj-$(CONFIG_I2C_EG20T) +=3D i2c-eg20t.o obj-$(CONFIG_I2C_EMEV2) +=3D i2c-emev2.o diff --git a/drivers/i2c/busses/i2c-dwc-core.h b/drivers/i2c/busses/i2c-dwc= -core.h new file mode 100644 index 000000000000..eba2eaf116c9 --- /dev/null +++ b/drivers/i2c/busses/i2c-dwc-core.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Synopsys DWC I2C adapter driver. + * + * Based on the TI DAVINCI I2C adapter driver. + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software Inc. + * Copyright (C) 2009 Provigent Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define IC_DFLT_OPERATION_REG_OFFSET 0x00 +#define IC_DFLT_I2C_REG_OFFSET 0x20 +#define IC_DFLT_SMBUS_REG_OFFSET 0xFC + +#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ + I2C_FUNC_SMBUS_BYTE | \ + I2C_FUNC_SMBUS_BYTE_DATA | \ + I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_BLOCK_DATA | \ + I2C_FUNC_SMBUS_I2C_BLOCK) + +#define DWC_IC_CTRL_OP_MODE BIT(0) +#define DWC_IC_CTRL_SPEED_STD BIT(4) +#define DWC_IC_CTRL_SPEED_FAST (2 << 4) +#define DWC_IC_CTRL_SPEED_HIGH (3 << 4) +#define DWC_IC_CTRL_SPEED_MASK GENMASK(5, 4) +#define DWC_IC_CTRL_10BITADDR_TGT BIT(8) +#define DWC_IC_CTRL_10BITADDR_CTRLR BIT(9) +#define DWC_IC_CTRL_STOP_DET_IFADDRESSED BIT(10) +#define DWC_IC_CTRL_TX_EMPTY_CTRL BIT(11) +#define DWC_IC_CTRL_RX_FIFO_FULL_HLD_CTRL BIT(12) +#define DWC_IC_CTRL_BUS_CLEAR_CTRL BIT(14) + +#define DWC_IC_DATA_CMD_DAT GENMASK(7, 0) +#define DWC_IC_DATA_CMD_FIRST_DATA_BYTE BIT(11) +#define DWC_IC_DATA_CMD_STOP BIT(9) +#define DWC_IC_DATA_CMD_CMD BIT(8) + +/* + * Registers offset + */ +#undef DW_IC_ENABLE +#define DW_IC_ENABLE (IC_DFLT_OPERATION_REG_OFFSET + 0x04) +#define DWC_IC_CAPABILITIES (IC_DFLT_OPERATION_REG_OFFSET + 0x0c) +#define DWC_IC_SMBUS_CAPABILITIES (IC_DFLT_OPERATION_REG_OFFSET + 0x18) + +#define DWC_IC_CTRL (IC_DFLT_I2C_REG_OFFSET + 0x04) +#undef DW_IC_TAR +#define DW_IC_TAR (IC_DFLT_I2C_REG_OFFSET + 0x08) +#define DWC_IC_DAR (IC_DFLT_I2C_REG_OFFSET + 0x0C) +#define DWC_IC_SCL_HCNT (IC_DFLT_I2C_REG_OFFSET + 0x24) +#define DWC_IC_SCL_LCNT (IC_DFLT_I2C_REG_OFFSET + 0x28) +#define DWC_IC_HS_SCL_HCNT (IC_DFLT_I2C_REG_OFFSET + 0x2c) +#define DWC_IC_HS_SCL_LCNT (IC_DFLT_I2C_REG_OFFSET + 0x30) +#undef DW_IC_SDA_HOLD +#define DW_IC_SDA_HOLD (IC_DFLT_I2C_REG_OFFSET + 0x34) +#define DWC_IC_SPKLEN (IC_DFLT_I2C_REG_OFFSET + 0x3c) +#define DWC_IC_HS_SPKLEN (IC_DFLT_I2C_REG_OFFSET + 0x40) +#define DWC_IC_SCL_STUCK_AT_LOW_TIMEOUT (IC_DFLT_I2C_REG_OFFSET + 0x44) +#define DWC_IC_SCL_STUCK_AT_LOW_TIMEOUT_MAX (IC_DFLT_I2C_REG_OFFSET + 0x48) +#define DWC_IC_SDA_STUCK_AT_LOW_TIMEOUT (IC_DFLT_I2C_REG_OFFSET + 0x4c) +#undef DW_IC_DATA_CMD +#define DW_IC_DATA_CMD (IC_DFLT_I2C_REG_OFFSET + 0x58) +#define DWC_IC_RX_TL (IC_DFLT_I2C_REG_OFFSET + 0x5c) +#define DWC_IC_TX_TL (IC_DFLT_I2C_REG_OFFSET + 0x60) +#undef DW_IC_INTR_STAT +#define DW_IC_INTR_STAT (IC_DFLT_I2C_REG_OFFSET + 0x74) +#undef DW_IC_INTR_MASK +#define DW_IC_INTR_MASK (IC_DFLT_I2C_REG_OFFSET + 0x78) +#undef DW_IC_RAW_INTR_STAT +#define DW_IC_RAW_INTR_STAT (IC_DFLT_I2C_REG_OFFSET + 0x7c) +#define DWC_IC_INTR_CLR (IC_DFLT_I2C_REG_OFFSET + 0x80) +#define DWC_CLR_INTR BIT(0) +#define DWC_IC_CLR_RX_UNDER BIT(1) +#define DWC_IC_CLR_RX_OVER BIT(2) +#define DWC_IC_CLR_TX_OVER BIT(3) +#define DWC_IC_CLR_RD_REQ BIT(4) +#define DWC_IC_CLR_TX_ABRT BIT(5) +#define DWC_IC_CLR_RX_DONE BIT(6) +#define DWC_IC_CLR_ACTIVITY BIT(7) +#define DWC_IC_CLR_STOP_DET BIT(8) +#define DWC_IC_CLR_START_DET BIT(9) +#define DWC_IC_CLR_GEN_CALL BIT(10) +#define DWC_IC_CLR_RESTART_DET BIT(11) +#define DWC_IC_CLR_SCL_STUCK_DET BIT(12) +#undef DW_IC_ENABLE_STATUS +#define DW_IC_ENABLE_STATUS (IC_DFLT_I2C_REG_OFFSET + 0x84) +#define DWC_IC_TX_TRMNT_SOURCE (IC_DFLT_I2C_REG_OFFSET + 0x88) +#undef DW_IC_STATUS +#define DW_IC_STATUS (IC_DFLT_I2C_REG_OFFSET + 0x8c) +#undef DW_IC_TXFLR +#define DW_IC_TXFLR (IC_DFLT_I2C_REG_OFFSET + 0x90) +#undef DW_IC_RXFLR +#define DW_IC_RXFLR (IC_DFLT_I2C_REG_OFFSET + 0x94) +#define DW_IC_COMP_PARAM_1 0xf4 +#undef DW_IC_COMP_VERSION +#define DW_IC_COMP_VERSION (IC_DFLT_I2C_REG_OFFSET + 0xa4) +#define DWC_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" =3D=3D v1.11* */ + +#undef DW_IC_COMP_TYPE +#define DW_IC_COMP_TYPE (IC_DFLT_I2C_REG_OFFSET + 0xa8) +#define DWC_IC_INTR_SCL_STUCK_AT_LOW BIT(14) + +#define DWC_IC_STATUS_ACTIVITY BIT(0) +#define DWC_IC_STATUS_TFE BIT(2) +#define DWC_IC_STATUS_RFNE BIT(3) +#define DWC_IC_STATUS_CTRLR_ACTIVITY BIT(5) +#define DWC_IC_STATUS_TGT_ACTIVITY BIT(6) + +#define DW_IC_SDA_HOLD_TX_SHIFT 0 +#define DW_IC_SDA_HOLD_TX_MASK GENMASK(15, 0) + +#define DW_IC_ERR_TX_ABRT 0x1 + +#define DWC_IC_TAR_SMBUS_QUICK_CMD BIT(16) +#define DWC_IC_TAR_SPECIAL BIT(11) + +#define DWC_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(4) | BIT(5)) +#define DWC_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(5, 4) + +#define DWC_IC_SMBUS_ARP_CTRL (IC_DFLT_SMBUS_REG_OFFSET + 0x8) +#define DWC_IC_SMBUS_INTR_STAT (IC_DFLT_SMBUS_REG_OFFSET + 0x28) +#define DWC_IC_SMBUS_INTR_CLR (IC_DFLT_SMBUS_REG_OFFSET + 0x34) +#define DWC_CLR_SMBUS_ALERT_DET BIT(10) +#define DWC_R_SMBUS_ALERT_DET BIT(10) + +#define DWC_IC_DAR4_EN 19 +#define DWC_IC_DAR3_EN 18 +#define DWC_IC_DAR2_EN 17 +#define DWC_IC_DAR_EN 16 + +#define DWC_IC_ENABLE_DAR_EN BIT(DWC_IC_DAR_EN) +#define DWC_IC_ENABLE_DAR2_EN BIT(DWC_IC_DAR2_EN) +#define DWC_IC_ENABLE_DAR3_EN BIT(DWC_IC_DAR3_EN) +#define DWC_IC_ENABLE_DAR4_EN BIT(DWC_IC_DAR4_EN) + +#define DW_IC_ENABLE_TX_CMD_BLOCK BIT(2) + +#define DWC_IC_SMBUS 10 + +#define DWC_IC_CAPABILITIES_IC_SMBUS BIT(DWC_IC_SMBUS) + +#define DWC_IC_SMBUS_ARP 2 + +#define DWC_IC_SMBUS_CAPABILITIES_SMBUS_ARP BIT(DWC_IC_SMBUS_ARP) + +#define DWC_IC_SMBUS_ARP_CTRL_NARP_DEVICE_TYPE 0 + +#undef TXGBE_RX_FIFO_DEPTH +#define TXGBE_RX_FIFO_DEPTH 0 + +extern const struct i2c_algorithm i2c_dw_slave_algo; +int i2c_dw_probe_slave(struct dw_i2c_dev *dev); +int i2c_dw_probe_master(struct dw_i2c_dev *dev); +void i2c_dw_read_clear_intrbits_common(struct dw_i2c_dev *dev); + +static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) +{ + int val; + + dev->status |=3D STATUS_ACTIVE; + regmap_read(dev->map, DW_IC_ENABLE, &val); + regmap_write(dev->map, DW_IC_ENABLE, + ((val & ~DW_IC_ENABLE_TX_CMD_BLOCK) | DW_IC_ENABLE_ENABLE)); +} + +static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) +{ + int val; + + regmap_read(dev->map, DW_IC_ENABLE, &val); + regmap_write(dev->map, DW_IC_ENABLE, val & ~DW_IC_ENABLE_ENABLE); + dev->status &=3D ~STATUS_ACTIVE; +} diff --git a/drivers/i2c/busses/i2c-dwc-master.c b/drivers/i2c/busses/i2c-d= wc-master.c new file mode 100644 index 000000000000..6e8d1828f99e --- /dev/null +++ b/drivers/i2c/busses/i2c-dwc-master.c @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Synopsys DWC I2C adapter driver (master only). + * + * Based on the TI DAVINCI I2C adapter driver. + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software Inc. + * Copyright (C) 2009 Provigent Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-designware-core.h" + +#define AMD_TIMEOUT_MIN_US 25 +#define AMD_TIMEOUT_MAX_US 250 +#define AMD_MASTERCFG_MASK GENMASK(15, 0) + +/** + * i2c_dwc_scl_hcnt() - Calculate SCL HCNT + * @ic_clk: Input clock in kHz + * @thigh: Duration in ns of logic 1 to generate + * @tr: SCL rise time in ns + * @spk_cnt: Spike count + */ +static u32 i2c_dwc_scl_hcnt(u32 ic_clk, u32 thigh, u32 tr, u32 spk_cnt) +{ + u64 min_thigh_cnt, rise_cnt; + + /* Formula: cnt =3D f_kHz * t_ns * 10^(-6) */ + min_thigh_cnt =3D DIV_ROUND_CLOSEST_ULL((u64)ic_clk * thigh, MICRO); + rise_cnt =3D DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tr, MICRO); + + return max(5, min_thigh_cnt + rise_cnt - spk_cnt - 3); +} + +/** + * i2c_dwc_scl_lcnt() - Calculate SCL LCNT + * @ic_clk: Input clock in kHz + * @tlow: Duration in ns of logic 0 to generate + * @tf: SCL fall time in ns + */ +static u32 i2c_dwc_scl_lcnt(u32 ic_clk, u32 tlow, u32 tf) +{ + u64 min_tlow_cnt, fall_cnt; + + /* Formula: cnt =3D f_kHz * t_ns * 10^(-6) */ + min_tlow_cnt =3D DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tlow, MICRO); + fall_cnt =3D DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tf, MICRO); + + return max(6, min_tlow_cnt + fall_cnt); +} + +static void i2c_dwc_configure_fifo_master(struct dw_i2c_dev *dev) +{ + /* Configure Tx/Rx FIFO threshold levels */ + regmap_write(dev->map, DWC_IC_TX_TL, dev->tx_fifo_depth / 2); + regmap_write(dev->map, DWC_IC_RX_TL, 0); + + /* Configure the I2C master */ + regmap_write(dev->map, DWC_IC_CTRL, dev->master_cfg); +} + +static int i2c_dwc_set_timings_master(struct dw_i2c_dev *dev) +{ + u32 scl_falling_time =3D 0, scl_rising_time =3D 0; + u32 scl_high_time =3D 0, scl_low_time =3D 0; + struct i2c_timings *t =3D &dev->timings; + unsigned int comp_param1; + u32 ic_clk, spk_cnt; + int ret; + + ret =3D i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + ret =3D regmap_read(dev->map, DWC_IC_CTRL, &comp_param1); + i2c_dw_release_lock(dev); + if (ret) + return ret; + + ic_clk =3D i2c_dw_clk_rate(dev); + + /* 50ns maximum spike */ + spk_cnt =3D DIV_ROUND_CLOSEST_ULL((u64)ic_clk * 50, MICRO); + + regmap_write(dev->map, DWC_IC_HS_SPKLEN, spk_cnt); + regmap_write(dev->map, DWC_IC_SPKLEN, spk_cnt); + + /* Parse user defined rise time and fall time*/ + if (t->scl_rise_ns) + scl_rising_time =3D t->scl_rise_ns; + + if (t->scl_fall_ns) + scl_falling_time =3D t->scl_fall_ns; + + /* Ensure the rise time and fall time should not lower than t_rise_max + * and t_fall_max specification, else it would run faster than expected + * frequency + */ + switch (t->bus_freq_hz) { + case I2C_MAX_STANDARD_MODE_FREQ: + scl_rising_time =3D max(scl_rising_time, 1000); + scl_falling_time =3D max(scl_falling_time, 300); + scl_high_time =3D 4000; /* tHIGH_min =3D 4.0 us */ + scl_low_time =3D 4700; /* tLOW_min =3D 4.7 us */ + break; + case I2C_MAX_FAST_MODE_FREQ: + scl_rising_time =3D max(scl_rising_time, 300); + scl_falling_time =3D max(scl_falling_time, 300); + scl_high_time =3D 600; /* tHIGH_min =3D 600 ns */ + scl_low_time =3D 1300; /* tLOW_min =3D 1.3 us */ + break; + case I2C_MAX_FAST_MODE_PLUS_FREQ: + scl_rising_time =3D max(scl_rising_time, 120); + scl_falling_time =3D max(scl_falling_time, 120); + scl_high_time =3D 260; /* tHIGH_min =3D 260 ns */ + scl_low_time =3D 500; /* tLOW_min =3D 500 ns */ + break; + case I2C_MAX_HIGH_SPEED_MODE_FREQ: + scl_rising_time =3D max(scl_rising_time, 40); + scl_falling_time =3D max(scl_falling_time, 40); + scl_high_time =3D 60; /* tHIGH_min =3D 60 ns */ + scl_low_time =3D 160; /* tLOW_min =3D 160 ns */ + break; + default: + scl_rising_time =3D max(scl_rising_time, 1000); + scl_falling_time =3D max(scl_falling_time, 300); + scl_high_time =3D 4000; /* tHIGH_min =3D 4.0 us */ + scl_low_time =3D 4700; /* tLOW_min =3D 4.7 us */ + break; + } + + ic_clk =3D i2c_dw_clk_rate(dev); + + if (!dev->scl_hcnt || !dev->scl_lcnt) { + dev->scl_hcnt =3D i2c_dwc_scl_hcnt(ic_clk, scl_high_time, + scl_rising_time, spk_cnt); + dev->scl_lcnt =3D i2c_dwc_scl_lcnt(ic_clk, scl_low_time, + scl_falling_time); + } + + dev_dbg(dev->dev, "Bus speed: %s\n", i2c_freq_mode_string(t->bus_freq_hz)= ); + + /* Check is high speed possible and fall back to fast mode if not */ + if ((dev->master_cfg & DWC_IC_CTRL_SPEED_MASK) =3D=3D DWC_IC_CTRL_SPEED_H= IGH) { + if ((comp_param1 & DWC_IC_COMP_PARAM_1_SPEED_MODE_MASK) + !=3D DWC_IC_COMP_PARAM_1_SPEED_MODE_HIGH) { + dev_err(dev->dev, "High Speed not supported!\n"); + t->bus_freq_hz =3D I2C_MAX_FAST_MODE_FREQ; + dev->master_cfg &=3D ~DWC_IC_CTRL_SPEED_MASK; + dev->master_cfg |=3D DWC_IC_CTRL_SPEED_FAST; + dev->hs_hcnt =3D 0; + dev->hs_lcnt =3D 0; + + /* Replace with I2C_MAX_FAST_MODE_PLUS_FREQ */ + scl_rising_time =3D max(scl_rising_time, 120); + scl_falling_time =3D max(scl_falling_time, 120); + scl_high_time =3D 260; /* tHIGH_min =3D 260 ns */ + scl_low_time =3D 500; /* tLOW_min =3D 500 ns */ + + dev->scl_hcnt =3D i2c_dwc_scl_hcnt(ic_clk, scl_high_time, + scl_rising_time, spk_cnt); + dev->scl_lcnt =3D i2c_dwc_scl_lcnt(ic_clk, scl_low_time, + scl_falling_time); + } else if (!dev->hs_hcnt || !dev->hs_lcnt) { + dev->hs_hcnt =3D dev->scl_hcnt; + dev->hs_lcnt =3D dev->scl_lcnt; + } + dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT =3D %d:%d\n", + dev->hs_hcnt, dev->hs_lcnt); + } else { + dev_dbg(dev->dev, "HCNT:LCNT: %d:%d\n", dev->scl_hcnt, dev->scl_lcnt); + } + + return 0; +} + +int i2c_dw_init(struct dw_i2c_dev *dev) +{ + int ret; + + ret =3D i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + /* Disable the adapter */ + __i2c_dw_disable(dev); + + /* Write standard speed timing parameters */ + regmap_write(dev->map, DWC_IC_SCL_HCNT, dev->scl_hcnt); + regmap_write(dev->map, DWC_IC_SCL_LCNT, dev->scl_lcnt); + + /* Write high speed timing parameters if supported */ + if (dev->hs_hcnt && dev->hs_lcnt) { + regmap_write(dev->map, DWC_IC_HS_SCL_HCNT, dev->hs_hcnt); + regmap_write(dev->map, DWC_IC_HS_SCL_LCNT, dev->hs_lcnt); + } + + /* Write SDA hold time if supported */ + if (dev->sda_hold_time) + regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time); + + i2c_dwc_configure_fifo_master(dev); + i2c_dw_release_lock(dev); + + return 0; +} + +static int i2c_dwc_set_sda_hold_time(struct dw_i2c_dev *dev) +{ + int ret =3D regmap_write_bits(dev->map, + DW_IC_SDA_HOLD, + DW_IC_SDA_HOLD_TX_MASK, + dev->sda_hold_time); + return ret; +} + +void i2c_dw_xfer_init(struct dw_i2c_dev *dev) +{ + struct i2c_msg *msgs =3D dev->msgs; + u32 ic_ctrl =3D 0, ic_tar =3D 0; + unsigned int dummy; + + /* Disable the adapter */ + __i2c_dw_disable(dev); + + /* If the slave address is ten bit address, enable 10BITADDR */ + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) { + ic_ctrl =3D DWC_IC_CTRL_10BITADDR_CTRLR; + /* + * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing + * mode has to be enabled via bit 12 of IC_TAR register. + * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be + * detected from registers. + */ + ic_tar =3D DW_IC_TAR_10BITADDR_MASTER; + } + + /* From i2c-core-smbus.c, I2C_SMBUS_QUICK intentionally has msg[0].len = =3D 0 */ + if (dev->msgs[0].len =3D=3D 0) + ic_tar |=3D DWC_IC_TAR_SMBUS_QUICK_CMD | DWC_IC_TAR_SPECIAL; + + regmap_update_bits(dev->map, DWC_IC_CTRL, DWC_IC_CTRL_10BITADDR_CTRLR, + ic_ctrl); + + /* + * Set the slave (target) address and enable 10-bit addressing mode + * if applicable. + */ + regmap_write(dev->map, DW_IC_TAR, + msgs[dev->msg_write_idx].addr | ic_tar); + + /* Enforce disabled interrupts (due to HW issues) */ + regmap_write(dev->map, DW_IC_INTR_MASK, 0); + + /* Enable the adapter */ + __i2c_dw_enable(dev); + + /* Dummy read to avoid the register getting stuck on Bay Trail */ + regmap_read(dev->map, DW_IC_ENABLE_STATUS, &dummy); + + /* Clear and enable interrupts */ + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_CLR_INTR); + regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK); +} + +void i2c_dw_read_clear_intrbits_common(struct dw_i2c_dev *dev) +{ + unsigned int stat; + + /* + * The IC_INTR_STAT register just indicates "enabled" interrupts. + * The unmasked raw version of interrupt status bits is available + * in the IC_RAW_INTR_STAT register. + * + * That is, + * stat =3D readl(IC_INTR_STAT); + * equals to, + * stat =3D readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK); + * + * The raw version might be useful for debugging purposes. + */ + regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + /* + * Do not use the IC_CLR_INTR register to clear interrupts, or + * you'll miss some interrupts, triggered during the period from + * readl(IC_INTR_STAT) to readl(IC_CLR_INTR). + * + * Instead, use the separately-prepared IC_CLR_* registers. + */ + if (stat & DW_IC_INTR_RX_UNDER) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_RX_UNDER); + if (stat & DW_IC_INTR_RX_OVER) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_RX_OVER); + if (stat & DW_IC_INTR_TX_OVER) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_TX_OVER); + if (stat & DW_IC_INTR_RD_REQ) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_RD_REQ); + if (stat & DW_IC_INTR_RX_DONE) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_RX_DONE); + if (stat & DW_IC_INTR_ACTIVITY) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_ACTIVITY); + if (stat & DW_IC_INTR_START_DET) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_START_DET); + if (stat & DW_IC_INTR_GEN_CALL) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_GEN_CALL); +} +EXPORT_SYMBOL_GPL(i2c_dw_read_clear_intrbits_common); + +u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) +{ + unsigned int stat; + + /* + * The IC_INTR_STAT register just indicates "enabled" interrupts. + * The unmasked raw version of interrupt status bits is available + * in the IC_RAW_INTR_STAT register. + * + * That is, + * stat =3D readl(IC_INTR_STAT); + * equals to, + * stat =3D readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK); + * + * The raw version might be useful for debugging purposes. + */ + regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + + if (stat & DW_IC_INTR_TX_ABRT) { + /* + * The IC_TX_ABRT_SOURCE register is cleared whenever + * the IC_CLR_TX_ABRT is read. Preserve it beforehand. + */ + regmap_read(dev->map, DWC_IC_TX_TRMNT_SOURCE, &dev->abort_source); + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_TX_ABRT); + } + if ((stat & DW_IC_INTR_STOP_DET) && + (dev->rx_outstanding =3D=3D 0 || (stat & DW_IC_INTR_RX_FULL))) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_STOP_DET); + if (stat & DW_IC_INTR_RESTART_DET) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_RESTART_DET); + if (stat & DWC_IC_INTR_SCL_STUCK_AT_LOW) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_SCL_STUCK_DET); + + i2c_dw_read_clear_intrbits_common(dev); + + return stat; +} + +void i2c_dw_configure_master(struct dw_i2c_dev *dev) +{ + struct i2c_timings *t =3D &dev->timings; + + dev->functionality =3D I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY | + I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_PEC; + + dev->master_cfg =3D DWC_IC_CTRL_OP_MODE; + + dev->mode =3D DW_IC_MASTER; + + switch (t->bus_freq_hz) { + case I2C_MAX_STANDARD_MODE_FREQ: + dev->master_cfg |=3D DWC_IC_CTRL_SPEED_STD; + break; + case I2C_MAX_FAST_MODE_FREQ: + dev->master_cfg |=3D DWC_IC_CTRL_SPEED_FAST; + break; + case I2C_MAX_FAST_MODE_PLUS_FREQ: + dev->master_cfg |=3D DWC_IC_CTRL_SPEED_FAST; + break; + case I2C_MAX_HIGH_SPEED_MODE_FREQ: + dev->master_cfg |=3D DWC_IC_CTRL_SPEED_HIGH; + break; + default: + dev->master_cfg |=3D DWC_IC_CTRL_SPEED_FAST; + } + + dev->set_sda_hold_time =3D i2c_dwc_set_sda_hold_time; +} + +int i2c_dw_probe_master(struct dw_i2c_dev *dev) +{ + struct i2c_adapter *adap =3D &dev->adapter; + unsigned int ic_ctrl; + int ret; + + init_completion(&dev->cmd_complete); + + ret =3D i2c_dwc_set_timings_master(dev); + if (ret) + return ret; + + /* Lock the bus for accessing DWC_IC_CTRL */ + ret =3D i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + /* + * On AMD platforms BIOS advertises the bus clear feature + * and enables the SCL/SDA stuck low. SMU FW does the + * bus recovery process. Driver should not ignore this BIOS + * advertisement of bus clear feature. + */ + ret =3D regmap_read(dev->map, DWC_IC_CTRL, &ic_ctrl); + i2c_dw_release_lock(dev); + if (ret) + return ret; + + if (ic_ctrl & DWC_IC_CTRL_BUS_CLEAR_CTRL) + dev->master_cfg |=3D DWC_IC_CTRL_BUS_CLEAR_CTRL; + + ret =3D i2c_dw_init(dev); + if (ret) + return ret; + + snprintf(adap->name, sizeof(adap->name), + "Synopsys DWC I2C adapter"); + + ret =3D i2c_dw_init_recovery_info(dev); + if (ret) + return ret; + + return ret; +} + +MODULE_AUTHOR("Sankarshan shukla "); +MODULE_DESCRIPTION("Synopsys DWC I2C bus master adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-dwc-slave.c b/drivers/i2c/busses/i2c-dw= c-slave.c new file mode 100644 index 000000000000..5369eb881238 --- /dev/null +++ b/drivers/i2c/busses/i2c-dwc-slave.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Synopsys DWC I2C adapter driver (slave only). + * + * Based on the Synopsys DWC I2C adapter driver (master). + * + * Copyright (C) 2016 Synopsys Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-designware-core.h" + +void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode) +{ + if (dev->mode =3D=3D DW_IC_SLAVE && mode =3D=3D DW_IC_SLAVE) { + regmap_write(dev->map, DWC_IC_DAR, dev->slave->addr); + __i2c_dw_enable(dev); + dev->status =3D 0; + } +} + +static void i2c_dwc_configure_fifo_slave(struct dw_i2c_dev *dev) +{ + /* Configure the I2C slave. */ + regmap_write(dev->map, DWC_IC_CTRL, 0); + regmap_write(dev->map, DWC_IC_CTRL, dev->slave_cfg); + regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_SLAVE_MASK); +} + +/** + * i2c_dwc_init_slave() - Initialize the DWC i2c slave hardware + * @dev: device private data + * + * This function configures and enables the I2C in slave mode. + * This function is called during I2C init function, and in case of timeou= t at + * run time. + */ +static int i2c_dwc_init_slave(struct dw_i2c_dev *dev) +{ + int ret; + int r_value; + + ret =3D i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + /* Disable the adapter. */ + __i2c_dw_disable(dev); + + /* Write SDA hold time if supported */ + if (dev->sda_hold_time) + regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time); + + regmap_read(dev->map, DWC_IC_CAPABILITIES, &r_value); + if (r_value & DWC_IC_CAPABILITIES_IC_SMBUS) { + regmap_read(dev->map, DWC_IC_SMBUS_CAPABILITIES, &r_value); + if (r_value & DWC_IC_SMBUS_CAPABILITIES_SMBUS_ARP) { + regmap_write(dev->map, DW_IC_ENABLE, DWC_IC_ENABLE_DAR_EN); + regmap_write(dev->map, DWC_IC_SMBUS_ARP_CTRL, + DWC_IC_SMBUS_ARP_CTRL_NARP_DEVICE_TYPE); + } + } + + i2c_dwc_configure_fifo_slave(dev); + i2c_dw_release_lock(dev); + + return 0; +} + +u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev) +{ + unsigned int stat; + unsigned int smbus_stat; + + /* + * The IC_INTR_STAT register just indicates "enabled" interrupts. + * The unmasked raw version of interrupt status bits is available + * in the IC_RAW_INTR_STAT register. + * + * That is, + * stat =3D readl(IC_INTR_STAT); + * equals to, + * stat =3D readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK); + * + * The raw version might be useful for debugging purposes. + */ + regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + regmap_read(dev->map, DWC_IC_SMBUS_INTR_STAT, &smbus_stat); + + /* + * Do not use the IC_CLR_INTR register to clear interrupts, or + * you'll miss some interrupts, triggered during the period from + * readl(IC_INTR_STAT) to readl(IC_CLR_INTR). + * + * Instead, use the separately-prepared IC_CLR_* registers. + */ + + if (stat & DW_IC_INTR_TX_ABRT) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_TX_ABRT); + if (stat & DW_IC_INTR_STOP_DET) + regmap_write(dev->map, DWC_IC_INTR_CLR, DWC_IC_CLR_STOP_DET); + if (smbus_stat & DWC_R_SMBUS_ALERT_DET) + regmap_write(dev->map, DWC_IC_SMBUS_INTR_CLR, DWC_CLR_SMBUS_ALERT_DET); + + i2c_dw_read_clear_intrbits_common(dev); + + return stat; +} + +#if IS_ENABLED(CONFIG_I2C_DWC_SLAVE) +static int i2c_dwc_xfer_ms(struct i2c_adapter *adap, struct i2c_msg *msgs,= int num) +{ + struct dw_i2c_dev *dev =3D i2c_get_adapdata(adap); + + if (!dev->ms_adapter) + return -ENXIO; + + return i2c_dw_xfer(dev->ms_adapter, msgs, num); +} +#endif + +const struct i2c_algorithm i2c_dw_slave_algo =3D { + .master_xfer =3D i2c_dwc_xfer_ms, + .functionality =3D i2c_dw_func, + .reg_slave =3D i2c_dw_reg_slave, + .unreg_slave =3D i2c_dw_unreg_slave, +}; + +void i2c_dw_configure_slave(struct dw_i2c_dev *dev) +{ + dev->functionality =3D I2C_FUNC_SLAVE | DW_IC_DEFAULT_FUNCTIONALITY; + + dev->slave_cfg =3D DWC_IC_CTRL_RX_FIFO_FULL_HLD_CTRL | + DWC_IC_CTRL_STOP_DET_IFADDRESSED; + + dev->mode =3D DW_IC_SLAVE; +} + +int i2c_dw_probe_slave(struct dw_i2c_dev *dev) +{ + struct i2c_adapter *adap =3D &dev->adapter; + struct device_node *ms_node; + int ret; + + ret =3D i2c_dwc_init_slave(dev); + if (ret) + return ret; + + snprintf(adap->name, sizeof(adap->name), "Synopsys DWC I2C Slave adapter"= ); + + /* Get the specified I2C master adapter from DTS for MCTP */ + ms_node =3D of_parse_phandle(dev->dev->of_node, "starfive,mctp-i2c-ms", 0= ); + if (ms_node) { + struct platform_device *ms_pdev =3D of_find_device_by_node(ms_node); + + if (ms_pdev) { + struct dw_i2c_dev *ms_dev =3D platform_get_drvdata(ms_pdev); + + if (ms_dev) + dev->ms_adapter =3D &ms_dev->adapter; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(i2c_dw_probe_slave); + +MODULE_AUTHOR("Sankarshan shukla "); +MODULE_DESCRIPTION("Synopsys DWC I2C bus slave adapter"); +MODULE_LICENSE("GPL"); --=20 2.43.0