From nobody Fri Oct 2 10:08:33 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (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 A1CA63B47CC for ; Sun, 2 Aug 2026 13:13:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785676431; cv=none; b=nAkQ/shhsx9BqS7nO3xLrHDEotND9bUZnnWClec94YR+edRCo66iUpw49KLLar3nfVY75SW3Li0y2UxvWjkNnOYnX73EZ+2nAAveO90F5nwzayOKYVxOWh3E3fwoIfa3MUZrAmdmVxlGoya9Zju1GT9GIXhxzCFrnxu7GcAMz58= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785676431; c=relaxed/simple; bh=c+YVks3b0NjnPxZoViYuM2n50/y5hiDqyE3XSAVuY7U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fP0q1vpbiZGkvMDRGAHkMvVZBYoq58ozXuG5NyZcJzuJtuFokXQB8XuC/aDpzpMz6ErCBe8EoDp0J19liAcP2TwNWSTiYQI58Ye/RPOJJjHCR11Uzz0rPI88LAxeJMT61rLSQqdX1Xe9VNQsQ6Q31JfTaA7QtpkbMUU7xgR/KrQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=piH226cc; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=UPxiwoGy; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="piH226cc"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="UPxiwoGy" Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 672B6h1B1810026 for ; Sun, 2 Aug 2026 13:13:48 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= WFMrveH/zKDPg6uSCRqHIFF/V3WcuiRR4bYskluiiOk=; b=piH226ccPxhyuSkF qrWV0HA4UabSsB9S3VG4rMDPrcgRPtCpkKl23ZpKNlQO7R5qYn1lr0HK/+Ve9K9e 6n2ijm7ae2IFZSaCj2xi3YHs7tjOWXZFQcZ9yqoNZpSqzGT0EMl1/TxbfWPfiNv3 T7QXBt0HJ1nLa7n6izV/EaqR3Xi6iY1eOFipTemOuJtmEq+rQz7Ybd0U9ihQts4I P9wR2++wjg92ijHGzVwtCPUbD+eBby3bWzF/B4SVjBPaMLLRzVmN/1KAldaz5i2F ZbgZkMs6C25Pu2RybhDiLQzlT8RsTaG89ZMGyW3PdlihmLCaKg7llcrfhehS8v2r lLNXTA== Received: from mail-pg1-f198.google.com (mail-pg1-f198.google.com [209.85.215.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4fs8q52wbh-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Sun, 02 Aug 2026 13:13:48 +0000 (GMT) Received: by mail-pg1-f198.google.com with SMTP id 41be03b00d2f7-cab3e9cd922so1653178a12.0 for ; Sun, 02 Aug 2026 06:13:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1785676427; x=1786281227; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=WFMrveH/zKDPg6uSCRqHIFF/V3WcuiRR4bYskluiiOk=; b=UPxiwoGypqreNsQyKsKCzrRaGeLjI9dnxsShw3xSa2mRE7nCJcZd4Y13VyjGqRs9cM EjeiFTlk14COn8Uo62XAuwXfx6zvcnA7rhAhLDiHBN8ojZM1EOCRGIBPqx2js+1Jl/3F gxsPK3otca9kXjZXb7ROzuATZ/gf5LsnIeCmvla72lXSfgO4rSRKLBDP6SSUL6bgLcR+ x6SLRkEWS1ppnychplOBMHZivft0xAog+FrMXITmmoNCULku0Tn0CSH6JbF+flvDlTlb 28glomotKExUMX4hIpKly4S1qX14QkrCpqIkoKi8XcADEAWekr1Hko/0XHs5eaB4HvmA ARzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785676427; x=1786281227; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=WFMrveH/zKDPg6uSCRqHIFF/V3WcuiRR4bYskluiiOk=; b=APFq9kdxqX3yq0J65hPu7uuLtMPWvHqsQM7jvaChXMd+pNq1HLptWVuompr3ZnINZ3 YYejzxEY/EPxtWI1X2PK9SD72p/PM+yO8HfxqiWkclo7T1TmQem8xfwlPL7gAbTcHIAq TLUK1Rr2Gn/3ytHWCFkKBoHkPwQhh9bCf0pOb188gxioSC0iYMTzvMEDr+cHuRwxAVVO f30NZ56cHU1TqPGqP8Vk/pdkG7OYPKBZt/kghvShCmWdHM38AnrbaoRBa4LfZD0w/w54 XSUDMRH831ZVS3zTYleI14US106Tz6EzDbKfSr9y9+ILCm6Xx5YgYqAUrlp/JoE/k5L6 PhPg== X-Forwarded-Encrypted: i=1; AHgh+RpPRTguCPulJGGapYF7GFeRL9cdNJJvXbZ94y98cpXYLwN/lD78fz1g8M8eWsVcGkIObOn2EaB3cpCF5xs=@vger.kernel.org X-Gm-Message-State: AOJu0YyUlfQ3AztPVBi4DJ52ZaodJzO3lCHbyw8EQbjNrrKC+2wvrigJ zsoB+jCP8rUG9E6SOu5awE5/4qS5tVT+GQGItJGKE19rvQ5Z0bpPnu80EZgi65nejPrkAWaOp7u 9Vn4HZUURtV2uIesYYG+oZrU1Kyvl4XruaOn6LVmwO1GBFdBYWcLPImO8CqnB2pPyL7Y= X-Gm-Gg: AR+sD13md4+RfpAfl2EpAzlO5JRQ3JGhK1RZ+0N6MpVckzErJq2lwV3x+S5EiFpMVAJ zRzSrrQQO51gviRve3mBeSkrBSrrKfbnULUBt944q8AnM6WWYLOlRMBG3p6WADhRTQx6OE7Bj5X vbd0Low8hW8CTqgg4gGs/8lNXtxK5Hxbsw6be5lSmtU1Gj0z0Ais4CKdoyEpEwUYLK2ZztP6Ifp rimAuugpxW+ZVzFXfWBNwsHFz/xsrhBe6QJasWkr3FOcTKoMkM5PHI17WoGCHoV2qzqktCBp7We 96fA6A6QOJ5cmuLl7yuKFm5vuVDCmkUfqtTXiRCESiYANyikCm0pBZbP3SCIwu/YziTYvUX5ys+ TlLYtBc2EEg+92AXHhFu1ulsjWuRDXnyGrUnr X-Received: by 2002:a05:6a20:430c:b0:3bf:b84c:2984 with SMTP id adf61e73a8af0-3c92a5a1956mr6354269637.11.1785676427391; Sun, 02 Aug 2026 06:13:47 -0700 (PDT) X-Received: by 2002:a05:6a20:430c:b0:3bf:b84c:2984 with SMTP id adf61e73a8af0-3c92a5a1956mr6354244637.11.1785676426894; Sun, 02 Aug 2026 06:13:46 -0700 (PDT) Received: from hu-vdadhani-hyd.qualcomm.com ([202.46.23.25]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3153e06f8dbsm28303457eec.22.2026.08.02.06.13.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 06:13:46 -0700 (PDT) From: Viken Dadhaniya Date: Sun, 02 Aug 2026 18:43:30 +0530 Subject: [PATCH v2 1/2] dt-bindings: i2c: Add Qualcomm I2C target controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-i2c-qcom-slave-v2-1-27653118fa75@oss.qualcomm.com> References: <20260802-i2c-qcom-slave-v2-0-27653118fa75@oss.qualcomm.com> In-Reply-To: <20260802-i2c-qcom-slave-v2-0-27653118fa75@oss.qualcomm.com> To: Mukesh Kumar Savaliya , Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-arm-msm@vger.kernel.org, linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Viken Dadhaniya X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=ed25519-sha256; t=1785676418; l=2894; i=viken.dadhaniya@oss.qualcomm.com; s=20260324; h=from:subject:message-id; bh=c+YVks3b0NjnPxZoViYuM2n50/y5hiDqyE3XSAVuY7U=; b=Pbj1y8oGh+c4QxvaVEvnyMqzGBQhd0ckHUQCEfsw+wxydShkDhqPFT7fwTB5x7saqp4i1qWVN 3Nz7Zpv5dyeCafFgms731GZ8k5tPP+g7KdrQvvGTMdCeWfieLvJRB6d X-Developer-Key: i=viken.dadhaniya@oss.qualcomm.com; a=ed25519; pk=C39f+LOIGhh/02LQpT46TsUSXRvBn9qXC8Xb26KJ44Y= X-Proofpoint-Spam-Info: AW1haW4tMjYwODAyMDExNiBTYWx0ZWRfXyf2utIBVWIho /KWHtUStWCNtUgOSeaMmAeOKLd9RnyL3hfQIZ4hc0wNu6aN7J2qAkm2CjrYbl5KooBvYM3JM/uV rbuAu9hP+bMMU3b1DmTVFKHW66zN07Y= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODAyMDExNiBTYWx0ZWRfX6rxbtQAg0vyX Gves/Qf5KBV4x0rBdX8Tdn0JGRz8N6SHMQ5uYoLYnVVlqOMF1efj+vALGTy9w3zA/TecNbeCVnd Sv1Ay/HqiFOtQJZ4BReVdZ0WdT5N+gBWQMWTk1nx55kAg6pH1jkHfYDPAC5pE8ifRdWJ1Sv2cT/ nVE8i9AJ3Kh+sDoy1dLFrT11PL48H5lKvlik7x5QL4HxhRsVseNwfS9lIL2VIeokBBlPuCqwh6S zXDJSK/9AWDvX9erWtATAICiMfnSesLGVtP8s/j9/eDHqp5RNX5MswlGXdel00PsRN1y8iaV7Nd M/Hx10+jW2HzPbbxVmNmtpU0IopxDwsfIDG/osEWoUx82mM3cElIO//VraN4i+6xWq6I3f8hPHk +JYOnKswoP6mn9LcxL6PumVUdGxzifOVSn3UJLidiaSPcnbt/SIqYVThYx9/vbT4I7GN23hTHF+ HpR/7W+3ntIwFi/Ujig== X-Proofpoint-GUID: JKwopqR76zoevoSBBaseQ1L5fGxO7Do0 X-Authority-Analysis: v=2.4 cv=IYC3n2qa c=1 sm=1 tr=0 ts=6a6f428c cx=c_pps a=Qgeoaf8Lrialg5Z894R3/Q==:117 a=ZePRamnt/+rB5gQjfz0u9A==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=3WHJM1ZQz_JShphwDgj5:22 a=gEfo2CItAAAA:8 a=EUspDBNiAAAA:8 a=64-jBHeFNbSwsrqMnDgA:9 a=QEXdDO2ut3YA:10 a=x9snwWr2DeNwDh03kgHS:22 a=sptkURWiP4Gy88Gu7hUp:22 X-Proofpoint-ORIG-GUID: JKwopqR76zoevoSBBaseQ1L5fGxO7Do0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-02_04,2026-07-30_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 lowpriorityscore=0 impostorscore=0 bulkscore=0 phishscore=0 suspectscore=0 priorityscore=1501 spamscore=0 malwarescore=0 clxscore=1015 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608020116 QDU1000 and related Qualcomm SoCs include a dedicated I2C target controller that operates exclusively in target mode. It is a distinct IP from the Qualcomm I2C master controllers (GENI, QUP) with a different register interface, so it requires its own binding. Document the MMIO region, interrupt, XO and AHB clocks, interconnect path, and optional pinctrl states for the controller. Signed-off-by: Viken Dadhaniya --- .../devicetree/bindings/i2c/qcom,i2c-target.yaml | 84 ++++++++++++++++++= ++++ 1 file changed, 84 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-target.yaml b/D= ocumentation/devicetree/bindings/i2c/qcom,i2c-target.yaml new file mode 100644 index 000000000000..1e34e874cc4c --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-target.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/qcom,i2c-target.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm I2C Target Controller + +maintainers: + - Mukesh Kumar Savaliya + - Viken Dadhaniya + +description: + Dedicated hardware IP found on Qualcomm SoCs that operates exclusively + as an I2C target (slave) device on the bus. Supports FIFO (PIO) mode + for data transfer. + +properties: + compatible: + enum: + - qcom,qdu1000-i2c-target + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: XO reference clock + - description: AHB bus clock + + clock-names: + items: + - const: xo + - const: ahb + + interconnects: + maxItems: 1 + + interconnect-names: + const: i2c + + pinctrl-0: true + pinctrl-1: true + + pinctrl-names: + items: + - const: default + - const: sleep + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - interconnects + - interconnect-names + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + i2c@88ca000 { + compatible =3D "qcom,qdu1000-i2c-target"; + reg =3D <0x88ca000 0x64>; + clocks =3D <&gcc GCC_SM_BUS_XO_CLK>, <&gcc GCC_SM_BUS_AHB_CLK>; + clock-names =3D "xo", "ahb"; + interrupts =3D ; + #address-cells =3D <1>; + #size-cells =3D <0>; + interconnect-names =3D "i2c"; + interconnects =3D <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_= SMBUS_CFG 0>; + }; +... --=20 2.34.1 From nobody Fri Oct 2 10:08:33 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (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 D21E23B5850 for ; Sun, 2 Aug 2026 13:13:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785676435; cv=none; b=hARsVZKaLGCV2IyrREWTvYutvbmpPPTgxvOM+XqZHBeWYSFMoKnwV4O2n+kmYklavJ2EYD84ONepM0rcLgeTgFXnA1swBuWyHnMqePwvJ6dICRkHGUn58wiEEQoT8vF5aukCqK6IpcIgMTsGspOKXWFBvimCU84H3+a0oOFzO+M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785676435; c=relaxed/simple; bh=x6kSr0aNgXnNuE3iiKV3J/ypVJgn8UqMYoiV4CsZ5UI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WabhuEg7ctS8ajT1ShT7HaNwBnUiPFNYcSriU+J1nR6L1v1KKz6PxJ1i4f8GfrB/sm/gUV5lFOn0X0+NVVP0IBXSFQIxjGwSbtRhkYOaGtwzUbJ+XeKMMvW1PdIeg1gVkpErvMqR5MyQ8Sn/2slXSq4bYo9+quupx8XAXIX2G4M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=KesZsRS+; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=Rn2EZATm; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="KesZsRS+"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="Rn2EZATm" Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 672B6nwN1318483 for ; Sun, 2 Aug 2026 13:13:53 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= FliEtR0iB0U+xyr5rIwkmZX9+qR47RFWsV+gxr2PKk8=; b=KesZsRS+KDVFmTTe LZn62D68MNjTC8KCkaxqMRDIBvZdg1WiWXG9PIL9Xdhb8COBPcNhtN6pNYEyMqKv 040TuGAbBDW90zlSbD/abMXGHcz7BsaT+BbQ+2caxKKWkwl7nzxYX58iWJMY+Ux4 AEGJwrWMdDFzA0IzE04/pDijgSRlQFkdZvVNSv+4rlW42uQxYpcDddtLZNRoScD6 nKGVL6cJjivlV3qEKt1vxkhmev0PF3U6nmoThh9FTBaJuHuFe6WtQY3ekiUN0pUh wv18YgKsmBsTohc+JIEOs7w1tX5hQ3RHzipsFRaEHJtpG7chlVA1/TMSLDK3qKpr dMmttg== Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4fs966atky-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Sun, 02 Aug 2026 13:13:52 +0000 (GMT) Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2cceabd70f5so75936575ad.1 for ; Sun, 02 Aug 2026 06:13:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1785676432; x=1786281232; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=FliEtR0iB0U+xyr5rIwkmZX9+qR47RFWsV+gxr2PKk8=; b=Rn2EZATmaprd8A92fb/svDiL2aL4OkA5/xrP3n7Zz+rfu2yiktGqKxFLgsCcb1jKgv sSV1Hp9UALddtKgDizP6OwWZsEdAyF1e0HcBekpmgigN8KsURXQkixEx0P6zg4UUxcJV acvZFrIg0cBjDEudvR6AKj0eMMOwG7rXxfkzYGd2gnzCc63fePNt+ioYADhCGuMy/PM4 8LCZqnuK43NJnJ3Hekg5zVxY8XJm5CStQCn5PholCUTUtz0fCNkjBvVXav4S9IjFJPFm XBOLpI3XM8yaEP3npRXZIlZhDcJ07ZVdAqNjjof3ZNMtzX5PJ/tmw6VvjE9nQGLEM/Po U0oQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1785676432; x=1786281232; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=FliEtR0iB0U+xyr5rIwkmZX9+qR47RFWsV+gxr2PKk8=; b=T+s3NbkqQ3OcHQBPbMFAle+E8Hu31C/mZ4PHnPnsHBF4LIZ7u5QmzEVv358C8n83c3 MtijULw6n4acOx//yGo8ZOdrFN9LI7Ga8KsU7FPux530CHd+P6F3WOOAF67ZbHcbBol3 cjF7SnMWap8+/FwpsFe13oRCFmorKU213HLY9Ag+H74Qs45IbXsMEx/JLeMoFwDQozet NGqZms3XL+QM/YA8BCryXjtocxvZwIco/MRYzYjiBZ9vQ3VQAKF5b8wP8YFkgwBS1QHZ H65cLuk/VL0nWX/5U65bpxt+s29y6w6JlgdpsrDLpGdjaki+4YZhJtYO7BgAlMoR6oa+ AQvg== X-Forwarded-Encrypted: i=1; AHgh+RotiNgiNMYI5evair4ztHIF78PbdaEaC3L0m2wYboG978L4igXl9djua2+uY7UY1e/il72wzDbGg9Q+f20=@vger.kernel.org X-Gm-Message-State: AOJu0YwP/tIBdjcSD1Z0Go2Ti1OLYGf7Q9Gd+QxOBAd8BM2uqPr0ftiS 4IB/TvbGQK1trqoCTDXistnKqaPu2AgAd10pitUq+Hbv/Wyalpv6xhUA/i2Dqh5j0WgIXJqTkgL gBP41Gnd1XcwqW0P0V4b+UZjBUbzwIPHP/lWX8BfV/Ed8ewrJl6zk/CgtXg5irGM2zPU= X-Gm-Gg: AR+sD13IywSIKOLwANOfm7mgTVN0H8p91PP/DE+7TnxbB+Co3hl19vzNjZGKZBSNyMd W4gv5V3OgUcoOAoJnkaeGCGa7Akzb2aFmpBz1ZRysz4OGcn5EuahXINc1U1FnrZ9qurK6pHr7o3 mjIEHOfIgAa32R/1NBsqUJzvW+SMUlbEVH8EatzLNM9V5/hxi9d1s85LcMcTHmq4KNOz/MxaA9m u4etAxZCu6jLncdbr8iUZxozU/TwOuk0WXdOZ0Bw7D4b2BktMurPwNxVq9FPlgX7klLgLMe3ci9 7M9Kc4krn0NlMcY9Zh55NNuwgDdjVV1CszXi661ESvbqJFhbT5ZMTUsLWP7FTvCM//8CzgAW6cN V6lnuqa3Ek0PJ46AtDDLgYTEih7M2qPp4xcpP X-Received: by 2002:a05:6a21:3a96:b0:3c3:935a:af2c with SMTP id adf61e73a8af0-3c92a51c2cfmr6593246637.3.1785676431427; Sun, 02 Aug 2026 06:13:51 -0700 (PDT) X-Received: by 2002:a05:6a21:3a96:b0:3c3:935a:af2c with SMTP id adf61e73a8af0-3c92a51c2cfmr6593220637.3.1785676430931; Sun, 02 Aug 2026 06:13:50 -0700 (PDT) Received: from hu-vdadhani-hyd.qualcomm.com ([202.46.23.25]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3153e06f8dbsm28303457eec.22.2026.08.02.06.13.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Aug 2026 06:13:50 -0700 (PDT) From: Viken Dadhaniya Date: Sun, 02 Aug 2026 18:43:31 +0530 Subject: [PATCH v2 2/2] i2c: qcom-target: Add driver for Qualcomm I2C target controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260802-i2c-qcom-slave-v2-2-27653118fa75@oss.qualcomm.com> References: <20260802-i2c-qcom-slave-v2-0-27653118fa75@oss.qualcomm.com> In-Reply-To: <20260802-i2c-qcom-slave-v2-0-27653118fa75@oss.qualcomm.com> To: Mukesh Kumar Savaliya , Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-arm-msm@vger.kernel.org, linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Viken Dadhaniya X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=ed25519-sha256; t=1785676418; l=22093; i=viken.dadhaniya@oss.qualcomm.com; s=20260324; h=from:subject:message-id; bh=x6kSr0aNgXnNuE3iiKV3J/ypVJgn8UqMYoiV4CsZ5UI=; b=Sw93AATN4qBBMfCBKYsk8QF6xy6eNtKQReArQGeHdZDX8LA0NyVFMecNjsnUWudxY7fGvPIq/ vDjeBHk7pDrDrtyLm3+IBxQEZ/4m/fImq4DB0v8KG7M4NNXP/m4Cjtu X-Developer-Key: i=viken.dadhaniya@oss.qualcomm.com; a=ed25519; pk=C39f+LOIGhh/02LQpT46TsUSXRvBn9qXC8Xb26KJ44Y= X-Proofpoint-ORIG-GUID: aahoBiMBn0BtyKg4KeOZdzXKpUfA5RNQ X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODAyMDExNiBTYWx0ZWRfXyMQydSM4H3sk UXaDgUtATTNswrZDOT7L0RCNSen7roCwqyk7BXgLtnen39B5o/4V0q4YYaPzNd3/T/atV+3ouok IWL2GYV15niKAcWCtMa1lhlmkcShjxXH2mvJqEgTdbjolAihN1+OKv5BnEad1nsvzgOC4//UPUd BsUD/FmNRDLcLHS4yxce+r4fOaRcHvHCZ3wEANXuumG6Iu7eWpLCi5tmjnPXtIgXpkSLzmr4zgE ACIaxfsxpg5QCeJvl4VJrs0Q7lSaeBZyuAXrexBM16yHpjntZkrCmuvjf52LbZdToYAunEAEoOx LBtPDmwzhgE+pPKberrtzOIL5VvDPjq0qAeTF9KFW9FYPP2Y2OK+rcBYCygXmfwt6GcYvlHPsDO tuEHDDDPHbg9I4ERPU3lSU7UMSlzitKJzlzA6nh+C6olWoM4YvMXC98JqyTh/GyV+UEtjnZaIAQ 7mIVMzxUEN01f0nrJ4g== X-Authority-Analysis: v=2.4 cv=TpfWQjXh c=1 sm=1 tr=0 ts=6a6f4290 cx=c_pps a=cmESyDAEBpBGqyK7t0alAg==:117 a=ZePRamnt/+rB5gQjfz0u9A==:17 a=IkcTkHD0fZMA:10 a=Sv0fKeRqtYgA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yx91gb_oNiZeI1HMLzn7:22 a=EUspDBNiAAAA:8 a=VwQbUJbxAAAA:8 a=6Aj5HnW1lPJNqB_X8VIA:9 a=yqRB-T0WfQLSyww9:21 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=1OuFwYUASf3TG4hYMiVC:22 X-Proofpoint-GUID: aahoBiMBn0BtyKg4KeOZdzXKpUfA5RNQ X-Proofpoint-Spam-Info: AW1haW4tMjYwODAyMDExNiBTYWx0ZWRfX0/bdUpe4RdHp 3opi3oYWsMlOvEH5YSVIjgGQA+QxMohBMBzuP1tklbQW5ETEZ1dsWhQ0NAg3Lhw3iwhGmWTKUzw lifHrMv40XpvG3PvkH+JTZH6+mOxHBw= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-02_04,2026-07-30_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 impostorscore=0 phishscore=0 spamscore=0 clxscore=1015 suspectscore=0 malwarescore=0 adultscore=0 bulkscore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608020116 QDU1000 and related Qualcomm SoCs include a dedicated I2C target controller that operates exclusively in target mode. The existing Qualcomm I2C controller drivers (GENI, QUP) are master-only and cannot serve systems where the SoC must respond as an I2C target on the bus. Register the controller with the Linux I2C slave framework via i2c_algorithm.reg_target and i2c_algorithm.unreg_target so that any standard slave backend (e.g. slave-24c02) can be attached at runtime via i2c_slave_register(). Handle IRQ events for RX FIFO service, clock stretching during read and write phases, STOP and repeated-start conditions, and error recovery with SW reset. Enable the required AHB and XO clocks, vote for interconnect bandwidth, and restore hardware state across suspend and resume using the noirq PM callbacks. Signed-off-by: Viken Dadhaniya --- MAINTAINERS | 9 + drivers/i2c/busses/Kconfig | 15 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-qcom-target.c | 560 +++++++++++++++++++++++++++++++= ++++ 4 files changed, 585 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fe67f7bfa44c..c3f273b0002b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22380,6 +22380,15 @@ S: Maintained F: Documentation/devicetree/bindings/i2c/qcom,i2c-geni-qcom.yaml F: drivers/i2c/busses/i2c-qcom-geni.c =20 +QUALCOMM I2C TARGET CONTROLLER DRIVER +M: Viken Dadhaniya +M: Mukesh Kumar Savaliya +L: linux-i2c@vger.kernel.org +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/i2c/qcom,i2c-target.yaml +F: drivers/i2c/busses/i2c-qcom-target.c + QUALCOMM I2C CCI DRIVER M: Loic Poulain M: Robert Foss diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d7b89508311f..2e18238e0ae6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1070,6 +1070,21 @@ config I2C_QCOM_GENI This driver can also be built as a module. If so, the module will be called i2c-qcom-geni. =20 +config I2C_QCOM_TARGET + tristate "Qualcomm I2C target controller" + depends on ARCH_QCOM || COMPILE_TEST + depends on COMMON_CLK + depends on INTERCONNECT + select I2C_SLAVE + help + This driver supports I2C target mode on Qualcomm Technologies + SoCs. If you say yes to this option, support will be included + for the built-in I2C target controller on QDU1000 and other + compatible Qualcomm SoCs. + + This driver can also be built as a module. If so, the module + will be called i2c-qcom-target. + config I2C_QUP tristate "Qualcomm QUP based I2C controller" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3755c54b3d82..ab3070cdb144 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -101,6 +101,7 @@ obj-$(CONFIG_I2C_PXA) +=3D i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) +=3D i2c-pxa-pci.o obj-$(CONFIG_I2C_QCOM_CCI) +=3D i2c-qcom-cci.o obj-$(CONFIG_I2C_QCOM_GENI) +=3D i2c-qcom-geni.o +obj-$(CONFIG_I2C_QCOM_TARGET) +=3D i2c-qcom-target.o obj-$(CONFIG_I2C_QUP) +=3D i2c-qup.o obj-$(CONFIG_I2C_RIIC) +=3D i2c-riic.o obj-$(CONFIG_I2C_RK3X) +=3D i2c-rk3x.o diff --git a/drivers/i2c/busses/i2c-qcom-target.c b/drivers/i2c/busses/i2c-= qcom-target.c new file mode 100644 index 000000000000..79b0b9ff7b9b --- /dev/null +++ b/drivers/i2c/busses/i2c-qcom-target.c @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register offsets */ +#define I2C_S_DEVICE_ADDR 0x00 +#define I2C_S_IRQ_STATUS 0x08 +#define I2C_S_IRQ_CLR 0x0C +#define I2C_S_IRQ_EN 0x10 +#define I2C_S_CONFIG 0x18 +#define I2C_S_CONTROL 0x1C +#define I2C_S_FIFOS_STATUS 0x20 +#define I2C_S_TX_FIFO 0x24 +#define I2C_S_RX_FIFO 0x28 +#define I2C_S_DEBUG_REG1 0x3C +#define I2C_S_DEBUG_REG2 0x40 +#define I2C_S_SW_RESET_REG 0x4C +#define I2C_S_CLK_LOW_TIMEOUT 0x50 +#define I2C_S_CLK_RELEASE_DELAY_CNT_VAL 0x54 +#define I2C_S_SDA_HOLD_CNT_VAL 0x58 + +/* I2C_S_CONFIG register fields */ +#define I2C_S_CORE_EN BIT(0) + +/* I2C_S_CONTROL register fields */ +#define CLEAR_RX_FIFO BIT(0) +#define CLEAR_TX_FIFO BIT(1) +#define NACK BIT(2) +#define ACK_RESUME BIT(3) + +/* I2C_S_SW_RESET_REG register fields */ +#define SW_RESET BIT(0) + +/* I2C_S_FIFOS_STATUS register fields */ +#define RX_FIFO_COUNT_MASK GENMASK(31, 16) + +/* Interconnect bandwidth vote in bytes per second */ +#define APPS_PROC_TO_I2C_TARGET_VOTE 1190000 + +/** + * enum qcom_i2c_target_irq - IRQ bit positions in I2C_S_IRQ_STATUS + * @STOP_DETECTED: I2C stop condition detected on the bus + * @RX_FIFO_FULL: receive FIFO has reached capacity + * @TX_FIFO_EMPTY: transmit FIFO is empty + * @RX_DATA_AVAIL: receive data is available in the RX FIFO + * @CLOCK_LOW_TIMEOUT: SCL held low longer than the configured timeout + * @STRCH_WR: clock stretching during a write (Rx) phase + * @STRCH_RD: clock stretching during a read (Tx) phase + * @GCA_DETECTED: general call address detected (not used) + * @ERR_CONDITION: unexpected start or stop bit detected (error) + * @RESTART_DETECTED: repeated start condition detected + */ +enum qcom_i2c_target_irq { + STOP_DETECTED, + RX_FIFO_FULL, + TX_FIFO_EMPTY, + RX_DATA_AVAIL, + CLOCK_LOW_TIMEOUT, + STRCH_WR, + STRCH_RD, + GCA_DETECTED, + ERR_CONDITION, + RESTART_DETECTED, +}; + +/* + * TX_FIFO_EMPTY is excluded: this driver fills the TX FIFO one byte at a + * time in response to STRCH_RD (clock-stretch during read phase), so + * TX_FIFO_EMPTY adds no value and would double the interrupt rate. + * GCA (general call address) is unsupported. + */ +#define QCOM_I2C_TARGET_ALL_IRQ (GENMASK(RESTART_DETECTED, STOP_DETECTED) \ + & ~(BIT(GCA_DETECTED) | BIT(TX_FIFO_EMPTY))) + +/* Bit indices for the status bitmask, used with set_bit/test_bit/clear_bi= t */ +enum qcom_i2c_target_status { + READ_IN_PROGRESS, + WRITE_IN_PROGRESS, +}; + +/** + * struct qcom_i2c_target - Qualcomm I2C target controller private data + * @dev: driver model device node + * @base: base address of HW registers + * @adap: I2C adapter (slave mode) + * @ahb_clk: AHB bus clock + * @xo_clk: XO reference clock + * @icc_path: interconnect bandwidth path + * @slave: currently registered slave backend client; written only + * under disable_irq() in reg_slave()/unreg_slave() so the + * ISR sees a stable pointer for its entire execution + * @status: bitmask of enum qcom_i2c_target_status flags; must be + * unsigned long for set_bit/test_bit/clear_bit; accessed + * only from the ISR and from reg_slave()/unreg_slave() + * under disable_irq(), so no additional lock is needed + * @irq: interrupt line number + */ +struct qcom_i2c_target { + struct device *dev; + void __iomem *base; + struct i2c_adapter adap; + struct clk *ahb_clk; + struct clk *xo_clk; + struct icc_path *icc_path; + struct i2c_client *slave; + unsigned long status; + int irq; +}; + +static void qcom_i2c_target_dump_regs(struct qcom_i2c_target *target) +{ + dev_dbg(target->dev, "I2C_S_DEVICE_ADDR: 0x%x\n", + readl_relaxed(target->base + I2C_S_DEVICE_ADDR)); + dev_dbg(target->dev, "I2C_S_IRQ_STATUS: 0x%x\n", + readl_relaxed(target->base + I2C_S_IRQ_STATUS)); + dev_dbg(target->dev, "I2C_S_CONFIG: 0x%x\n", + readl_relaxed(target->base + I2C_S_CONFIG)); + dev_dbg(target->dev, "I2C_S_IRQ_EN: 0x%x\n", + readl_relaxed(target->base + I2C_S_IRQ_EN)); + dev_dbg(target->dev, "I2C_S_FIFOS_STATUS: 0x%x\n", + readl_relaxed(target->base + I2C_S_FIFOS_STATUS)); + dev_dbg(target->dev, "I2C_S_DEBUG_REG1: 0x%x\n", + readl_relaxed(target->base + I2C_S_DEBUG_REG1)); + dev_dbg(target->dev, "I2C_S_DEBUG_REG2: 0x%x\n", + readl_relaxed(target->base + I2C_S_DEBUG_REG2)); + dev_dbg(target->dev, "I2C_S_CLK_LOW_TIMEOUT: 0x%x\n", + readl_relaxed(target->base + I2C_S_CLK_LOW_TIMEOUT)); + dev_dbg(target->dev, "I2C_S_CLK_RELEASE_DELAY_CNT_VAL: 0x%x\n", + readl_relaxed(target->base + I2C_S_CLK_RELEASE_DELAY_CNT_VAL)); + dev_dbg(target->dev, "I2C_S_SDA_HOLD_CNT_VAL: 0x%x\n", + readl_relaxed(target->base + I2C_S_SDA_HOLD_CNT_VAL)); +} + + +static void qcom_i2c_target_hw_init(struct qcom_i2c_target *target) +{ + dev_dbg(target->dev, "HW init: resetting FIFOs, enabling IRQs and core\n"= ); + writel(CLEAR_TX_FIFO | CLEAR_RX_FIFO, target->base + I2C_S_CONTROL); + writel(QCOM_I2C_TARGET_ALL_IRQ, target->base + I2C_S_IRQ_EN); + writel(I2C_S_CORE_EN, target->base + I2C_S_CONFIG); +} + +static void qcom_i2c_target_write_requested(struct qcom_i2c_target *target) +{ + u8 val =3D 0; + + if (!test_bit(WRITE_IN_PROGRESS, &target->status)) { + dev_dbg(target->dev, "Write phase started\n"); + set_bit(WRITE_IN_PROGRESS, &target->status); + i2c_slave_event(target->slave, I2C_SLAVE_WRITE_REQUESTED, &val); + } +} + +static int qcom_i2c_target_drain_rx_fifo(struct qcom_i2c_target *target) +{ + unsigned int rx_count; + int i, ret =3D 0; + u8 val; + + rx_count =3D FIELD_GET(RX_FIFO_COUNT_MASK, + readl_relaxed(target->base + I2C_S_FIFOS_STATUS)); + + for (i =3D 0; i < rx_count; i++) { + val =3D (u8)readl_relaxed(target->base + I2C_S_RX_FIFO); + dev_dbg(target->dev, "Data from RX FIFO: 0x%x\n", val); + ret =3D i2c_slave_event(target->slave, I2C_SLAVE_WRITE_RECEIVED, &val); + if (ret) + break; + } + + return ret; +} + +static void qcom_i2c_target_hw_reset(struct qcom_i2c_target *target) +{ + /* Clear error bits before SW_RESET; the reset may not be instantaneous */ + writel(BIT(ERR_CONDITION) | BIT(CLOCK_LOW_TIMEOUT), + target->base + I2C_S_IRQ_CLR); + writel(SW_RESET, target->base + I2C_S_SW_RESET_REG); + qcom_i2c_target_hw_init(target); + writel(target->slave->addr, target->base + I2C_S_DEVICE_ADDR); +} + +static irqreturn_t qcom_i2c_target_handle_error(struct qcom_i2c_target *ta= rget, + u32 irq_stat) +{ + u8 val =3D 0; + + if (irq_stat & BIT(ERR_CONDITION)) + dev_err(target->dev, "Error condition: unexpected Start/Stop bits\n"); + else + dev_err(target->dev, "Clock low timeout\n"); + qcom_i2c_target_dump_regs(target); + qcom_i2c_target_hw_reset(target); + i2c_slave_event(target->slave, I2C_SLAVE_STOP, &val); + target->status =3D 0; + return IRQ_HANDLED; +} + +static irqreturn_t qcom_i2c_target_handle_stop(struct qcom_i2c_target *tar= get, + u32 irq_stat) +{ + u8 val =3D 0; + + dev_dbg(target->dev, "Stop bit detected\n"); + /* + * Short-write corner case: WRITE_IN_PROGRESS was never set because + * no RX_DATA_AVAIL or STRCH_WR fired before STOP. Do not call + * qcom_i2c_target_write_requested() here =E2=80=94 STOP ends the transac= tion + * so setting WRITE_IN_PROGRESS now would leave a stale bit after + * target->status is cleared below. + */ + if (!test_bit(WRITE_IN_PROGRESS, &target->status)) { + unsigned int rx_count; + + rx_count =3D FIELD_GET(RX_FIFO_COUNT_MASK, + readl_relaxed(target->base + I2C_S_FIFOS_STATUS)); + if (rx_count) + i2c_slave_event(target->slave, I2C_SLAVE_WRITE_REQUESTED, + &val); + } + qcom_i2c_target_drain_rx_fifo(target); + i2c_slave_event(target->slave, I2C_SLAVE_STOP, &val); + target->status =3D 0; + writel(CLEAR_RX_FIFO, target->base + I2C_S_CONTROL); + /* + * STOP terminates the transaction, so any other Rx or clock + * stretch bits latched in this same status read have already + * been serviced by the drain above or are now stale. Ack the + * whole word rather than just STOP_DETECTED; clearing only STOP + * would leave those bits set and immediately re-enter the + * handler, which for a co-asserted STRCH_RD would push a stale + * byte into the TX FIFO. + */ + writel(irq_stat, target->base + I2C_S_IRQ_CLR); + return IRQ_HANDLED; +} + +static void qcom_i2c_target_handle_rx_data(struct qcom_i2c_target *target, + u32 rx_irq_bits) +{ + int ret; + + dev_dbg(target->dev, "Rx data event (rx_irq_bits=3D0x%x)\n", rx_irq_bits); + qcom_i2c_target_write_requested(target); + ret =3D qcom_i2c_target_drain_rx_fifo(target); + if (ret) + dev_dbg(target->dev, "Backend requested NACK\n"); + writel(ret ? NACK | CLEAR_RX_FIFO : ACK_RESUME, + target->base + I2C_S_CONTROL); + writel(rx_irq_bits, target->base + I2C_S_IRQ_CLR); +} + +static void qcom_i2c_target_handle_strch_rd(struct qcom_i2c_target *target) +{ + enum i2c_slave_event event =3D I2C_SLAVE_READ_PROCESSED; + u8 val =3D 0; + + dev_dbg(target->dev, "Clock stretching during read (Tx) phase\n"); + if (!test_bit(READ_IN_PROGRESS, &target->status)) { + set_bit(READ_IN_PROGRESS, &target->status); + /* Repeated-start: master switched direction from write to read */ + clear_bit(WRITE_IN_PROGRESS, &target->status); + event =3D I2C_SLAVE_READ_REQUESTED; + } + i2c_slave_event(target->slave, event, &val); + dev_dbg(target->dev, "Data to TX FIFO: 0x%x\n", val); + writel(val, target->base + I2C_S_TX_FIFO); + writel(ACK_RESUME, target->base + I2C_S_CONTROL); + writel(BIT(STRCH_RD), target->base + I2C_S_IRQ_CLR); +} + +static irqreturn_t qcom_i2c_target_irq(int irq, void *dev) +{ + struct qcom_i2c_target *target =3D dev; + u32 irq_stat, rx_bits; + + /* + * Dispatch priority (highest first): + * ERR_CONDITION / CLOCK_LOW_TIMEOUT =E2=80=94 hardware error, trigger= s SW reset + * STOP_DETECTED =E2=80=94 end of transaction, cle= ars all state + * STRCH_RD =E2=80=94 read-phase data supply + * RX_FIFO_FULL / RX_DATA_AVAIL / + * STRCH_WR =E2=80=94 write-phase Rx, coalesc= ed into one drain + * RESTART_DETECTED =E2=80=94 repeated start, resets = state + */ + irq_stat =3D readl_relaxed(target->base + I2C_S_IRQ_STATUS); + if (!irq_stat) + return IRQ_NONE; + + dev_dbg(target->dev, "IRQ status: 0x%x\n", irq_stat); + + /* + * Load target->slave once. Both reg_slave() and unreg_slave() disable + * the IRQ before writing the pointer, so it cannot change while this + * handler runs. Sub-handlers may dereference target->slave directly. + */ + if (!READ_ONCE(target->slave)) { + writel(irq_stat, target->base + I2C_S_IRQ_CLR); + return IRQ_HANDLED; + } + + if (irq_stat & (BIT(ERR_CONDITION) | BIT(CLOCK_LOW_TIMEOUT))) + return qcom_i2c_target_handle_error(target, irq_stat); + + if (irq_stat & BIT(STOP_DETECTED)) + return qcom_i2c_target_handle_stop(target, irq_stat); + + if (irq_stat & BIT(STRCH_RD)) + qcom_i2c_target_handle_strch_rd(target); + + /* + * Coalesce all write-phase Rx bits into a single drain+ACK. When the + * RX FIFO fills at threshold, RX_FIFO_FULL, RX_DATA_AVAIL and STRCH_WR + * can all assert in the same irq_stat snapshot. Pass the combined mask + * so ACK_RESUME is written exactly once and all bits are cleared togethe= r. + */ + rx_bits =3D irq_stat & (BIT(RX_FIFO_FULL) | BIT(RX_DATA_AVAIL) | + BIT(STRCH_WR)); + if (rx_bits) + qcom_i2c_target_handle_rx_data(target, rx_bits); + + if (irq_stat & BIT(RESTART_DETECTED)) { + dev_dbg(target->dev, "Repeated start bit detected\n"); + target->status =3D 0; + writel(ACK_RESUME, target->base + I2C_S_CONTROL); + writel(BIT(RESTART_DETECTED), target->base + I2C_S_IRQ_CLR); + } + + return IRQ_HANDLED; +} + +static int qcom_i2c_target_reg_slave(struct i2c_client *slave) +{ + struct qcom_i2c_target *target =3D i2c_get_adapdata(slave->adapter); + + if (target->slave) + return -EBUSY; + + if (slave->flags & I2C_CLIENT_TEN) + return -EAFNOSUPPORT; + + disable_irq(target->irq); + WRITE_ONCE(target->slave, slave); + writel(slave->addr, target->base + I2C_S_DEVICE_ADDR); + enable_irq(target->irq); + + return 0; +} + +static int qcom_i2c_target_unreg_slave(struct i2c_client *slave) +{ + struct qcom_i2c_target *target =3D i2c_get_adapdata(slave->adapter); + + if (!target->slave) + return -EINVAL; + disable_irq(target->irq); + WRITE_ONCE(target->slave, NULL); + target->status =3D 0; + writel(0, target->base + I2C_S_DEVICE_ADDR); + enable_irq(target->irq); + + return 0; +} + +static int qcom_i2c_target_icc_init(struct qcom_i2c_target *target) +{ + int ret; + + target->icc_path =3D devm_of_icc_get(target->dev, "i2c"); + if (IS_ERR(target->icc_path)) + return dev_err_probe(target->dev, PTR_ERR(target->icc_path), + "failed to get ICC path\n"); + + /* + * The controller only needs interconnect bandwidth while it is + * powered. The vote is placed here and across resume with + * icc_set_bw(), and dropped with icc_set_bw(path, 0, 0) on suspend + * and remove, so the vote and unvote are always symmetric. + */ + ret =3D icc_set_bw(target->icc_path, APPS_PROC_TO_I2C_TARGET_VOTE, + APPS_PROC_TO_I2C_TARGET_VOTE); + if (ret) + return dev_err_probe(target->dev, ret, "icc_set_bw failed\n"); + + return 0; +} + +static u32 qcom_i2c_target_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SLAVE; +} + +static const struct i2c_algorithm qcom_i2c_target_algo =3D { + .reg_target =3D qcom_i2c_target_reg_slave, + .unreg_target =3D qcom_i2c_target_unreg_slave, + .functionality =3D qcom_i2c_target_func, +}; + +static int qcom_i2c_target_adap_init(struct qcom_i2c_target *target) +{ + target->adap.algo =3D &qcom_i2c_target_algo; + target->adap.dev.parent =3D target->dev; + target->adap.dev.of_node =3D target->dev->of_node; + strscpy(target->adap.name, "qcom-i2c-target", + sizeof(target->adap.name)); + i2c_set_adapdata(&target->adap, target); + + return i2c_add_adapter(&target->adap); +} + +static int qcom_i2c_target_probe(struct platform_device *pdev) +{ + struct qcom_i2c_target *target; + struct device *dev =3D &pdev->dev; + int ret; + + target =3D devm_kzalloc(dev, sizeof(*target), GFP_KERNEL); + if (!target) + return -ENOMEM; + + target->dev =3D dev; + + target->base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(target->base)) + return dev_err_probe(dev, PTR_ERR(target->base), + "failed to map registers\n"); + + target->xo_clk =3D devm_clk_get_enabled(dev, "xo"); + if (IS_ERR(target->xo_clk)) + return dev_err_probe(dev, PTR_ERR(target->xo_clk), + "failed to get and enable XO clock\n"); + + target->ahb_clk =3D devm_clk_get_enabled(dev, "ahb"); + if (IS_ERR(target->ahb_clk)) + return dev_err_probe(dev, PTR_ERR(target->ahb_clk), + "failed to get and enable AHB clock\n"); + + target->irq =3D platform_get_irq(pdev, 0); + if (target->irq < 0) + return target->irq; + + ret =3D qcom_i2c_target_icc_init(target); + if (ret) + return ret; + + ret =3D devm_request_irq(dev, target->irq, qcom_i2c_target_irq, 0, + dev_name(dev), target); + if (ret) + return dev_err_probe(dev, ret, "request_irq failed for IRQ %d\n", + target->irq); + + qcom_i2c_target_hw_init(target); + + platform_set_drvdata(pdev, target); + + ret =3D qcom_i2c_target_adap_init(target); + if (ret) + return dev_err_probe(dev, ret, "i2c_add_adapter failed\n"); + + return 0; +} + +static void qcom_i2c_target_remove(struct platform_device *pdev) +{ + struct qcom_i2c_target *target =3D platform_get_drvdata(pdev); + + disable_irq(target->irq); + i2c_del_adapter(&target->adap); + writel(0, target->base + I2C_S_CONFIG); + icc_set_bw(target->icc_path, 0, 0); +} + +static int qcom_i2c_target_suspend(struct device *dev) +{ + struct qcom_i2c_target *target =3D dev_get_drvdata(dev); + int ret; + + ret =3D icc_set_bw(target->icc_path, 0, 0); + if (ret) + dev_err(dev, "icc_set_bw failed on suspend: %d\n", ret); + + clk_disable_unprepare(target->xo_clk); + clk_disable_unprepare(target->ahb_clk); + + return 0; +} + +static int qcom_i2c_target_resume(struct device *dev) +{ + struct qcom_i2c_target *target =3D dev_get_drvdata(dev); + int ret; + + ret =3D clk_prepare_enable(target->ahb_clk); + if (ret) { + dev_err(dev, "failed to enable AHB clock\n"); + return ret; + } + + ret =3D clk_prepare_enable(target->xo_clk); + if (ret) { + dev_err(dev, "failed to enable XO clock\n"); + goto err_disable_ahb; + } + + ret =3D icc_set_bw(target->icc_path, APPS_PROC_TO_I2C_TARGET_VOTE, + APPS_PROC_TO_I2C_TARGET_VOTE); + if (ret) { + dev_err(dev, "icc_set_bw failed\n"); + goto err_disable_xo; + } + + qcom_i2c_target_hw_init(target); + if (target->slave) + writel(target->slave->addr, target->base + I2C_S_DEVICE_ADDR); + + return 0; + +err_disable_xo: + clk_disable_unprepare(target->xo_clk); +err_disable_ahb: + clk_disable_unprepare(target->ahb_clk); + return ret; +} + +static const struct dev_pm_ops qcom_i2c_target_pm_ops =3D { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_i2c_target_suspend, + qcom_i2c_target_resume) +}; + +static const struct of_device_id qcom_i2c_target_dt_match[] =3D { + { .compatible =3D "qcom,qdu1000-i2c-target" }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_i2c_target_dt_match); + +static struct platform_driver qcom_i2c_target_driver =3D { + .driver =3D { + .name =3D "qcom-i2c-target", + .pm =3D &qcom_i2c_target_pm_ops, + .of_match_table =3D qcom_i2c_target_dt_match, + }, + .probe =3D qcom_i2c_target_probe, + .remove =3D qcom_i2c_target_remove, +}; +module_platform_driver(qcom_i2c_target_driver); + +MODULE_DESCRIPTION("Qualcomm I2C target controller driver"); +MODULE_AUTHOR("Viken Dadhaniya "); +MODULE_LICENSE("GPL"); --=20 2.34.1