From nobody Fri Apr 3 22:33:01 2026 Received: from SJ2PR03CU001.outbound.protection.outlook.com (mail-westusazon11012068.outbound.protection.outlook.com [52.101.43.68]) (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 C88F8363C7F; Mon, 23 Mar 2026 07:46:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.43.68 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251986; cv=fail; b=XHVSsfTRs6eBn5PdCMagxvEuq6yz1ii2HePeAq5kOFh52Lu+7cbu3WtNpkAefNsLPKpojmrvl50k8aHbr3tqxI73y5QncPjhDjqLbxVMN5I7KjRXEYtUwccNEDswSe+itVfdmjseD3AquKAFR/eZqbzlixt8z4fmzbmzRJ7f2Yo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251986; c=relaxed/simple; bh=o15lnZlTR5B+RzPeunvYRaRk12m7lVOOTsQ58yR5uTM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CdoWV1EEFtEVcwPkm2iUfuolgRdnktt5JHG/b/HAAuB2nu8kkJi8aLjjmbtB6rEASNgZyBrnlAV01iH2HEiEPTCFnb1XdpXURacbJlRR3BhSq2HWgR3BsZ2GakoutSw/zdzKgXUACg/H6CNoCT+5N55f940+gQq1GgVe/DdNF1A= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=4X2QpGSb; arc=fail smtp.client-ip=52.101.43.68 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="4X2QpGSb" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=A5H7tDdZSncYbD9s92iPreQwcoKtNqbQXcg13kplDWPcuKQnG0m40TkShSOz3aS7LxVf/VGngdFeRUFhw3BsZZwIyoeQiasXeCu5E/WZZtWbdeA8VYT+3y6wZyCzdb6zYnDY5+hSET845dvU/wmhP9wu1JGFpcWYhWWnGc2C97Q/E9oyo9a2/BAxxUMcc6u460oWXyVDsm3g+SZ0qHv5N7//1N/tmgDGNfPfWjTuoYxo2mt5AIlZHAA8Nm++T18b7YpRMDC9dgWE4xuCPfKQ0bQA28DWWm5dnb5ixm4WqiZ5IL8JpnUiTCrhUMJ2rl0mCGEAdiWnr8OhTIDRJGu6Rw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=kcjsSbZuqFX1KVGm1LOHervGke2vor87A3Vxf0iZhRQ=; b=chKVNUYirWmFM+h6eLnAZleYqypm0GrmmexXwzWuF6THuCJPkxKZDzu4rp0KFVQEawDwtkLnL7pE1T5+jJ9Jrfj7KIDPkJntkOl92JF/n9RldfAiHojCeSPihAzFXYvLOoxZVqzqdidx3wyE7C52s9RTaeVF/ekMgnuPEf/mgCpWAJ8JfXfAfWdiamW4h23DF8X+h+pdFqRdsaUV/09LiSssP/Vwtxg39IAUPda20RTSHobR/+laQl42bzclLUZU8D9DO7sXWIXodmvLsXguLnQa4b3MRyMOqQSfmx3tRmzxQj06koAswIxPM9rMl9VK2PM5W60Ph7gU8CCKcxy0/Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=kcjsSbZuqFX1KVGm1LOHervGke2vor87A3Vxf0iZhRQ=; b=4X2QpGSb6R3bZAyZujDAbbXHEPjwKe20rTBZHGqgFyNr9ICO30yzuhkpD4JLCw3cyuORUtaOCqre7WoBkCkFNRdIjlMgiD/2Xu6pIx831V5hcnWSY+XIQHvb+wVUBCxEedswUj4FsAVfRkqJv8VlzAjRvDWcaaJE07XLutcGeZ0= Received: from BL0PR05CA0003.namprd05.prod.outlook.com (2603:10b6:208:91::13) by BN3PR12MB9595.namprd12.prod.outlook.com (2603:10b6:408:2cb::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.20; Mon, 23 Mar 2026 07:46:09 +0000 Received: from BL6PEPF0001AB4E.namprd04.prod.outlook.com (2603:10b6:208:91:cafe::d9) by BL0PR05CA0003.outlook.office365.com (2603:10b6:208:91::13) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9723.31 via Frontend Transport; Mon, 23 Mar 2026 07:46:09 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb07.amd.com; pr=C Received: from satlexmb07.amd.com (165.204.84.17) by BL6PEPF0001AB4E.mail.protection.outlook.com (10.167.242.72) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9723.19 via Frontend Transport; Mon, 23 Mar 2026 07:46:09 +0000 Received: from satlexmb10.amd.com (10.181.42.219) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Mon, 23 Mar 2026 02:46:07 -0500 Received: from satlexmb07.amd.com (10.181.42.216) by satlexmb10.amd.com (10.181.42.219) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Mon, 23 Mar 2026 02:46:06 -0500 Received: from xhdlakshmis40.xilinx.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Mon, 23 Mar 2026 02:46:03 -0500 From: Sai Krishna Potthuri To: Jonathan Cameron , David Lechner , Nuno Sa , Andy Shevchenko , Michal Simek , Rob Herring , Krzysztof Kozlowski , Conor Dooley CC: , , , , , , Sai Krishna Potthuri Subject: [PATCH v2 1/4] iio: adc: xilinx-xadc: Split driver into core and platform files Date: Mon, 23 Mar 2026 13:15:02 +0530 Message-ID: <20260323074505.3853353-2-sai.krishna.potthuri@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> References: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BL6PEPF0001AB4E:EE_|BN3PR12MB9595:EE_ X-MS-Office365-Filtering-Correlation-Id: 7f0c7b7e-8ae3-4c5e-43bc-08de88b03f58 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|1800799024|36860700016|7416014|376014|13003099007|22082099003|56012099003|18002099003; X-Microsoft-Antispam-Message-Info: uk3Z7mT9taOZqcg4iOPcrddsiMh4s9I6PHawvBQAj3/u60dUc6aw+P1vbZfy6vwfnSou9tznW7PPPQ91WwgMMcXjrJ3OSR1AeVbEKLIWU6Ph3XuwnMvEHgWxuHCkHOx0zIdryKvWTTq++Y8jwZ5gOm5ZhwVSIlKxyHu53iuw9UUc120WPt2TH5O7rUtvFCc+4vnlIkVgCB8qGDaBwEiK+xzfc7KkFKc8anV/0WSoV4pdw9R/s0ieC4T16JN8w6HffuVrbb0xs2fZGPWSKO4//YA1iEGFDe99BKoKo1GQMlqX0xNMeDuf18dcvnv1MU+tIBjhzTXjb0kFAyjy87HJqTxTTCqb3S95WZX5bxQuKt3me+756ORURWjHh19MabD2MyhOdssnH9zx5aIDucD0wVAtDXBT2li0oUnjeScb5QliwYDV9fr2ZUKHHb9NJTLhyW7p331WLT8HVZkxD395SqPLV3tK4HbnX6l0SC1EROABkZRP2My76bhuedAIihCnBfdXg0SvnZ4pu20GgV96BqZdtashCwXGoS9AdkFdZb6PpgTfvWwgLtB9bwjUjPtlIpnnStVWiARg27lKtOU75//SKJ+qRe3bLqV/H8crZgjhev2vR9WMQYX4Qk1gAhuj6MkVdgOWMo1tuPWiSLoazVMAV4Y4Wzku9CH/xocy8QMpfAzaHXSTki90YO7DjXKb1TjKbI5sqgQpc4nJNZtey26CFZkQ5OPPGWhUWo5LDzNTz1VUQvAJpk6USm0X9P5MHMJ85+XuOxjT0phcBH3MQg== X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:satlexmb07.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(1800799024)(36860700016)(7416014)(376014)(13003099007)(22082099003)(56012099003)(18002099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: Jk4TFitBaNtFZiSlv0FYc5EbtdBJY5f/8RKAy0AwBjRb5DVrN1kNw1zQlNZmO3fYLatmtM4Yf+IIVREmbJ6bru42oN73PeA38vU1arAw10cfRg7RYo27WB07t63XaKkos/BrgICNMKtnVsYw4YsufppJJvpjWY5vYWY+TYnY2wPjzbbm7/CxMyvvRg4gm1mqWJg05507IjWwCRCfAO5fropN6F0RpCff6AaifngS137C7yDoABT0gtaB+5wqn4UMjRssUdDgjUFuSkQR5ZAHvTtwCv/J5QcyFCffJa8qrycNk0dAAwn7kcwx4RmBCWIeAJCnW1tP3PT2S7mvOXCpOmQRju0LdIPknJpq9dRTPGW/OJoETiEp1Hx88AJp0EuIkUDrjRcdh40FtxMfEUbR3EmjwSzDTzAu9NDQEAgO8Nb76iZ1dKNmvDkRww6xgqof X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Mar 2026 07:46:09.1198 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7f0c7b7e-8ae3-4c5e-43bc-08de88b03f58 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[satlexmb07.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BL6PEPF0001AB4E.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN3PR12MB9595 Content-Type: text/plain; charset="utf-8" Split the xilinx-xadc-core.c into separate core and platform specific files to prepare for I2C interface support. xilinx-xadc-core.c is reorganized as follows: xilinx-xadc-core.c: - Platform-independent IIO/ADC operations - Channel definitions and management - Buffer and trigger management - Device tree parsing xilinx-xadc-platform.c: - ZYNQ platform (FIFO-based) register access and interrupt handling - AXI platform (memory-mapped) register access and interrupt handling - Platform-specific setup and configuration - Platform device probe function Update Kconfig to introduce XILINX_XADC_CORE as a helper module selected by XILINX_XADC and update Makefile to build the split modules: - xilinx-xadc-common.o (core + events) - xilinx-xadc-platform.o (platform-specific) Reorganized the code and No behavioral changes. Signed-off-by: Sai Krishna Potthuri --- drivers/iio/adc/Kconfig | 8 +- drivers/iio/adc/Makefile | 5 +- drivers/iio/adc/xilinx-xadc-core.c | 790 +++---------------------- drivers/iio/adc/xilinx-xadc-platform.c | 665 +++++++++++++++++++++ drivers/iio/adc/xilinx-xadc.h | 30 + 5 files changed, 779 insertions(+), 719 deletions(-) create mode 100644 drivers/iio/adc/xilinx-xadc-platform.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index ea3ba1397392..a4a7556f4016 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1744,11 +1744,15 @@ config VIPERBOARD_ADC To compile this driver as a module, choose M here: the module will be called viperboard_adc. =20 +config XILINX_XADC_CORE + tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + config XILINX_XADC tristate "Xilinx XADC driver" depends on HAS_IOMEM - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER + select XILINX_XADC_CORE help Say yes here to have support for the Xilinx 7 Series XADC or UltraScale/UltraScale+ System Management Wizard. diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 09ae6edb2650..1b05176f0098 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -154,5 +154,6 @@ obj-$(CONFIG_TWL6030_GPADC) +=3D twl6030-gpadc.o obj-$(CONFIG_VF610_ADC) +=3D vf610_adc.o obj-$(CONFIG_VIPERBOARD_ADC) +=3D viperboard_adc.o obj-$(CONFIG_XILINX_AMS) +=3D xilinx-ams.o -xilinx-xadc-y :=3D xilinx-xadc-core.o xilinx-xadc-events.o -obj-$(CONFIG_XILINX_XADC) +=3D xilinx-xadc.o +xilinx-xadc-common-y :=3D xilinx-xadc-core.o xilinx-xadc-events.o +obj-$(CONFIG_XILINX_XADC_CORE) +=3D xilinx-xadc-common.o +obj-$(CONFIG_XILINX_XADC) +=3D xilinx-xadc-platform.o diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xa= dc-core.c index e257c1b94a5f..268e46e5349c 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -11,588 +11,37 @@ * - AXI XADC interface: Xilinx PG019 */ =20 -#include #include #include #include #include #include -#include #include -#include -#include #include #include -#include =20 #include #include #include -#include #include #include #include =20 #include "xilinx-xadc.h" =20 -static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT =3D 500; - -/* ZYNQ register definitions */ -#define XADC_ZYNQ_REG_CFG 0x00 -#define XADC_ZYNQ_REG_INTSTS 0x04 -#define XADC_ZYNQ_REG_INTMSK 0x08 -#define XADC_ZYNQ_REG_STATUS 0x0c -#define XADC_ZYNQ_REG_CFIFO 0x10 -#define XADC_ZYNQ_REG_DFIFO 0x14 -#define XADC_ZYNQ_REG_CTL 0x18 - -#define XADC_ZYNQ_CFG_ENABLE BIT(31) -#define XADC_ZYNQ_CFG_CFIFOTH_MASK (0xf << 20) -#define XADC_ZYNQ_CFG_CFIFOTH_OFFSET 20 -#define XADC_ZYNQ_CFG_DFIFOTH_MASK (0xf << 16) -#define XADC_ZYNQ_CFG_DFIFOTH_OFFSET 16 -#define XADC_ZYNQ_CFG_WEDGE BIT(13) -#define XADC_ZYNQ_CFG_REDGE BIT(12) -#define XADC_ZYNQ_CFG_TCKRATE_MASK (0x3 << 8) -#define XADC_ZYNQ_CFG_TCKRATE_DIV2 (0x0 << 8) -#define XADC_ZYNQ_CFG_TCKRATE_DIV4 (0x1 << 8) -#define XADC_ZYNQ_CFG_TCKRATE_DIV8 (0x2 << 8) -#define XADC_ZYNQ_CFG_TCKRATE_DIV16 (0x3 << 8) -#define XADC_ZYNQ_CFG_IGAP_MASK 0x1f -#define XADC_ZYNQ_CFG_IGAP(x) (x) - -#define XADC_ZYNQ_INT_CFIFO_LTH BIT(9) -#define XADC_ZYNQ_INT_DFIFO_GTH BIT(8) -#define XADC_ZYNQ_INT_ALARM_MASK 0xff -#define XADC_ZYNQ_INT_ALARM_OFFSET 0 - -#define XADC_ZYNQ_STATUS_CFIFO_LVL_MASK (0xf << 16) -#define XADC_ZYNQ_STATUS_CFIFO_LVL_OFFSET 16 -#define XADC_ZYNQ_STATUS_DFIFO_LVL_MASK (0xf << 12) -#define XADC_ZYNQ_STATUS_DFIFO_LVL_OFFSET 12 -#define XADC_ZYNQ_STATUS_CFIFOF BIT(11) -#define XADC_ZYNQ_STATUS_CFIFOE BIT(10) -#define XADC_ZYNQ_STATUS_DFIFOF BIT(9) -#define XADC_ZYNQ_STATUS_DFIFOE BIT(8) -#define XADC_ZYNQ_STATUS_OT BIT(7) -#define XADC_ZYNQ_STATUS_ALM(x) BIT(x) - -#define XADC_ZYNQ_CTL_RESET BIT(4) - -#define XADC_ZYNQ_CMD_NOP 0x00 -#define XADC_ZYNQ_CMD_READ 0x01 -#define XADC_ZYNQ_CMD_WRITE 0x02 - -#define XADC_ZYNQ_CMD(cmd, addr, data) (((cmd) << 26) | ((addr) << 16) | (= data)) - -/* AXI register definitions */ -#define XADC_AXI_REG_RESET 0x00 -#define XADC_AXI_REG_STATUS 0x04 -#define XADC_AXI_REG_ALARM_STATUS 0x08 -#define XADC_AXI_REG_CONVST 0x0c -#define XADC_AXI_REG_XADC_RESET 0x10 -#define XADC_AXI_REG_GIER 0x5c -#define XADC_AXI_REG_IPISR 0x60 -#define XADC_AXI_REG_IPIER 0x68 - -/* 7 Series */ -#define XADC_7S_AXI_ADC_REG_OFFSET 0x200 - -/* UltraScale */ -#define XADC_US_AXI_ADC_REG_OFFSET 0x400 - -#define XADC_AXI_RESET_MAGIC 0xa -#define XADC_AXI_GIER_ENABLE BIT(31) - -#define XADC_AXI_INT_EOS BIT(4) -#define XADC_AXI_INT_ALARM_MASK 0x3c0f - -#define XADC_FLAGS_BUFFERED BIT(0) -#define XADC_FLAGS_IRQ_OPTIONAL BIT(1) - -/* - * The XADC hardware supports a samplerate of up to 1MSPS. Unfortunately i= t does - * not have a hardware FIFO. Which means an interrupt is generated for each - * conversion sequence. At 1MSPS sample rate the CPU in ZYNQ7000 is comple= tely - * overloaded by the interrupts that it soft-lockups. For this reason the = driver - * limits the maximum samplerate 150kSPS. At this rate the CPU is fairly b= usy, - * but still responsive. - */ -#define XADC_MAX_SAMPLERATE 150000 - -static void xadc_write_reg(struct xadc *xadc, unsigned int reg, - uint32_t val) +void xadc_write_reg(struct xadc *xadc, unsigned int reg, uint32_t val) { writel(val, xadc->base + reg); } +EXPORT_SYMBOL_GPL(xadc_write_reg); =20 -static void xadc_read_reg(struct xadc *xadc, unsigned int reg, - uint32_t *val) +void xadc_read_reg(struct xadc *xadc, unsigned int reg, uint32_t *val) { *val =3D readl(xadc->base + reg); } +EXPORT_SYMBOL_GPL(xadc_read_reg); =20 -/* - * The ZYNQ interface uses two asynchronous FIFOs for communication with t= he - * XADC. Reads and writes to the XADC register are performed by submitting= a - * request to the command FIFO (CFIFO), once the request has been complete= d the - * result can be read from the data FIFO (DFIFO). The method currently use= d in - * this driver is to submit the request for a read/write operation, then g= o to - * sleep and wait for an interrupt that signals that a response is availab= le in - * the data FIFO. - */ - -static void xadc_zynq_write_fifo(struct xadc *xadc, uint32_t *cmd, - unsigned int n) -{ - unsigned int i; - - for (i =3D 0; i < n; i++) - xadc_write_reg(xadc, XADC_ZYNQ_REG_CFIFO, cmd[i]); -} - -static void xadc_zynq_drain_fifo(struct xadc *xadc) -{ - uint32_t status, tmp; - - xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); - - while (!(status & XADC_ZYNQ_STATUS_DFIFOE)) { - xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); - xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); - } -} - -static void xadc_zynq_update_intmsk(struct xadc *xadc, unsigned int mask, - unsigned int val) -{ - xadc->zynq_intmask &=3D ~mask; - xadc->zynq_intmask |=3D val; - - xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, - xadc->zynq_intmask | xadc->zynq_masked_alarm); -} - -static int xadc_zynq_write_adc_reg(struct xadc *xadc, unsigned int reg, - uint16_t val) -{ - uint32_t cmd[1]; - uint32_t tmp; - int ret; - - spin_lock_irq(&xadc->lock); - xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, - XADC_ZYNQ_INT_DFIFO_GTH); - - reinit_completion(&xadc->completion); - - cmd[0] =3D XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_WRITE, reg, val); - xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); - xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); - tmp &=3D ~XADC_ZYNQ_CFG_DFIFOTH_MASK; - tmp |=3D 0 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; - xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); - - xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); - spin_unlock_irq(&xadc->lock); - - ret =3D wait_for_completion_interruptible_timeout(&xadc->completion, HZ); - if (ret =3D=3D 0) - ret =3D -EIO; - else - ret =3D 0; - - xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); - - return ret; -} - -static int xadc_zynq_read_adc_reg(struct xadc *xadc, unsigned int reg, - uint16_t *val) -{ - uint32_t cmd[2]; - uint32_t resp, tmp; - int ret; - - cmd[0] =3D XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_READ, reg, 0); - cmd[1] =3D XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_NOP, 0, 0); - - spin_lock_irq(&xadc->lock); - xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, - XADC_ZYNQ_INT_DFIFO_GTH); - xadc_zynq_drain_fifo(xadc); - reinit_completion(&xadc->completion); - - xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); - xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); - tmp &=3D ~XADC_ZYNQ_CFG_DFIFOTH_MASK; - tmp |=3D 1 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; - xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); - - xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); - spin_unlock_irq(&xadc->lock); - ret =3D wait_for_completion_interruptible_timeout(&xadc->completion, HZ); - if (ret =3D=3D 0) - ret =3D -EIO; - if (ret < 0) - return ret; - - xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); - xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); - - *val =3D resp & 0xffff; - - return 0; -} - -static unsigned int xadc_zynq_transform_alarm(unsigned int alarm) -{ - return ((alarm & 0x80) >> 4) | - ((alarm & 0x78) << 1) | - (alarm & 0x07); -} - -/* - * The ZYNQ threshold interrupts are level sensitive. Since we can't make = the - * threshold condition go way from within the interrupt handler, this mean= s as - * soon as a threshold condition is present we would enter the interrupt h= andler - * again and again. To work around this we mask all active thresholds inte= rrupts - * in the interrupt handler and start a timer. In this timer we poll the - * interrupt status and only if the interrupt is inactive we unmask it aga= in. - */ -static void xadc_zynq_unmask_worker(struct work_struct *work) -{ - struct xadc *xadc =3D container_of(work, struct xadc, zynq_unmask_work.wo= rk); - unsigned int misc_sts, unmask; - - xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &misc_sts); - - misc_sts &=3D XADC_ZYNQ_INT_ALARM_MASK; - - spin_lock_irq(&xadc->lock); - - /* Clear those bits which are not active anymore */ - unmask =3D (xadc->zynq_masked_alarm ^ misc_sts) & xadc->zynq_masked_alarm; - xadc->zynq_masked_alarm &=3D misc_sts; - - /* Also clear those which are masked out anyway */ - xadc->zynq_masked_alarm &=3D ~xadc->zynq_intmask; - - /* Clear the interrupts before we unmask them */ - xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, unmask); - - xadc_zynq_update_intmsk(xadc, 0, 0); - - spin_unlock_irq(&xadc->lock); - - /* if still pending some alarm re-trigger the timer */ - if (xadc->zynq_masked_alarm) { - schedule_delayed_work(&xadc->zynq_unmask_work, - msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); - } - -} - -static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) -{ - struct iio_dev *indio_dev =3D devid; - struct xadc *xadc =3D iio_priv(indio_dev); - uint32_t status; - - xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); - - status &=3D ~(xadc->zynq_intmask | xadc->zynq_masked_alarm); - - if (!status) - return IRQ_NONE; - - spin_lock(&xadc->lock); - - xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status); - - if (status & XADC_ZYNQ_INT_DFIFO_GTH) { - xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, - XADC_ZYNQ_INT_DFIFO_GTH); - complete(&xadc->completion); - } - - status &=3D XADC_ZYNQ_INT_ALARM_MASK; - if (status) { - xadc->zynq_masked_alarm |=3D status; - /* - * mask the current event interrupt, - * unmask it when the interrupt is no more active. - */ - xadc_zynq_update_intmsk(xadc, 0, 0); - - xadc_handle_events(indio_dev, - xadc_zynq_transform_alarm(status)); - - /* unmask the required interrupts in timer. */ - schedule_delayed_work(&xadc->zynq_unmask_work, - msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); - } - spin_unlock(&xadc->lock); - - return IRQ_HANDLED; -} - -#define XADC_ZYNQ_TCK_RATE_MAX 50000000 -#define XADC_ZYNQ_IGAP_DEFAULT 20 -#define XADC_ZYNQ_PCAP_RATE_MAX 200000000 - -static int xadc_zynq_setup(struct platform_device *pdev, - struct iio_dev *indio_dev, int irq) -{ - struct xadc *xadc =3D iio_priv(indio_dev); - unsigned long pcap_rate; - unsigned int tck_div; - unsigned int div; - unsigned int igap; - unsigned int tck_rate; - int ret; - - /* TODO: Figure out how to make igap and tck_rate configurable */ - igap =3D XADC_ZYNQ_IGAP_DEFAULT; - tck_rate =3D XADC_ZYNQ_TCK_RATE_MAX; - - xadc->zynq_intmask =3D ~0; - - pcap_rate =3D clk_get_rate(xadc->clk); - if (!pcap_rate) - return -EINVAL; - - if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { - ret =3D clk_set_rate(xadc->clk, - (unsigned long)XADC_ZYNQ_PCAP_RATE_MAX); - if (ret) - return ret; - } - - if (tck_rate > pcap_rate / 2) { - div =3D 2; - } else { - div =3D pcap_rate / tck_rate; - if (pcap_rate / div > XADC_ZYNQ_TCK_RATE_MAX) - div++; - } - - if (div <=3D 3) - tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV2; - else if (div <=3D 7) - tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV4; - else if (div <=3D 15) - tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV8; - else - tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV16; - - xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, XADC_ZYNQ_CTL_RESET); - xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, 0); - xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, ~0); - xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, xadc->zynq_intmask); - xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, XADC_ZYNQ_CFG_ENABLE | - XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | - tck_div | XADC_ZYNQ_CFG_IGAP(igap)); - - if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { - ret =3D clk_set_rate(xadc->clk, pcap_rate); - if (ret) - return ret; - } - - return 0; -} - -static unsigned long xadc_zynq_get_dclk_rate(struct xadc *xadc) -{ - unsigned int div; - uint32_t val; - - xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &val); - - switch (val & XADC_ZYNQ_CFG_TCKRATE_MASK) { - case XADC_ZYNQ_CFG_TCKRATE_DIV4: - div =3D 4; - break; - case XADC_ZYNQ_CFG_TCKRATE_DIV8: - div =3D 8; - break; - case XADC_ZYNQ_CFG_TCKRATE_DIV16: - div =3D 16; - break; - default: - div =3D 2; - break; - } - - return clk_get_rate(xadc->clk) / div; -} - -static void xadc_zynq_update_alarm(struct xadc *xadc, unsigned int alarm) -{ - unsigned long flags; - uint32_t status; - - /* Move OT to bit 7 */ - alarm =3D ((alarm & 0x08) << 4) | ((alarm & 0xf0) >> 1) | (alarm & 0x07); - - spin_lock_irqsave(&xadc->lock, flags); - - /* Clear previous interrupts if any. */ - xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); - xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status & alarm); - - xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_ALARM_MASK, - ~alarm & XADC_ZYNQ_INT_ALARM_MASK); - - spin_unlock_irqrestore(&xadc->lock, flags); -} - -static const struct xadc_ops xadc_zynq_ops =3D { - .read =3D xadc_zynq_read_adc_reg, - .write =3D xadc_zynq_write_adc_reg, - .setup =3D xadc_zynq_setup, - .get_dclk_rate =3D xadc_zynq_get_dclk_rate, - .interrupt_handler =3D xadc_zynq_interrupt_handler, - .update_alarm =3D xadc_zynq_update_alarm, - .type =3D XADC_TYPE_S7, - /* Temp in C =3D (val * 503.975) / 2**bits - 273.15 */ - .temp_scale =3D 503975, - .temp_offset =3D 273150, -}; - -static const unsigned int xadc_axi_reg_offsets[] =3D { - [XADC_TYPE_S7] =3D XADC_7S_AXI_ADC_REG_OFFSET, - [XADC_TYPE_US] =3D XADC_US_AXI_ADC_REG_OFFSET, -}; - -static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg, - uint16_t *val) -{ - uint32_t val32; - - xadc_read_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4, - &val32); - *val =3D val32 & 0xffff; - - return 0; -} - -static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg, - uint16_t val) -{ - xadc_write_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4, - val); - - return 0; -} - -static int xadc_axi_setup(struct platform_device *pdev, - struct iio_dev *indio_dev, int irq) -{ - struct xadc *xadc =3D iio_priv(indio_dev); - - xadc_write_reg(xadc, XADC_AXI_REG_RESET, XADC_AXI_RESET_MAGIC); - xadc_write_reg(xadc, XADC_AXI_REG_GIER, XADC_AXI_GIER_ENABLE); - - return 0; -} - -static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid) -{ - struct iio_dev *indio_dev =3D devid; - struct xadc *xadc =3D iio_priv(indio_dev); - uint32_t status, mask; - unsigned int events; - - xadc_read_reg(xadc, XADC_AXI_REG_IPISR, &status); - xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &mask); - status &=3D mask; - - if (!status) - return IRQ_NONE; - - if ((status & XADC_AXI_INT_EOS) && xadc->trigger) - iio_trigger_poll(xadc->trigger); - - if (status & XADC_AXI_INT_ALARM_MASK) { - /* - * The order of the bits in the AXI-XADC status register does - * not match the order of the bits in the XADC alarm enable - * register. xadc_handle_events() expects the events to be in - * the same order as the XADC alarm enable register. - */ - events =3D (status & 0x000e) >> 1; - events |=3D (status & 0x0001) << 3; - events |=3D (status & 0x3c00) >> 6; - xadc_handle_events(indio_dev, events); - } - - xadc_write_reg(xadc, XADC_AXI_REG_IPISR, status); - - return IRQ_HANDLED; -} - -static void xadc_axi_update_alarm(struct xadc *xadc, unsigned int alarm) -{ - uint32_t val; - unsigned long flags; - - /* - * The order of the bits in the AXI-XADC status register does not match - * the order of the bits in the XADC alarm enable register. We get - * passed the alarm mask in the same order as in the XADC alarm enable - * register. - */ - alarm =3D ((alarm & 0x07) << 1) | ((alarm & 0x08) >> 3) | - ((alarm & 0xf0) << 6); - - spin_lock_irqsave(&xadc->lock, flags); - xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val); - val &=3D ~XADC_AXI_INT_ALARM_MASK; - val |=3D alarm; - xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val); - spin_unlock_irqrestore(&xadc->lock, flags); -} - -static unsigned long xadc_axi_get_dclk(struct xadc *xadc) -{ - return clk_get_rate(xadc->clk); -} - -static const struct xadc_ops xadc_7s_axi_ops =3D { - .read =3D xadc_axi_read_adc_reg, - .write =3D xadc_axi_write_adc_reg, - .setup =3D xadc_axi_setup, - .get_dclk_rate =3D xadc_axi_get_dclk, - .update_alarm =3D xadc_axi_update_alarm, - .interrupt_handler =3D xadc_axi_interrupt_handler, - .flags =3D XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL, - .type =3D XADC_TYPE_S7, - /* Temp in C =3D (val * 503.975) / 2**bits - 273.15 */ - .temp_scale =3D 503975, - .temp_offset =3D 273150, -}; - -static const struct xadc_ops xadc_us_axi_ops =3D { - .read =3D xadc_axi_read_adc_reg, - .write =3D xadc_axi_write_adc_reg, - .setup =3D xadc_axi_setup, - .get_dclk_rate =3D xadc_axi_get_dclk, - .update_alarm =3D xadc_axi_update_alarm, - .interrupt_handler =3D xadc_axi_interrupt_handler, - .flags =3D XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL, - .type =3D XADC_TYPE_US, - /** - * Values below are for UltraScale+ (SYSMONE4) using internal reference. - * See https://docs.xilinx.com/v/u/en-US/ug580-ultrascale-sysmon - */ - .temp_scale =3D 509314, - .temp_offset =3D 280231, -}; - -static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, - uint16_t mask, uint16_t val) +static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, u16 m= ask, u16 val) { uint16_t tmp; int ret; @@ -604,8 +53,7 @@ static int _xadc_update_adc_reg(struct xadc *xadc, unsig= ned int reg, return _xadc_write_adc_reg(xadc, reg, (tmp & ~mask) | val); } =20 -static int xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, - uint16_t mask, uint16_t val) +static int xadc_update_adc_reg(struct xadc *xadc, unsigned int reg, u16 ma= sk, u16 val) { int ret; =20 @@ -621,12 +69,11 @@ static unsigned long xadc_get_dclk_rate(struct xadc *x= adc) return xadc->ops->get_dclk_rate(xadc); } =20 -static int xadc_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *mask) +static int xadc_update_scan_mode(struct iio_dev *indio_dev, const unsigned= long *mask) { struct xadc *xadc =3D iio_priv(indio_dev); - size_t n; void *data; + size_t n; =20 n =3D bitmap_weight(mask, iio_get_masklength(indio_dev)); =20 @@ -698,9 +145,8 @@ static irqreturn_t xadc_trigger_handler(int irq, void *= p) static int xadc_trigger_set_state(struct iio_trigger *trigger, bool state) { struct xadc *xadc =3D iio_trigger_get_drvdata(trigger); + unsigned int convst, val; unsigned long flags; - unsigned int convst; - unsigned int val; int ret =3D 0; =20 mutex_lock(&xadc->mutex); @@ -718,7 +164,7 @@ static int xadc_trigger_set_state(struct iio_trigger *t= rigger, bool state) convst =3D 0; } ret =3D _xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF0_EC, - convst); + convst); if (ret) goto err_out; } else { @@ -745,8 +191,7 @@ static const struct iio_trigger_ops xadc_trigger_ops = =3D { .set_trigger_state =3D &xadc_trigger_set_state, }; =20 -static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, - const char *name) +static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev, c= onst char *name) { struct device *dev =3D indio_dev->dev.parent; struct iio_trigger *trig; @@ -813,12 +258,12 @@ static int xadc_get_seq_mode(struct xadc *xadc, unsig= ned long scan_mode) return XADC_CONF1_SEQ_SIMULTANEOUS; } =20 -static int xadc_postdisable(struct iio_dev *indio_dev) +int xadc_postdisable(struct iio_dev *indio_dev) { struct xadc *xadc =3D iio_priv(indio_dev); unsigned long scan_mask; int ret; - int i; + u32 i; =20 scan_mask =3D 1; /* Run calibration as part of the sequence */ for (i =3D 0; i < indio_dev->num_channels; i++) @@ -840,6 +285,7 @@ static int xadc_postdisable(struct iio_dev *indio_dev) =20 return xadc_power_adc_b(xadc, XADC_CONF1_SEQ_CONTINUOUS); } +EXPORT_SYMBOL_GPL(xadc_postdisable); =20 static int xadc_preenable(struct iio_dev *indio_dev) { @@ -894,7 +340,7 @@ static const struct iio_buffer_setup_ops xadc_buffer_op= s =3D { .postdisable =3D &xadc_postdisable, }; =20 -static int xadc_read_samplerate(struct xadc *xadc) +int xadc_read_samplerate(struct xadc *xadc) { unsigned int div; uint16_t val16; @@ -910,9 +356,10 @@ static int xadc_read_samplerate(struct xadc *xadc) =20 return xadc_get_dclk_rate(xadc) / div / 26; } +EXPORT_SYMBOL_GPL(xadc_read_samplerate); =20 -static int xadc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int *val, int *val2, long info) +static int xadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec c= onst *chan, + int *val, int *val2, long info) { struct xadc *xadc =3D iio_priv(indio_dev); unsigned int bits =3D chan->scan_type.realbits; @@ -978,7 +425,37 @@ static int xadc_read_raw(struct iio_dev *indio_dev, } } =20 -static int xadc_write_samplerate(struct xadc *xadc, int val) +int xadc_setup_buffer_and_triggers(struct device *dev, struct iio_dev *ind= io_dev, + struct xadc *xadc, int irq) +{ + int ret; + + if (!(xadc->ops->flags & XADC_FLAGS_BUFFERED)) + return 0; + + ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &xadc_trigger_handler, + &xadc_buffer_ops); + if (ret) + return ret; + + if (irq > 0) { + xadc->convst_trigger =3D xadc_alloc_trigger(indio_dev, "convst"); + if (IS_ERR(xadc->convst_trigger)) + return PTR_ERR(xadc->convst_trigger); + + xadc->samplerate_trigger =3D xadc_alloc_trigger(indio_dev, + "samplerate"); + if (IS_ERR(xadc->samplerate_trigger)) + return PTR_ERR(xadc->samplerate_trigger); + } + + return 0; +} +EXPORT_SYMBOL_GPL(xadc_setup_buffer_and_triggers); + +int xadc_write_samplerate(struct xadc *xadc, int val) { unsigned long clk_rate =3D xadc_get_dclk_rate(xadc); unsigned int div; @@ -1014,6 +491,7 @@ static int xadc_write_samplerate(struct xadc *xadc, in= t val) return xadc_update_adc_reg(xadc, XADC_REG_CONF2, XADC_CONF2_DIV_MASK, div << XADC_CONF2_DIV_OFFSET); } +EXPORT_SYMBOL_GPL(xadc_write_samplerate); =20 static int xadc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info) @@ -1175,21 +653,6 @@ static const struct iio_info xadc_info =3D { .update_scan_mode =3D &xadc_update_scan_mode, }; =20 -static const struct of_device_id xadc_of_match_table[] =3D { - { - .compatible =3D "xlnx,zynq-xadc-1.00.a", - .data =3D &xadc_zynq_ops - }, { - .compatible =3D "xlnx,axi-xadc-1.00.a", - .data =3D &xadc_7s_axi_ops - }, { - .compatible =3D "xlnx,system-management-wiz-1.3", - .data =3D &xadc_us_axi_ops - }, - { } -}; -MODULE_DEVICE_TABLE(of, xadc_of_match_table); - static int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, in= t irq) { struct device *dev =3D indio_dev->dev.parent; @@ -1298,156 +761,53 @@ static int xadc_parse_dt(struct iio_dev *indio_dev,= unsigned int *conf, int irq) return 0; } =20 -static const char * const xadc_type_names[] =3D { +const char * const xadc_type_names[] =3D { [XADC_TYPE_S7] =3D "xadc", [XADC_TYPE_US] =3D "xilinx-system-monitor", }; =20 -static void xadc_cancel_delayed_work(void *data) +struct iio_dev *xadc_device_setup(struct device *dev, int size, + const struct xadc_ops **ops) { - struct delayed_work *work =3D data; - - cancel_delayed_work_sync(work); -} - -static int xadc_probe(struct platform_device *pdev) -{ - struct device *dev =3D &pdev->dev; - const struct xadc_ops *ops; struct iio_dev *indio_dev; - unsigned int bipolar_mask; - unsigned int conf0; - struct xadc *xadc; - int ret; - int irq; - int i; - - ops =3D device_get_match_data(dev); - if (!ops) - return -EINVAL; =20 - irq =3D platform_get_irq_optional(pdev, 0); - if (irq < 0 && - (irq !=3D -ENXIO || !(ops->flags & XADC_FLAGS_IRQ_OPTIONAL))) - return irq; + *ops =3D device_get_match_data(dev); + if (!*ops) + return ERR_PTR(-ENODEV); =20 - indio_dev =3D devm_iio_device_alloc(dev, sizeof(*xadc)); + indio_dev =3D devm_iio_device_alloc(dev, size); if (!indio_dev) - return -ENOMEM; - - xadc =3D iio_priv(indio_dev); - xadc->ops =3D ops; - init_completion(&xadc->completion); - mutex_init(&xadc->mutex); - spin_lock_init(&xadc->lock); - INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker); - - xadc->base =3D devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(xadc->base)) - return PTR_ERR(xadc->base); + return ERR_PTR(-ENOMEM); =20 - indio_dev->name =3D xadc_type_names[xadc->ops->type]; - indio_dev->modes =3D INDIO_DIRECT_MODE; + indio_dev->name =3D xadc_type_names[(*ops)->type]; indio_dev->info =3D &xadc_info; + indio_dev->modes =3D INDIO_DIRECT_MODE; =20 - ret =3D xadc_parse_dt(indio_dev, &conf0, irq); - if (ret) - return ret; - - if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { - ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, - &iio_pollfunc_store_time, - &xadc_trigger_handler, - &xadc_buffer_ops); - if (ret) - return ret; - - if (irq > 0) { - xadc->convst_trigger =3D xadc_alloc_trigger(indio_dev, "convst"); - if (IS_ERR(xadc->convst_trigger)) - return PTR_ERR(xadc->convst_trigger); - - xadc->samplerate_trigger =3D xadc_alloc_trigger(indio_dev, - "samplerate"); - if (IS_ERR(xadc->samplerate_trigger)) - return PTR_ERR(xadc->samplerate_trigger); - } - } - - xadc->clk =3D devm_clk_get_enabled(dev, NULL); - if (IS_ERR(xadc->clk)) - return PTR_ERR(xadc->clk); - - /* - * Make sure not to exceed the maximum samplerate since otherwise the - * resulting interrupt storm will soft-lock the system. - */ - if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { - ret =3D xadc_read_samplerate(xadc); - if (ret < 0) - return ret; - - if (ret > XADC_MAX_SAMPLERATE) { - ret =3D xadc_write_samplerate(xadc, XADC_MAX_SAMPLERATE); - if (ret < 0) - return ret; - } - } - - if (irq > 0) { - ret =3D devm_request_irq(dev, irq, xadc->ops->interrupt_handler, - 0, dev_name(dev), indio_dev); - if (ret) - return ret; - - ret =3D devm_add_action_or_reset(dev, xadc_cancel_delayed_work, - &xadc->zynq_unmask_work); - if (ret) - return ret; - } - - ret =3D xadc->ops->setup(pdev, indio_dev, irq); - if (ret) - return ret; + return indio_dev; +} +EXPORT_SYMBOL_GPL(xadc_device_setup); =20 - for (i =3D 0; i < 16; i++) - xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), - &xadc->threshold[i]); +int xadc_device_configure(struct device *dev, struct iio_dev *indio_dev, + int irq, unsigned int *conf0, + unsigned int *bipolar_mask) +{ + int ret; + u32 i; =20 - ret =3D xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0); + ret =3D xadc_parse_dt(indio_dev, conf0, irq); if (ret) return ret; =20 - bipolar_mask =3D 0; + *bipolar_mask =3D 0; for (i =3D 0; i < indio_dev->num_channels; i++) { if (indio_dev->channels[i].scan_type.sign =3D=3D 's') - bipolar_mask |=3D BIT(indio_dev->channels[i].scan_index); + *bipolar_mask |=3D BIT(indio_dev->channels[i].scan_index); } =20 - ret =3D xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask); - if (ret) - return ret; - - ret =3D xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1), - bipolar_mask >> 16); - if (ret) - return ret; - - /* Go to non-buffered mode */ - xadc_postdisable(indio_dev); - - return devm_iio_device_register(dev, indio_dev); + return 0; } - -static struct platform_driver xadc_driver =3D { - .probe =3D xadc_probe, - .driver =3D { - .name =3D "xadc", - .of_match_table =3D xadc_of_match_table, - }, -}; -module_platform_driver(xadc_driver); +EXPORT_SYMBOL_GPL(xadc_device_configure); =20 MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("Xilinx XADC IIO driver"); +MODULE_DESCRIPTION("Xilinx XADC IIO core driver"); diff --git a/drivers/iio/adc/xilinx-xadc-platform.c b/drivers/iio/adc/xilin= x-xadc-platform.c new file mode 100644 index 000000000000..f1ffbf5cff42 --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc-platform.c @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx XADC platform driver + * + * Copyright 2013-2014 Analog Devices Inc. + * Author: Lars-Peter Clausen + * + * Documentation for the parts can be found at: + * - XADC hardmacro: Xilinx UG480 + * - ZYNQ XADC interface: Xilinx UG585 + * - AXI XADC interface: Xilinx PG019 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "xilinx-xadc.h" + +static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT =3D 500; + +/* ZYNQ register definitions */ +#define XADC_ZYNQ_REG_CFG 0x00 +#define XADC_ZYNQ_REG_INTSTS 0x04 +#define XADC_ZYNQ_REG_INTMSK 0x08 +#define XADC_ZYNQ_REG_STATUS 0x0c +#define XADC_ZYNQ_REG_CFIFO 0x10 +#define XADC_ZYNQ_REG_DFIFO 0x14 +#define XADC_ZYNQ_REG_CTL 0x18 + +#define XADC_ZYNQ_CFG_ENABLE BIT(31) +#define XADC_ZYNQ_CFG_CFIFOTH_MASK (0xf << 20) +#define XADC_ZYNQ_CFG_CFIFOTH_OFFSET 20 +#define XADC_ZYNQ_CFG_DFIFOTH_MASK (0xf << 16) +#define XADC_ZYNQ_CFG_DFIFOTH_OFFSET 16 +#define XADC_ZYNQ_CFG_WEDGE BIT(13) +#define XADC_ZYNQ_CFG_REDGE BIT(12) +#define XADC_ZYNQ_CFG_TCKRATE_MASK (0x3 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV2 (0x0 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV4 (0x1 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV8 (0x2 << 8) +#define XADC_ZYNQ_CFG_TCKRATE_DIV16 (0x3 << 8) +#define XADC_ZYNQ_CFG_IGAP_MASK 0x1f +#define XADC_ZYNQ_CFG_IGAP(x) (x) + +#define XADC_ZYNQ_INT_CFIFO_LTH BIT(9) +#define XADC_ZYNQ_INT_DFIFO_GTH BIT(8) +#define XADC_ZYNQ_INT_ALARM_MASK 0xff +#define XADC_ZYNQ_INT_ALARM_OFFSET 0 + +#define XADC_ZYNQ_STATUS_CFIFO_LVL_MASK (0xf << 16) +#define XADC_ZYNQ_STATUS_CFIFO_LVL_OFFSET 16 +#define XADC_ZYNQ_STATUS_DFIFO_LVL_MASK (0xf << 12) +#define XADC_ZYNQ_STATUS_DFIFO_LVL_OFFSET 12 +#define XADC_ZYNQ_STATUS_CFIFOF BIT(11) +#define XADC_ZYNQ_STATUS_CFIFOE BIT(10) +#define XADC_ZYNQ_STATUS_DFIFOF BIT(9) +#define XADC_ZYNQ_STATUS_DFIFOE BIT(8) +#define XADC_ZYNQ_STATUS_OT BIT(7) +#define XADC_ZYNQ_STATUS_ALM(x) BIT(x) + +#define XADC_ZYNQ_CTL_RESET BIT(4) + +#define XADC_ZYNQ_CMD_NOP 0x00 +#define XADC_ZYNQ_CMD_READ 0x01 +#define XADC_ZYNQ_CMD_WRITE 0x02 + +#define XADC_ZYNQ_CMD(cmd, addr, data) (((cmd) << 26) | ((addr) << 16) | (= data)) + +/* AXI register definitions */ +#define XADC_AXI_REG_RESET 0x00 +#define XADC_AXI_REG_STATUS 0x04 +#define XADC_AXI_REG_ALARM_STATUS 0x08 +#define XADC_AXI_REG_CONVST 0x0c +#define XADC_AXI_REG_XADC_RESET 0x10 +#define XADC_AXI_REG_GIER 0x5c +#define XADC_AXI_REG_IPISR 0x60 +#define XADC_AXI_REG_IPIER 0x68 + +/* 7 Series */ +#define XADC_7S_AXI_ADC_REG_OFFSET 0x200 +/* UltraScale */ +#define XADC_US_AXI_ADC_REG_OFFSET 0x400 +#define XADC_AXI_RESET_MAGIC 0xa +#define XADC_AXI_GIER_ENABLE BIT(31) +#define XADC_AXI_INT_EOS BIT(4) +#define XADC_AXI_INT_ALARM_MASK 0x3c0f + +/* + * The ZYNQ interface uses two asynchronous FIFOs for communication with t= he + * XADC. Reads and writes to the XADC register are performed by submitting= a + * request to the command FIFO (CFIFO), once the request has been complete= d the + * result can be read from the data FIFO (DFIFO). The method currently use= d in + * this driver is to submit the request for a read/write operation, then g= o to + * sleep and wait for an interrupt that signals that a response is availab= le in + * the data FIFO. + */ +static void xadc_zynq_write_fifo(struct xadc *xadc, uint32_t *cmd, unsigne= d int n) +{ + unsigned int i; + + for (i =3D 0; i < n; i++) + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFIFO, cmd[i]); +} + +static void xadc_zynq_drain_fifo(struct xadc *xadc) +{ + u32 status, tmp; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); + + while (!(status & XADC_ZYNQ_STATUS_DFIFOE)) { + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); + xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &status); + } +} + +static void xadc_zynq_update_intmsk(struct xadc *xadc, unsigned int mask, = unsigned int val) +{ + xadc->zynq_intmask &=3D ~mask; + xadc->zynq_intmask |=3D val; + + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, xadc->zynq_intmask | xadc->zyn= q_masked_alarm); +} + +static int xadc_zynq_write_adc_reg(struct xadc *xadc, unsigned int reg, ui= nt16_t val) +{ + u32 cmd[1], tmp; + int ret; + + spin_lock_irq(&xadc->lock); + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, XADC_ZYNQ_INT_DFIF= O_GTH); + + reinit_completion(&xadc->completion); + + cmd[0] =3D XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_WRITE, reg, val); + xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); + xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); + tmp &=3D ~XADC_ZYNQ_CFG_DFIFOTH_MASK; + tmp |=3D 0 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); + + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); + spin_unlock_irq(&xadc->lock); + + ret =3D wait_for_completion_interruptible_timeout(&xadc->completion, HZ); + if (ret =3D=3D 0) + ret =3D -EIO; + else + ret =3D 0; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &tmp); + + return ret; +} + +static int xadc_zynq_read_adc_reg(struct xadc *xadc, unsigned int reg, uin= t16_t *val) +{ + u32 cmd[2], resp, tmp; + int ret; + + cmd[0] =3D XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_READ, reg, 0); + cmd[1] =3D XADC_ZYNQ_CMD(XADC_ZYNQ_CMD_NOP, 0, 0); + + spin_lock_irq(&xadc->lock); + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, XADC_ZYNQ_INT_DFIF= O_GTH); + xadc_zynq_drain_fifo(xadc); + reinit_completion(&xadc->completion); + + xadc_zynq_write_fifo(xadc, cmd, ARRAY_SIZE(cmd)); + xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &tmp); + tmp &=3D ~XADC_ZYNQ_CFG_DFIFOTH_MASK; + tmp |=3D 1 << XADC_ZYNQ_CFG_DFIFOTH_OFFSET; + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, tmp); + + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, 0); + spin_unlock_irq(&xadc->lock); + ret =3D wait_for_completion_interruptible_timeout(&xadc->completion, HZ); + if (ret =3D=3D 0) + ret =3D -EIO; + if (ret < 0) + return ret; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); + xadc_read_reg(xadc, XADC_ZYNQ_REG_DFIFO, &resp); + + *val =3D resp & 0xffff; + + return 0; +} + +static unsigned int xadc_zynq_transform_alarm(unsigned int alarm) +{ + return ((alarm & 0x80) >> 4) | + ((alarm & 0x78) << 1) | + (alarm & 0x07); +} + +/* + * The ZYNQ threshold interrupts are level sensitive. Since we can't make = the + * threshold condition go way from within the interrupt handler, this mean= s as + * soon as a threshold condition is present we would enter the interrupt h= andler + * again and again. To work around this we mask all active thresholds inte= rrupts + * in the interrupt handler and start a timer. In this timer we poll the + * interrupt status and only if the interrupt is inactive we unmask it aga= in. + */ +static void xadc_zynq_unmask_worker(struct work_struct *work) +{ + struct xadc *xadc =3D container_of(work, struct xadc, zynq_unmask_work.wo= rk); + unsigned int misc_sts, unmask; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_STATUS, &misc_sts); + + misc_sts &=3D XADC_ZYNQ_INT_ALARM_MASK; + + spin_lock_irq(&xadc->lock); + + /* Clear those bits which are not active anymore */ + unmask =3D (xadc->zynq_masked_alarm ^ misc_sts) & xadc->zynq_masked_alarm; + xadc->zynq_masked_alarm &=3D misc_sts; + + /* Also clear those which are masked out anyway */ + xadc->zynq_masked_alarm &=3D ~xadc->zynq_intmask; + + /* Clear the interrupts before we unmask them */ + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, unmask); + + xadc_zynq_update_intmsk(xadc, 0, 0); + + spin_unlock_irq(&xadc->lock); + + /* if still pending some alarm re-trigger the timer */ + if (xadc->zynq_masked_alarm) + schedule_delayed_work(&xadc->zynq_unmask_work, + msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); +} + +static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) +{ + struct iio_dev *indio_dev =3D devid; + struct xadc *xadc =3D iio_priv(indio_dev); + u32 status; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); + + status &=3D ~(xadc->zynq_intmask | xadc->zynq_masked_alarm); + + if (!status) + return IRQ_NONE; + + spin_lock(&xadc->lock); + + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status); + + if (status & XADC_ZYNQ_INT_DFIFO_GTH) { + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_DFIFO_GTH, + XADC_ZYNQ_INT_DFIFO_GTH); + complete(&xadc->completion); + } + + status &=3D XADC_ZYNQ_INT_ALARM_MASK; + if (status) { + xadc->zynq_masked_alarm |=3D status; + /* + * mask the current event interrupt, + * unmask it when the interrupt is no more active. + */ + xadc_zynq_update_intmsk(xadc, 0, 0); + + xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(status)); + + /* unmask the required interrupts in timer. */ + schedule_delayed_work(&xadc->zynq_unmask_work, + msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); + } + spin_unlock(&xadc->lock); + + return IRQ_HANDLED; +} + +#define XADC_ZYNQ_TCK_RATE_MAX 50000000 +#define XADC_ZYNQ_IGAP_DEFAULT 20 +#define XADC_ZYNQ_PCAP_RATE_MAX 200000000 + +static int xadc_zynq_setup(struct platform_device *pdev, struct iio_dev *i= ndio_dev, int irq) +{ + unsigned int tck_div, div, igap, tck_rate; + struct xadc *xadc =3D iio_priv(indio_dev); + unsigned long pcap_rate; + int ret; + + /* TODO: Figure out how to make igap and tck_rate configurable */ + igap =3D XADC_ZYNQ_IGAP_DEFAULT; + tck_rate =3D XADC_ZYNQ_TCK_RATE_MAX; + + xadc->zynq_intmask =3D ~0; + + pcap_rate =3D clk_get_rate(xadc->clk); + if (!pcap_rate) + return -EINVAL; + + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret =3D clk_set_rate(xadc->clk, (unsigned long)XADC_ZYNQ_PCAP_RATE_MAX); + if (ret) + return ret; + } + + if (tck_rate > pcap_rate / 2) { + div =3D 2; + } else { + div =3D pcap_rate / tck_rate; + if (pcap_rate / div > XADC_ZYNQ_TCK_RATE_MAX) + div++; + } + + if (div <=3D 3) + tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV2; + else if (div <=3D 7) + tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV4; + else if (div <=3D 15) + tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV8; + else + tck_div =3D XADC_ZYNQ_CFG_TCKRATE_DIV16; + + xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, XADC_ZYNQ_CTL_RESET); + xadc_write_reg(xadc, XADC_ZYNQ_REG_CTL, 0); + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, ~0); + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTMSK, xadc->zynq_intmask); + xadc_write_reg(xadc, XADC_ZYNQ_REG_CFG, XADC_ZYNQ_CFG_ENABLE | + XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE | + tck_div | XADC_ZYNQ_CFG_IGAP(igap)); + + if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) { + ret =3D clk_set_rate(xadc->clk, pcap_rate); + if (ret) + return ret; + } + + return 0; +} + +static unsigned long xadc_zynq_get_dclk_rate(struct xadc *xadc) +{ + unsigned int div; + u32 val; + + xadc_read_reg(xadc, XADC_ZYNQ_REG_CFG, &val); + + switch (val & XADC_ZYNQ_CFG_TCKRATE_MASK) { + case XADC_ZYNQ_CFG_TCKRATE_DIV4: + div =3D 4; + break; + case XADC_ZYNQ_CFG_TCKRATE_DIV8: + div =3D 8; + break; + case XADC_ZYNQ_CFG_TCKRATE_DIV16: + div =3D 16; + break; + default: + div =3D 2; + break; + } + + return clk_get_rate(xadc->clk) / div; +} + +static void xadc_zynq_update_alarm(struct xadc *xadc, unsigned int alarm) +{ + unsigned long flags; + u32 status; + + /* Move OT to bit 7 */ + alarm =3D ((alarm & 0x08) << 4) | ((alarm & 0xf0) >> 1) | (alarm & 0x07); + + spin_lock_irqsave(&xadc->lock, flags); + + /* Clear previous interrupts if any. */ + xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); + xadc_write_reg(xadc, XADC_ZYNQ_REG_INTSTS, status & alarm); + + xadc_zynq_update_intmsk(xadc, XADC_ZYNQ_INT_ALARM_MASK, + ~alarm & XADC_ZYNQ_INT_ALARM_MASK); + + spin_unlock_irqrestore(&xadc->lock, flags); +} + +static const struct xadc_ops xadc_zynq_ops =3D { + .read =3D xadc_zynq_read_adc_reg, + .write =3D xadc_zynq_write_adc_reg, + .setup =3D xadc_zynq_setup, + .get_dclk_rate =3D xadc_zynq_get_dclk_rate, + .interrupt_handler =3D xadc_zynq_interrupt_handler, + .update_alarm =3D xadc_zynq_update_alarm, + .type =3D XADC_TYPE_S7, + /* Temp in C =3D (val * 503.975) / 2**bits - 273.15 */ + .temp_scale =3D 503975, + .temp_offset =3D 273150, +}; + +static const unsigned int xadc_axi_reg_offsets[] =3D { + [XADC_TYPE_S7] =3D XADC_7S_AXI_ADC_REG_OFFSET, + [XADC_TYPE_US] =3D XADC_US_AXI_ADC_REG_OFFSET, +}; + +static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg, uint= 16_t *val) +{ + u32 val32; + + xadc_read_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4, &val= 32); + *val =3D val32 & 0xffff; + + return 0; +} + +static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg, u16= val) +{ + xadc_write_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4, val= ); + + return 0; +} + +static int xadc_axi_setup(struct platform_device *pdev, struct iio_dev *in= dio_dev, int irq) +{ + struct xadc *xadc =3D iio_priv(indio_dev); + + xadc_write_reg(xadc, XADC_AXI_REG_RESET, XADC_AXI_RESET_MAGIC); + xadc_write_reg(xadc, XADC_AXI_REG_GIER, XADC_AXI_GIER_ENABLE); + + return 0; +} + +static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid) +{ + struct iio_dev *indio_dev =3D devid; + struct xadc *xadc =3D iio_priv(indio_dev); + u32 status, mask; + unsigned int events; + + xadc_read_reg(xadc, XADC_AXI_REG_IPISR, &status); + xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &mask); + status &=3D mask; + + if (!status) + return IRQ_NONE; + + if ((status & XADC_AXI_INT_EOS) && xadc->trigger) + iio_trigger_poll(xadc->trigger); + + if (status & XADC_AXI_INT_ALARM_MASK) { + /* + * The order of the bits in the AXI-XADC status register does + * not match the order of the bits in the XADC alarm enable + * register. xadc_handle_events() expects the events to be in + * the same order as the XADC alarm enable register. + */ + events =3D (status & 0x000e) >> 1; + events |=3D (status & 0x0001) << 3; + events |=3D (status & 0x3c00) >> 6; + xadc_handle_events(indio_dev, events); + } + + xadc_write_reg(xadc, XADC_AXI_REG_IPISR, status); + + return IRQ_HANDLED; +} + +static void xadc_axi_update_alarm(struct xadc *xadc, unsigned int alarm) +{ + u32 val; + unsigned long flags; + + /* + * The order of the bits in the AXI-XADC status register does not match + * the order of the bits in the XADC alarm enable register. We get + * passed the alarm mask in the same order as in the XADC alarm enable + * register. + */ + alarm =3D ((alarm & 0x07) << 1) | ((alarm & 0x08) >> 3) | + ((alarm & 0xf0) << 6); + + spin_lock_irqsave(&xadc->lock, flags); + xadc_read_reg(xadc, XADC_AXI_REG_IPIER, &val); + val &=3D ~XADC_AXI_INT_ALARM_MASK; + val |=3D alarm; + xadc_write_reg(xadc, XADC_AXI_REG_IPIER, val); + spin_unlock_irqrestore(&xadc->lock, flags); +} + +static unsigned long xadc_axi_get_dclk(struct xadc *xadc) +{ + return clk_get_rate(xadc->clk); +} + +static const struct xadc_ops xadc_7s_axi_ops =3D { + .read =3D xadc_axi_read_adc_reg, + .write =3D xadc_axi_write_adc_reg, + .setup =3D xadc_axi_setup, + .get_dclk_rate =3D xadc_axi_get_dclk, + .update_alarm =3D xadc_axi_update_alarm, + .interrupt_handler =3D xadc_axi_interrupt_handler, + .flags =3D XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL, + .type =3D XADC_TYPE_S7, + /* Temp in C =3D (val * 503.975) / 2**bits - 273.15 */ + .temp_scale =3D 503975, + .temp_offset =3D 273150, +}; + +static const struct xadc_ops xadc_us_axi_ops =3D { + .read =3D xadc_axi_read_adc_reg, + .write =3D xadc_axi_write_adc_reg, + .setup =3D xadc_axi_setup, + .get_dclk_rate =3D xadc_axi_get_dclk, + .update_alarm =3D xadc_axi_update_alarm, + .interrupt_handler =3D xadc_axi_interrupt_handler, + .flags =3D XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL, + .type =3D XADC_TYPE_US, + /** + * Values below are for UltraScale+ (SYSMONE4) using internal reference. + * See https://docs.xilinx.com/v/u/en-US/ug580-ultrascale-sysmon + */ + .temp_scale =3D 509314, + .temp_offset =3D 280231, +}; + +static const struct of_device_id xadc_of_match_table[] =3D { + { + .compatible =3D "xlnx,zynq-xadc-1.00.a", + .data =3D &xadc_zynq_ops + }, { + .compatible =3D "xlnx,axi-xadc-1.00.a", + .data =3D &xadc_7s_axi_ops + }, { + .compatible =3D "xlnx,system-management-wiz-1.3", + .data =3D &xadc_us_axi_ops + }, + { } +}; +MODULE_DEVICE_TABLE(of, xadc_of_match_table); + +static void xadc_cancel_delayed_work(void *data) +{ + struct delayed_work *work =3D data; + + cancel_delayed_work_sync(work); +} + +static int xadc_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + const struct xadc_ops *ops; + struct iio_dev *indio_dev; + unsigned int bipolar_mask; + unsigned int conf0; + struct xadc *xadc; + int ret; + int irq; + u32 i; + + indio_dev =3D xadc_device_setup(dev, sizeof(*xadc), &ops); + if (IS_ERR(indio_dev)) + return PTR_ERR(indio_dev); + + irq =3D platform_get_irq_optional(pdev, 0); + if (irq < 0 && + (irq !=3D -ENXIO || !(ops->flags & XADC_FLAGS_IRQ_OPTIONAL))) + return irq; + + xadc =3D iio_priv(indio_dev); + xadc->ops =3D ops; + init_completion(&xadc->completion); + mutex_init(&xadc->mutex); + spin_lock_init(&xadc->lock); + INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker); + + xadc->base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(xadc->base)) + return PTR_ERR(xadc->base); + + ret =3D xadc_device_configure(dev, indio_dev, irq, &conf0, &bipolar_mask); + if (ret) + return ret; + + ret =3D xadc_setup_buffer_and_triggers(dev, indio_dev, xadc, irq); + if (ret) + return ret; + + xadc->clk =3D devm_clk_get_enabled(dev, NULL); + if (IS_ERR(xadc->clk)) + return PTR_ERR(xadc->clk); + + /* + * Make sure not to exceed the maximum samplerate since otherwise the + * resulting interrupt storm will soft-lock the system. + */ + if (xadc->ops->flags & XADC_FLAGS_BUFFERED) { + ret =3D xadc_read_samplerate(xadc); + if (ret < 0) + return ret; + + if (ret > XADC_MAX_SAMPLERATE) { + ret =3D xadc_write_samplerate(xadc, XADC_MAX_SAMPLERATE); + if (ret < 0) + return ret; + } + } + + if (irq > 0) { + ret =3D devm_request_irq(dev, irq, xadc->ops->interrupt_handler, + 0, dev_name(dev), indio_dev); + if (ret) + return ret; + + ret =3D devm_add_action_or_reset(dev, xadc_cancel_delayed_work, + &xadc->zynq_unmask_work); + if (ret) + return ret; + } + + ret =3D xadc->ops->setup(pdev, indio_dev, irq); + if (ret) + return ret; + + for (i =3D 0; i < 16; i++) + xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i), &xadc->threshold[i]); + + ret =3D xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0); + if (ret) + return ret; + + ret =3D xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask); + if (ret) + return ret; + + ret =3D xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1), bipolar_mask >> = 16); + if (ret) + return ret; + + /* Go to non-buffered mode */ + xadc_postdisable(indio_dev); + + return devm_iio_device_register(dev, indio_dev); +} + +static struct platform_driver xadc_driver =3D { + .probe =3D xadc_probe, + .driver =3D { + .name =3D "xadc", + .of_match_table =3D xadc_of_match_table, + }, +}; +module_platform_driver(xadc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Xilinx XADC platform driver"); diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index b4d9d4683117..a2d208fbd13b 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -211,4 +211,34 @@ static inline int xadc_write_adc_reg(struct xadc *xadc= , unsigned int reg, #define XADC_THRESHOLD_VCCPAUX_MIN 0xe #define XADC_THRESHOLD_VCCODDR_MIN 0xf =20 +/* + * The XADC hardware supports a samplerate of up to 1MSPS. Unfortunately i= t does + * not have a hardware FIFO. Which means an interrupt is generated for each + * conversion sequence. At 1MSPS sample rate the CPU in ZYNQ7000 is comple= tely + * overloaded by the interrupts that it soft-lockups. For this reason the = driver + * limits the maximum samplerate 150kSPS. At this rate the CPU is fairly b= usy, + * but still responsive. + */ +#define XADC_MAX_SAMPLERATE 150000 + +#define XADC_FLAGS_BUFFERED BIT(0) +#define XADC_FLAGS_IRQ_OPTIONAL BIT(1) + +/* AXI register definitions needed by core */ +#define XADC_AXI_REG_IPISR 0x60 +#define XADC_AXI_REG_IPIER 0x68 +#define XADC_AXI_INT_EOS BIT(4) + +void xadc_write_reg(struct xadc *xadc, unsigned int reg, uint32_t val); +void xadc_read_reg(struct xadc *xadc, unsigned int reg, uint32_t *val); +struct iio_dev *xadc_device_setup(struct device *dev, int size, + const struct xadc_ops **ops); +int xadc_device_configure(struct device *dev, struct iio_dev *indio_dev, + int irq, unsigned int *conf0, unsigned int *bipolar_mask); +int xadc_read_samplerate(struct xadc *xadc); +int xadc_write_samplerate(struct xadc *xadc, int val); +int xadc_setup_buffer_and_triggers(struct device *dev, struct iio_dev *ind= io_dev, + struct xadc *xadc, int irq); +int xadc_postdisable(struct iio_dev *indio_dev); + #endif --=20 2.25.1 From nobody Fri Apr 3 22:33:01 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012054.outbound.protection.outlook.com [52.101.48.54]) (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 4D8BB36309D; Mon, 23 Mar 2026 07:46:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.54 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251984; cv=fail; b=XUvSvr++AzTkMMNx29KTJuKF+FL7KmnifokXQlbeGVR36kYmRjySUhBuytiyLaBNp1CArK/BbY3TzM7bhTg8A7qT8sct2nK2vWKZ69tyeN6iua7ikhnxypY3gI7Xxlzs6bemCAB9R5+PpSuWUqje6E77GP6o8OW/dVM5TLjDv+w= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251984; c=relaxed/simple; bh=jMvTqjbddnJQwwhZPFod6NEowaZzBH2dTs9Pchd46WE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZBYw2PVjMGmxijLe84uQsXIIqYPL7p5nYDtGzTBeu4UOdNlgNmw3gk9/OafRlQnsmMXy2+0Snt6JAi0frVpumTCpJSs8d8B7MxBBzYww4o0yIEOfHO3nNwafnI+aOwFFHiEAGsL04nuYJxomFIxFZQYKGlzliDue+C1C24QLusQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=g5iUVu0s; arc=fail smtp.client-ip=52.101.48.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="g5iUVu0s" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Zgw7m1WKRwDl1Rl0eX3CCVA7moiHLlvEJ09AhmgOq0QmD/fuUCpwTw/8LS/3e8slxELkRDPOCQ0ZTk/SdbbRlgv2wwMGiM9vf4XJRou1s1lT+R/VbYhXnAzdwYV7M8nu77ejWFxTBTsboO9SzS0KPU0OuOUHmd5j2WmTZxXg+Xu7idUb4KIvQHeWrx1XZJdE1+Qhy0ymweXLPTreriRBR2jdCfgl0vfSbZ7rtN/K4gVSwMaB92KOen3bhkltYG0/L6RJU+adwpgybgkN+8azogXrvqy2gPA2f3WIiAHAyCB4dObqCeXALCv2uvut0R/cjiH1HJjqWf4gIc0sN3iDyg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=S3AyIx475olH2C2g+uM9vRsRlHsLGPzSrQGUbFMikhk=; b=js2wjnmnJtSyDdZpcGu2uEGBAqYe5wdZUxxUL4GEfuQZF8EAO63xsGVOaDU6LMA5YS8fZYCcQJdcFcIHkdC/o1Tj8fwPZKdj/UxLbXksAvvwIzKmn0yJjcYzAir0XV2lFb3C5zzjLkzFWnQPqJFae02Lv1YsmmYUZXggq86JHBwFRVFDumFZVzL61soaVP6Z+eyXSqhJz/uKICYRq7V4jUJ8CVPswa+mbB0HFPNr97NzwLhZV18tigO12H1KhE8ieNyj1pJhtxXpBZ5KxxZKvWvD1dkPoUwDAKVYtuCl+Erg4oGoJHaWuUAv+stOJuDYoR6KoHF2aIqAGgOakCAU+Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=S3AyIx475olH2C2g+uM9vRsRlHsLGPzSrQGUbFMikhk=; b=g5iUVu0sxSRnxcNdSfCmw4DKEAUF7uwBrS+9I0xMo4oMtuBvSlZOF/myOj1VQR3uHGrDmtv9RAi0zhjv6BIFFsdQ8ysQkY8HMi+HvUzLFJ6DzbOUzum0BO6ycimpq5dXGI06rUOjkJX+nuQX7ABgmXh6hDtaqgd9NQ0XKTmTMDc= Received: from MN0P221CA0003.NAMP221.PROD.OUTLOOK.COM (2603:10b6:208:52a::6) by CH3PR12MB8851.namprd12.prod.outlook.com (2603:10b6:610:180::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.15; Mon, 23 Mar 2026 07:46:14 +0000 Received: from BL6PEPF0001AB51.namprd04.prod.outlook.com (2603:10b6:208:52a:cafe::2e) by MN0P221CA0003.outlook.office365.com (2603:10b6:208:52a::6) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9723.31 via Frontend Transport; Mon, 23 Mar 2026 07:46:13 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb07.amd.com; pr=C Received: from satlexmb07.amd.com (165.204.84.17) by BL6PEPF0001AB51.mail.protection.outlook.com (10.167.242.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9723.19 via Frontend Transport; Mon, 23 Mar 2026 07:46:13 +0000 Received: from satlexmb10.amd.com (10.181.42.219) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Mon, 23 Mar 2026 02:46:11 -0500 Received: from satlexmb07.amd.com (10.181.42.216) by satlexmb10.amd.com (10.181.42.219) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Mon, 23 Mar 2026 02:46:10 -0500 Received: from xhdlakshmis40.xilinx.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Mon, 23 Mar 2026 02:46:07 -0500 From: Sai Krishna Potthuri To: Jonathan Cameron , David Lechner , Nuno Sa , Andy Shevchenko , Michal Simek , Rob Herring , Krzysztof Kozlowski , Conor Dooley CC: , , , , , , Sai Krishna Potthuri Subject: [PATCH v2 2/4] iio: adc: xilinx-xadc: Add .setup_channels() to struct xadc_ops Date: Mon, 23 Mar 2026 13:15:03 +0530 Message-ID: <20260323074505.3853353-3-sai.krishna.potthuri@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> References: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BL6PEPF0001AB51:EE_|CH3PR12MB8851:EE_ X-MS-Office365-Filtering-Correlation-Id: eed23862-262e-4b6b-ea6a-08de88b041ee X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700016|82310400026|1800799024|7416014|376014|22082099003|56012099003|18002099003; X-Microsoft-Antispam-Message-Info: x6v04Ad8yb7tHF301MgJvqqWtEZHSXgzNUFCqJxmn4DHgcaHMAUE6HGRHRuE5F5f6sNz91vcrTYR8h23wl8UfNEefiU3M93JkCUneBd4oquAEmB2Wa7JIMDcxtfloXatnbSHTB4UeXoD0H77po7p4oTALxD4fVd3bkqTizIcSzS59ipxTcZPe1JopFaZO78Z8O/p8BHqd6YtHkt8LV53ZdQDK/RfKhRbimBSdXehEsoZm79rDKCirItewvkGAvHV+7vJwquMfcZ1yYp4TuBfTWPmhi5Mze0ZXf6ttLsjfVNMMkkmk/UeA6A1viOODqtLMG1mmF56e8Hpq2hPkXVoxCSgFEsOD+y2dexcayYWUroxLx6RVGlmcZquR9Jm/hzoQim/zTFM8IxwZP2NfV8f3t3HJJ2OqPB49vWnMF3LHjybUPZychdFIsajQsN621SBzLlIx/T0t39Zm10LRLjkIQFTf+QPBr2NlWoLs92qEDfhiJDnZhMfDi/XthWcmbiQ/sbqOLuUkdGRssC79Hg3KHdLO8eMpowE8sFJJh3zYn32lAI+Xvm3VggMFrtzj3hLKriX9J79JTpo5SlMAlvC3hmDADdi6/B/7QV8cLJxGQm1MjWagDROWq92YY+ZV+7C86x8dLLnAb2RI7FjySh84ISSuNSDXXTLrziY57CH1L2iy/AZNN3UqADabt/yILdO7s3eLjFav42vliEdAXSSFfrIlaBcO8vUIuyYHpqTvFkW6Slu8AbGrCTn0JKvMpUt+bc6WLFwoMvf9ip2Tgs6rQ== X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:satlexmb07.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(36860700016)(82310400026)(1800799024)(7416014)(376014)(22082099003)(56012099003)(18002099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: H7+BY9k2ebRekqMAW9yPgGKF1RhKBEtzkbcwwu0j6/ZagB2Dnt843xh57ILzOIJrZypC8UvWZNBiS5JGXFakfdz2XaCMUeVm1nQeVE0gLkrOhlD0jZKynY9ZLNrpgyCtM2cIjz0JC0zNL5SWOKmMdeeSdYgEdwQSwoyDWVa0XHWBpaaZDG9Tr65upNkWzfzA7ij4++WU9xTw9tBuD1JjD0ZmaNW+WXzwYya9U8bfYvWVZPrafTkztEFGYbfityioi55LfeE4HTMFb6FJZ6tbgld92vZTvsPGsx9Y84wOQtQQjwOyA9rK4SsL620XK3rPaEzKA5ZuC685qTOKq1sptCvDvaio2Bs4Wur1LBxyyFoXt/wQcCzHVTDZwo+0QjtPXHXcCkbZcu/svzOzPGXY9md2qCV/NfYC1Kuj/B0z6uhGM2XOcG0tHFibjH+sCDja X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Mar 2026 07:46:13.4454 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: eed23862-262e-4b6b-ea6a-08de88b041ee X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[satlexmb07.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BL6PEPF0001AB51.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH3PR12MB8851 Content-Type: text/plain; charset="utf-8" Add .setup_channels() function pointer to struct xadc_ops to enable different interfaces to have custom channel setup logic. Signed-off-by: Sai Krishna Potthuri --- drivers/iio/adc/xilinx-xadc-core.c | 6 ++++-- drivers/iio/adc/xilinx-xadc-platform.c | 3 +++ drivers/iio/adc/xilinx-xadc.h | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xa= dc-core.c index 268e46e5349c..7fbf55f8e0bb 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -653,7 +653,7 @@ static const struct iio_info xadc_info =3D { .update_scan_mode =3D &xadc_update_scan_mode, }; =20 -static int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, in= t irq) +int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, int irq) { struct device *dev =3D indio_dev->dev.parent; struct xadc *xadc =3D iio_priv(indio_dev); @@ -760,6 +760,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, uns= igned int *conf, int irq) =20 return 0; } +EXPORT_SYMBOL_GPL(xadc_parse_dt); =20 const char * const xadc_type_names[] =3D { [XADC_TYPE_S7] =3D "xadc", @@ -791,10 +792,11 @@ int xadc_device_configure(struct device *dev, struct = iio_dev *indio_dev, int irq, unsigned int *conf0, unsigned int *bipolar_mask) { + struct xadc *xadc =3D iio_priv(indio_dev); int ret; u32 i; =20 - ret =3D xadc_parse_dt(indio_dev, conf0, irq); + ret =3D xadc->ops->setup_channels(indio_dev, conf0, irq); if (ret) return ret; =20 diff --git a/drivers/iio/adc/xilinx-xadc-platform.c b/drivers/iio/adc/xilin= x-xadc-platform.c index f1ffbf5cff42..9015b131daa3 100644 --- a/drivers/iio/adc/xilinx-xadc-platform.c +++ b/drivers/iio/adc/xilinx-xadc-platform.c @@ -401,6 +401,7 @@ static const struct xadc_ops xadc_zynq_ops =3D { .get_dclk_rate =3D xadc_zynq_get_dclk_rate, .interrupt_handler =3D xadc_zynq_interrupt_handler, .update_alarm =3D xadc_zynq_update_alarm, + .setup_channels =3D xadc_parse_dt, .type =3D XADC_TYPE_S7, /* Temp in C =3D (val * 503.975) / 2**bits - 273.15 */ .temp_scale =3D 503975, @@ -508,6 +509,7 @@ static const struct xadc_ops xadc_7s_axi_ops =3D { .get_dclk_rate =3D xadc_axi_get_dclk, .update_alarm =3D xadc_axi_update_alarm, .interrupt_handler =3D xadc_axi_interrupt_handler, + .setup_channels =3D xadc_parse_dt, .flags =3D XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL, .type =3D XADC_TYPE_S7, /* Temp in C =3D (val * 503.975) / 2**bits - 273.15 */ @@ -522,6 +524,7 @@ static const struct xadc_ops xadc_us_axi_ops =3D { .get_dclk_rate =3D xadc_axi_get_dclk, .update_alarm =3D xadc_axi_update_alarm, .interrupt_handler =3D xadc_axi_interrupt_handler, + .setup_channels =3D xadc_parse_dt, .flags =3D XADC_FLAGS_BUFFERED | XADC_FLAGS_IRQ_OPTIONAL, .type =3D XADC_TYPE_US, /** diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index a2d208fbd13b..feec8ef76e4f 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -82,6 +82,7 @@ struct xadc_ops { void (*update_alarm)(struct xadc *xadc, unsigned int alarm); unsigned long (*get_dclk_rate)(struct xadc *xadc); irqreturn_t (*interrupt_handler)(int irq, void *devid); + int (*setup_channels)(struct iio_dev *indio_dev, unsigned int *conf, int = irq); =20 unsigned int flags; enum xadc_type type; @@ -233,6 +234,7 @@ void xadc_write_reg(struct xadc *xadc, unsigned int reg= , uint32_t val); void xadc_read_reg(struct xadc *xadc, unsigned int reg, uint32_t *val); struct iio_dev *xadc_device_setup(struct device *dev, int size, const struct xadc_ops **ops); +int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, int irq); int xadc_device_configure(struct device *dev, struct iio_dev *indio_dev, int irq, unsigned int *conf0, unsigned int *bipolar_mask); int xadc_read_samplerate(struct xadc *xadc); --=20 2.25.1 From nobody Fri Apr 3 22:33:01 2026 Received: from CO1PR03CU002.outbound.protection.outlook.com (mail-westus2azon11010063.outbound.protection.outlook.com [52.101.46.63]) (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 3EA13364053; Mon, 23 Mar 2026 07:46:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.46.63 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251987; cv=fail; b=tvEMFECRRlO6omgrhdBeTaKDe2tAoqld2aVAVDzkkrL6wkoMt7ZSGCy9nOpoFdA7YBmvIFTBjcPlCddrQP8zE2hMwjY6PXLhsfmWFMCfkS1lxPa5cH+K5Eo83fOLx5a0G1+vMczQ9cn8BZ9lbpe0YzuKtNBbgSJuhzDfCVsqM4I= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251987; c=relaxed/simple; bh=gB8sTKP9Gd0ktIAK5pjrbgJ1eErUJvmzKJLjB6WPbrY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=q5gI2XrPrNPNLTrpXU56oCEgblLxIR9pHLJDSJI8k4otVeZ2UUsJYHIAvvwBXpeYfR3K0ryRNg/h07tsdmeghEx8GBY2X9IL6wJ3bLCZARve+R+DfIowxjz7lTPfVnfrxrwN/pKz3fFcvTST0tUVSQhMNSB8RBiv4nH+w/akVh4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=xSj21CCu; arc=fail smtp.client-ip=52.101.46.63 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="xSj21CCu" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=S0xs/xOhz8DuU1skVrJj09gkkqwto29WRlUNjsPy9FwY+LJ1FMKXhkiXR8xeS40Ur+w8MWVdwV59Ap3PX20nF3D82zwZZBENWJIVla/pkXRDg/4ut85Cp65To7qeiQeH287BxtPLIkGcFWLDg0bHIIfRZrNBOWBI21jnpSEfa9HZC1UW8wYEVXt+I2tKoCKg0ntav0Ia5q1FzIjurBCg9YpRhh7kN9rVk83Tdtq04tm3CKHHND+xvAvf/hc2o/6kyoVWfALlaQPhm/PET+/bcgJ5I7ejWBUjbMkMurkNpYNaa5uahgJIgylA4chvol140xmEXJV7fLq61qi65zx1oQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=PdJob3FigaIv6MGj21BovoPuxvgP9qQ0dLnWgLi4yWg=; b=uezhx7ln/nQ8ZVp69kyUUDRbr7MiDCrDhtaO6ubdshPuGmzmrmwv66dOkToeWJCtkuhZ/cqC8/parY4+go5VLfyxTZi4qan6Cav7zD3kvjmIOblBhQ5349G0wRKhEaUGwSc11vS5EKDVL9U+ZaS/BkFfSy8a7YA+pDCZioNam1Nsj+H3RTHeNhJtolY/7PyJH0yTAukhpP1ZXyAKsvJwg7vxutJWwhYC8jffT4mScKOY0B5MlTlqYRoChP1GyT83nPzG/fKbw1IAgUZufRQyX+/kQTC/Uo3VmLi4SwgOER70pR67zwQgakoM8RD837teJfTAGHK4TmgKlzwD4fdcUg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=PdJob3FigaIv6MGj21BovoPuxvgP9qQ0dLnWgLi4yWg=; b=xSj21CCu4KBKkgG2Qg7sEogkSF58MzgdQtTJj90Muf4SmsctdvE9M4RZMRp+hHF4hD3mEXPrcnDHlHVSHKKnl5HEAsnPaaCHGd/CzyPyzQHEmFvLEB/9IWeE2eKC086lOatBG5lIkuBN+I+yw3qQxTUqNXgvi7P/4dWrISWqwQ8= Received: from BL1PR13CA0314.namprd13.prod.outlook.com (2603:10b6:208:2c1::19) by DS0PR12MB9039.namprd12.prod.outlook.com (2603:10b6:8:de::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.20; Mon, 23 Mar 2026 07:46:17 +0000 Received: from BL6PEPF0001AB50.namprd04.prod.outlook.com (2603:10b6:208:2c1:cafe::f0) by BL1PR13CA0314.outlook.office365.com (2603:10b6:208:2c1::19) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9723.25 via Frontend Transport; Mon, 23 Mar 2026 07:46:09 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb07.amd.com; pr=C Received: from satlexmb07.amd.com (165.204.84.17) by BL6PEPF0001AB50.mail.protection.outlook.com (10.167.242.74) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9723.19 via Frontend Transport; Mon, 23 Mar 2026 07:46:16 +0000 Received: from SATLEXMB03.amd.com (10.181.40.144) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.2562.17; Mon, 23 Mar 2026 02:46:16 -0500 Received: from satlexmb07.amd.com (10.181.42.216) by SATLEXMB03.amd.com (10.181.40.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.39; Mon, 23 Mar 2026 02:46:14 -0500 Received: from xhdlakshmis40.xilinx.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Mon, 23 Mar 2026 02:46:11 -0500 From: Sai Krishna Potthuri To: Jonathan Cameron , David Lechner , Nuno Sa , Andy Shevchenko , Michal Simek , Rob Herring , Krzysztof Kozlowski , Conor Dooley CC: , , , , , , Sai Krishna Potthuri Subject: [PATCH v2 3/4] iio: adc: xilinx-xadc: Add I2C interface support Date: Mon, 23 Mar 2026 13:15:04 +0530 Message-ID: <20260323074505.3853353-4-sai.krishna.potthuri@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> References: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: None (SATLEXMB03.amd.com: sai.krishna.potthuri@amd.com does not designate permitted sender hosts) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BL6PEPF0001AB50:EE_|DS0PR12MB9039:EE_ X-MS-Office365-Filtering-Correlation-Id: 7039d6e7-c9c6-4343-8300-08de88b04400 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|82310400026|7416014|376014|36860700016|56012099003|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: zzY3Xl+ymfcgHWkyxoFcV+seqImnxIu8lvzu1vGnFIVCwVQ5steefcJRbfo8MC/6Y8j1L9kednTYLGtIh5Q/XpHTJBWWGTa5ffKbfoDrCbkNxaNyS9G22LdKRPZ7MpfhJLbdQE1VH+hnUNlfJRLrV58V8MCu3cVwNwz9MinsBZem7XGm9EAsRGM+7An31YsqyQu8Fz003H2r3Dyi0IV5dY361OgTVzaVxvYeYOolVMpBFo0yYHfp92h5ZNBk6GR0zkLmxCBKxEDGoKl/xTLUBCzE7wBRfhpyE4XEdwI60AldBXkKXXCbNyNxUYEMapGOw/f53XijILHLlMZTbAhZCvoJm8lfNEgm37e4oh1cbUEgjm8TyirsFamkimL1jhAKTUDeNRsjDu6/N28iN/HycIJH2hyVcB5o/5ckU0bYz2Ey63b82VbC1VStJkozd0sZQgm+QPdgBo5ZhGdt1ijQPhMS8vqAzNNuQFEZC7QoaAUu0PIcKmwlJcEG638iKYiQ59MP0RSt3xv60RNWMxSzWvVu8pbG7zoQFYVyfN+7axM2nc9/6wHo1i98dhtOLiLpiVuP8HBQAQ0evPZfCRYU4wctRtz2FY32xy85vah7Yv6rftYMby9ahjLXeDi1NVfCXIZBIUD/OGbH8zOm2qogam5gIk9JSZ8Ye9IzjzhVf40XSDml71ce3ImBSI+Wmcd6cmaDMWHlXHZflgEidtyIsZpvMUM0GVLiipekkYF2e86ap7l42wsLgpQAcewUMtHz2Z5FHR6jG3jXEj/s74a3wg== X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:satlexmb07.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(1800799024)(82310400026)(7416014)(376014)(36860700016)(56012099003)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: N/0nLKGL2feHyJjj5h7zTtPtTVWY3DNct+hxsQOZhQHXkMDiyMkxOqMJf0rU/jTwmv6uAmOn8o76PMXQjHo70HqePvfpW5gX+lliY5waM+XD4YVJ6EEVo762BmXE7zsQ4Q9tAphucgtqSkiEkzDraii2McfhBmepPU6c9s8C0PX0qoNlmOG/bejLRlgpT6ApRKgzb4QK94hnHjQJLJS0F7JmHqynXSarqy4qAY6vxrJMpVBtzP4vzK/n+bDOZiTHWoRaDG6H+By3oUtKPdCOoscWTyg2UH5omR5nHd1D1sdGDtioGSKHzKTH16x9VR+jQzW6VFJop5w3JaU42Y/9Tx4rXqRrDiljBJAtMrUYXltcZogS0dI/zYFH25ETh54k216IWlPta8j8jnNbWxswDU9wuI/es6AnJlyuck+rzTHbHe/BfpFPVFxhqYMqJyRe X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Mar 2026 07:46:16.9256 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7039d6e7-c9c6-4343-8300-08de88b04400 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[satlexmb07.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BL6PEPF0001AB50.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS0PR12MB9039 Content-Type: text/plain; charset="utf-8" Add I2C interface support for Xilinx System Management Wizard IP along with the existing AXI memory-mapped interface. This support enables monitoring the voltage and temperature on UltraScale+ devices where the System Management Wizard is connected via I2C. Key changes: - Implement 32-bit DRP(Dynamic Reconfiguration Port) packet format as per Xilinx PG185 specification. - Add separate I2C probe with xadc_i2c_of_match_table to handle same compatible string("xlnx,system-management-wiz-1.3") on I2C bus. - Implement delayed version of hardware initialization for I2C interface to handle the case where System Management Wizard IP is not ready during the I2C probe. - Add NULL checks for get_dclk_rate callback function in sampling rate functions to support interfaces without clock control - Create separate iio_info structure(xadc_i2c_info) without event callbacks for I2C devices - Add xadc_i2c_transaction() function to handle I2C read/write operations - Add XADC_TYPE_US_I2C type to distinguish I2C interface from AXI Signed-off-by: Sai Krishna Potthuri --- drivers/iio/adc/Kconfig | 15 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/xilinx-xadc-core.c | 28 +++- drivers/iio/adc/xilinx-xadc-i2c.c | 215 +++++++++++++++++++++++++++++ drivers/iio/adc/xilinx-xadc.h | 1 + 5 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 drivers/iio/adc/xilinx-xadc-i2c.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index a4a7556f4016..5a3956a5c086 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1767,6 +1767,21 @@ config XILINX_XADC The driver can also be build as a module. If so, the module will be cal= led xilinx-xadc. =20 +config XILINX_XADC_I2C + tristate "Xilinx System Management Wizard I2C Interface support" + depends on I2C + select XILINX_XADC_CORE + help + Say yes here to allow accessing the System Management + Wizard on UltraScale+ devices via I2C. + + This provides voltage and temperature monitoring capabilities + through the same IIO sysfs interface, but using I2C communication + protocol. + + The driver can also be build as a module. If so, the module will be cal= led + xilinx-xadc-i2c. + config XILINX_AMS tristate "Xilinx AMS driver" depends on ARCH_ZYNQMP || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 1b05176f0098..2dc08c9d82cc 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -157,3 +157,4 @@ obj-$(CONFIG_XILINX_AMS) +=3D xilinx-ams.o xilinx-xadc-common-y :=3D xilinx-xadc-core.o xilinx-xadc-events.o obj-$(CONFIG_XILINX_XADC_CORE) +=3D xilinx-xadc-common.o obj-$(CONFIG_XILINX_XADC) +=3D xilinx-xadc-platform.o +obj-$(CONFIG_XILINX_XADC_I2C) +=3D xilinx-xadc-i2c.o diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xa= dc-core.c index 7fbf55f8e0bb..383bd93676ec 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -222,7 +222,8 @@ static int xadc_power_adc_b(struct xadc *xadc, unsigned= int seq_mode) * non-existing ADC-B powers down the main ADC, so just return and don't * do anything. */ - if (xadc->ops->type =3D=3D XADC_TYPE_US) + if (xadc->ops->type =3D=3D XADC_TYPE_US || + xadc->ops->type =3D=3D XADC_TYPE_US_I2C) return 0; =20 /* Powerdown the ADC-B when it is not needed. */ @@ -245,7 +246,8 @@ static int xadc_get_seq_mode(struct xadc *xadc, unsigne= d long scan_mode) unsigned int aux_scan_mode =3D scan_mode >> 16; =20 /* UltraScale has only one ADC and supports only continuous mode */ - if (xadc->ops->type =3D=3D XADC_TYPE_US) + if (xadc->ops->type =3D=3D XADC_TYPE_US || + xadc->ops->type =3D=3D XADC_TYPE_US_I2C) return XADC_CONF1_SEQ_CONTINUOUS; =20 if (xadc->external_mux_mode =3D=3D XADC_EXTERNAL_MUX_DUAL) @@ -346,6 +348,9 @@ int xadc_read_samplerate(struct xadc *xadc) uint16_t val16; int ret; =20 + if (!xadc->ops->get_dclk_rate) + return -EOPNOTSUPP; + ret =3D xadc_read_adc_reg(xadc, XADC_REG_CONF2, &val16); if (ret) return ret; @@ -457,9 +462,14 @@ EXPORT_SYMBOL_GPL(xadc_setup_buffer_and_triggers); =20 int xadc_write_samplerate(struct xadc *xadc, int val) { - unsigned long clk_rate =3D xadc_get_dclk_rate(xadc); + unsigned long clk_rate; unsigned int div; =20 + if (!xadc->ops->get_dclk_rate) + return -EOPNOTSUPP; + + clk_rate =3D xadc_get_dclk_rate(xadc); + if (!clk_rate) return -EINVAL; =20 @@ -653,6 +663,11 @@ static const struct iio_info xadc_info =3D { .update_scan_mode =3D &xadc_update_scan_mode, }; =20 +static const struct iio_info xadc_i2c_info =3D { + .read_raw =3D &xadc_read_raw, + .write_raw =3D &xadc_write_raw, +}; + int xadc_parse_dt(struct iio_dev *indio_dev, unsigned int *conf, int irq) { struct device *dev =3D indio_dev->dev.parent; @@ -765,6 +780,7 @@ EXPORT_SYMBOL_GPL(xadc_parse_dt); const char * const xadc_type_names[] =3D { [XADC_TYPE_S7] =3D "xadc", [XADC_TYPE_US] =3D "xilinx-system-monitor", + [XADC_TYPE_US_I2C] =3D "xilinx-system-monitor", }; =20 struct iio_dev *xadc_device_setup(struct device *dev, int size, @@ -781,7 +797,11 @@ struct iio_dev *xadc_device_setup(struct device *dev, = int size, return ERR_PTR(-ENOMEM); =20 indio_dev->name =3D xadc_type_names[(*ops)->type]; - indio_dev->info =3D &xadc_info; + if ((*ops)->type =3D=3D XADC_TYPE_US_I2C) + indio_dev->info =3D &xadc_i2c_info; + else + indio_dev->info =3D &xadc_info; + indio_dev->modes =3D INDIO_DIRECT_MODE; =20 return indio_dev; diff --git a/drivers/iio/adc/xilinx-xadc-i2c.c b/drivers/iio/adc/xilinx-xad= c-i2c.c new file mode 100644 index 000000000000..3d802b907260 --- /dev/null +++ b/drivers/iio/adc/xilinx-xadc-i2c.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx XADC I2C Interface Driver + * + * Copyright (C) 2026 Advanced Micro Devices, Inc. + * + * This driver implements I2C interface support for Xilinx System Manageme= nt + * Wizard IP on UltraScale+ devices. It uses the 32-bit DRP (Dynamic + * Reconfiguration Port) packet format as per Xilinx PG185 specification. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xilinx-xadc.h" + +#define XADC_I2C_READ_DATA_SIZE 2 +#define XADC_I2C_WRITE_DATA_SIZE 4 /* 32-bit DRP packet */ +#define XADC_I2C_INSTR_READ BIT(2) +#define XADC_I2C_INSTR_WRITE BIT(3) + +#define XADC_I2C_DRP_DATA0_MASK GENMASK(7, 0) +#define XADC_I2C_DRP_DATA1_MASK GENMASK(15, 8) +#define XADC_I2C_DRP_ADDR_MASK GENMASK(7, 0) + +#define XADC_INPUT_MODE_BITS 16 + +struct xadc_i2c { + struct xadc xadc; + struct i2c_client *client; + bool hw_initialized; + unsigned int conf0; + unsigned int bipolar_mask; +}; + +static int xadc_i2c_read_transaction(struct xadc *xadc, unsigned int reg, = u16 *val) +{ + struct xadc_i2c *xadc_i2c =3D container_of(xadc, struct xadc_i2c, xadc); + char write_buffer[XADC_I2C_WRITE_DATA_SIZE] =3D { 0 }; + struct i2c_client *client =3D xadc_i2c->client; + char read_buffer[XADC_I2C_READ_DATA_SIZE]; + int ret; + + write_buffer[2] =3D FIELD_GET(XADC_I2C_DRP_ADDR_MASK, reg); + write_buffer[3] =3D XADC_I2C_INSTR_READ; + + ret =3D i2c_master_send(client, write_buffer, XADC_I2C_WRITE_DATA_SIZE); + if (ret < 0) + return ret; + + ret =3D i2c_master_recv(client, read_buffer, XADC_I2C_READ_DATA_SIZE); + if (ret < 0) + return ret; + + *val =3D FIELD_PREP(XADC_I2C_DRP_DATA0_MASK, read_buffer[0]) | + FIELD_PREP(XADC_I2C_DRP_DATA1_MASK, read_buffer[1]); + + return 0; +} + +static int xadc_i2c_write_transaction(struct xadc *xadc, unsigned int reg,= u16 val) +{ + struct xadc_i2c *xadc_i2c =3D container_of(xadc, struct xadc_i2c, xadc); + struct i2c_client *client =3D xadc_i2c->client; + char write_buffer[XADC_I2C_WRITE_DATA_SIZE]; + int ret; + + write_buffer[0] =3D FIELD_GET(XADC_I2C_DRP_DATA0_MASK, val); + write_buffer[1] =3D FIELD_GET(XADC_I2C_DRP_DATA1_MASK, val); + write_buffer[2] =3D FIELD_GET(XADC_I2C_DRP_ADDR_MASK, reg); + write_buffer[3] =3D XADC_I2C_INSTR_WRITE; + + ret =3D i2c_master_send(client, write_buffer, XADC_I2C_WRITE_DATA_SIZE); + if (ret < 0) + return ret; + + return 0; +} + +static int xadc_hardware_init(struct xadc *xadc) +{ + struct xadc_i2c *xadc_i2c =3D container_of(xadc, struct xadc_i2c, xadc); + int ret; + u32 i; + + for (i =3D 0; i < ARRAY_SIZE(xadc->threshold); i++) { + ret =3D xadc_i2c_read_transaction(xadc, XADC_REG_THRESHOLD(i), + &xadc->threshold[i]); + if (ret) + return ret; + } + + ret =3D xadc_i2c_write_transaction(xadc, XADC_REG_CONF0, xadc_i2c->conf0); + if (ret) + return ret; + + ret =3D xadc_i2c_write_transaction(xadc, XADC_REG_INPUT_MODE(0), + xadc_i2c->bipolar_mask); + if (ret) + return ret; + + ret =3D xadc_i2c_write_transaction(xadc, XADC_REG_INPUT_MODE(1), + xadc_i2c->bipolar_mask >> XADC_INPUT_MODE_BITS); + if (ret) + return ret; + + xadc_i2c->hw_initialized =3D true; + + return 0; +} + +static int xadc_i2c_read_reg(struct xadc *xadc, unsigned int reg, u16 *val) +{ + struct xadc_i2c *xadc_i2c =3D container_of(xadc, struct xadc_i2c, xadc); + + if (!xadc_i2c->hw_initialized) { + int ret; + + ret =3D xadc_hardware_init(xadc); + if (ret) + return ret; + } + + return xadc_i2c_read_transaction(xadc, reg, val); +} + +static int xadc_i2c_write_reg(struct xadc *xadc, unsigned int reg, u16 val) +{ + struct xadc_i2c *xadc_i2c =3D container_of(xadc, struct xadc_i2c, xadc); + + if (!xadc_i2c->hw_initialized) { + int ret; + + ret =3D xadc_hardware_init(xadc); + if (ret) + return ret; + } + + return xadc_i2c_write_transaction(xadc, reg, val); +} + +static const struct xadc_ops xadc_system_mgmt_wiz_i2c_ops =3D { + .read =3D xadc_i2c_read_reg, + .write =3D xadc_i2c_write_reg, + .setup_channels =3D xadc_parse_dt, + .type =3D XADC_TYPE_US_I2C, + .temp_scale =3D 509314, + .temp_offset =3D 280231, +}; + +static int xadc_i2c_probe(struct i2c_client *client) +{ + struct device *dev =3D &client->dev; + unsigned int conf0, bipolar_mask; + const struct xadc_ops *ops; + struct iio_dev *indio_dev; + struct xadc_i2c *xadc_i2c; + struct xadc *xadc; + int ret; + + indio_dev =3D xadc_device_setup(dev, sizeof(*xadc_i2c), &ops); + if (IS_ERR(indio_dev)) + return PTR_ERR(indio_dev); + + xadc_i2c =3D iio_priv(indio_dev); + xadc_i2c->client =3D client; + xadc =3D &xadc_i2c->xadc; + xadc->clk =3D NULL; + xadc->ops =3D ops; + mutex_init(&xadc->mutex); + spin_lock_init(&xadc->lock); + + ret =3D xadc_device_configure(dev, indio_dev, 0, &conf0, &bipolar_mask); + if (ret) { + dev_err(dev, "Failed to setup the device: %d\n", ret); + return ret; + } + + i2c_set_clientdata(client, indio_dev); + xadc_i2c->conf0 =3D conf0; + xadc_i2c->bipolar_mask =3D bipolar_mask; + xadc_i2c->hw_initialized =3D false; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id xadc_i2c_of_match_table[] =3D { + { + .compatible =3D "xlnx,system-management-wiz-1.3", + .data =3D &xadc_system_mgmt_wiz_i2c_ops, + }, + { } +}; +MODULE_DEVICE_TABLE(of, xadc_i2c_of_match_table); + +static struct i2c_driver xadc_i2c_driver =3D { + .probe =3D xadc_i2c_probe, + .driver =3D { + .name =3D "xadc-i2c", + .of_match_table =3D xadc_i2c_of_match_table, + }, +}; +module_i2c_driver(xadc_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sai Krishna Potthuri "); +MODULE_DESCRIPTION("Xilinx XADC I2C Interface Driver"); diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index feec8ef76e4f..d0c64b5f55f1 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -72,6 +72,7 @@ struct xadc { enum xadc_type { XADC_TYPE_S7, /* Series 7 */ XADC_TYPE_US, /* UltraScale and UltraScale+ */ + XADC_TYPE_US_I2C, /* UltraScale+ I2C interface */ }; =20 struct xadc_ops { --=20 2.25.1 From nobody Fri Apr 3 22:33:01 2026 Received: from BN8PR05CU002.outbound.protection.outlook.com (mail-eastus2azon11011013.outbound.protection.outlook.com [52.101.57.13]) (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 74A18364029; Mon, 23 Mar 2026 07:46:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.57.13 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251990; cv=fail; b=AADPHbpFTy6NUq7LII9WWr56y1Y044IYqBrAyN9gKzBaj94RonlBxj9dZjVDuOb/SPcsAaYt1mrmsf20XTwEwp4y4vouLwkvPGyqFSUQThWfNqtdCXj/LPSis+uwpmXxW9Msg42tiMX7cEH4O9whDp3VBr7spzn5fbjcK3RLlgA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774251990; c=relaxed/simple; bh=FxCTv5PWrtLeMkYxagbLgkKYO7D5QdEyp4QgIT6zNOM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=poJ6FLfNLK3LHl3sA/FbJXnTGSauFfQ7oR2YZdAgGW6QR9u/qZL2alV8WAXRfMyhb+oDSvfLOUkDmMpLkmzmRqbnEzkzl6M14GKTI203qtIycaKHQX1nbNpCpAwY7374vR7hFE7Y/DQiT9z6aqrsLjAPGTn3pkOHI/9Qvpq7mQY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=Rfab8b2k; arc=fail smtp.client-ip=52.101.57.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="Rfab8b2k" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=oOV3RiD3YUtHqJTE7ngI4K/TIQ8C0aa02OW3mWBwS0DcL8xvQ1+suBYlodd1my0SOtKceHB33wgkpMVcpPFLaYw65tmstSfBQOkXs/rdc3ggQZhnIKg7PoJoha2PmHNPQsgz2gQrom50i3Mg2yIuav5HsJe4v8J7sn0b5t4nKQNMuBIh9D6ZRXTZnhjLV6edWdu5znzcAN67gkyaXuQl3Surjpg01lMrQDvLDpD8hJYDy822ZURXqYyiNQfUTUpMr66jUFAUhhUyKovk67v3L9mjZHilh1UZpMJUtx+mLTO96AlsKmgeS39qicSh88Y2DkOPe6fuMa9FI3GHZTpC9w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=n9MdYhasxLC4ZQk3/Kl7zCKc2Zrw/FHUwCXqWAqPBBs=; b=Fqrqwj4/rQ6R5ym/tuSF+fho65Mu6SYcpJ7iDcqzTYF7YFFzAZmNOo6S0lNlj2Klqne7GZLXRpAVRq492nd0wWQcnS5I3s9Z1ZRDAU8ykuQmm7TKDTP7c72bgQRYJRSjRinYlgYMy8+cU9v8boH392R3wbLwFU0ujwOpZ940cXf4pGVSG2QoUwm7o6R0r6n9zuZjwiKidcxhHaCLYHS/MxZMuRyGecTiFNoFyZKHxbEK8N9+jrRvcgXTBNAIVLO/n8WqHbzys3/nJmEmRNZeCligoh9PmaBeNOBUHsXGEOHVkZrXWMStlKWo7G/uYMAh6hnaRWxKxkmjtI3ETCNFMw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=kernel.org smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=n9MdYhasxLC4ZQk3/Kl7zCKc2Zrw/FHUwCXqWAqPBBs=; b=Rfab8b2kKwgVgKB5rM8hVQhLG7iFWKNekMMfGcVKXRRl45/W/EhF8e9ljVz6+WY9OQ55RG7hXhTjtXbaZFEB7vyvm34t+m9B1hekV5JqpQJV4TOsxxQRfhgnDsRC+S7erv7xhGcupdPe97DwFn63Ldx+FiRmJPzc0u6T2nCBD4A= Received: from MN2PR05CA0036.namprd05.prod.outlook.com (2603:10b6:208:c0::49) by SJ1PR12MB6364.namprd12.prod.outlook.com (2603:10b6:a03:452::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.20; Mon, 23 Mar 2026 07:46:20 +0000 Received: from BL6PEPF0001AB4C.namprd04.prod.outlook.com (2603:10b6:208:c0:cafe::70) by MN2PR05CA0036.outlook.office365.com (2603:10b6:208:c0::49) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9723.31 via Frontend Transport; Mon, 23 Mar 2026 07:46:19 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb07.amd.com; pr=C Received: from satlexmb07.amd.com (165.204.84.17) by BL6PEPF0001AB4C.mail.protection.outlook.com (10.167.242.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9723.19 via Frontend Transport; Mon, 23 Mar 2026 07:46:19 +0000 Received: from satlexmb07.amd.com (10.181.42.216) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.17; Mon, 23 Mar 2026 02:46:18 -0500 Received: from xhdlakshmis40.xilinx.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server id 15.2.2562.17 via Frontend Transport; Mon, 23 Mar 2026 02:46:15 -0500 From: Sai Krishna Potthuri To: Jonathan Cameron , David Lechner , Nuno Sa , Andy Shevchenko , Michal Simek , Rob Herring , Krzysztof Kozlowski , Conor Dooley CC: , , , , , , Sai Krishna Potthuri Subject: [PATCH v2 4/4] dt-bindings: iio: adc: xlnx,axi-xadc: convert to DT schema Date: Mon, 23 Mar 2026 13:15:05 +0530 Message-ID: <20260323074505.3853353-5-sai.krishna.potthuri@amd.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> References: <20260323074505.3853353-1-sai.krishna.potthuri@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BL6PEPF0001AB4C:EE_|SJ1PR12MB6364:EE_ X-MS-Office365-Filtering-Correlation-Id: a8146aba-334b-4feb-52ab-08de88b045b7 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|1800799024|36860700016|376014|7416014|13003099007|18002099003|22082099003|56012099003; X-Microsoft-Antispam-Message-Info: 8JnHcOpgE7gnEsrQbmdYZjasFgkjym/N83IhiFiWE6UTKwcDnbqis371H8/EhbFzMaQ9gAE5xloXY9MJrUjAPqxlWZPHBHtcuUvD5KpCT3qCsE5gbhrvWG+Y9me16YLAYOZvvnq1qN7a3bTwDr0BekulLBpH6YuV0wXHS8VqG6UHFXByqclAE66Lps4Z3ZcDPpyQXwI67s1UV4jOs8wTZSgz9/6t2wD9K2TPR76UjQ+g9WHj8mpr9ny++P8WmFhhDs9R6Uy5ZRJZyp4ML8Npw9Ibl7u4zkqAVuqZxUjq5CiXin2zoPyCj7Wcz+r5O6qecuu/M0GJVapPaGr1MsN4xtAW4dAbEjXjuyf/WwbzQ15+J15RSznP090erqTZtsV9PNC7DYkNxwkabClc6HmfmCMyutrq0lrTIKNGmxm2GklR3vyOLHwJdSQE8OEGGNdHwjKScgL3IKch+8QTXxJOEdBA+BwOTsyxZnVdvNKQy5MDHIfaFFy5JUMITW6qPkZq5fTWRLCI4AkduybwWvChUyN4HqXvwLIFWR1nRStskcR/sMAC8tJOxIJQQenzVXWdMgxwHU6Kq9CTBMbxYuVeqj92Bbllxt/INhG3vxQFsPhyWTTGgha0CLooiYL5MoY3QEMbkKg+y2yxQPefvc5fYNuV884AVZfwzc1s5uvsqp8WGJbdXfey1tLLobLIvrm30dW8sjqa7p74/3SFRt2JSnkAxtIYrnf4BrUYkYcyMcM= X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:satlexmb07.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(1800799024)(36860700016)(376014)(7416014)(13003099007)(18002099003)(22082099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: WW0eFh77wgbN1ty92zWSR4XG0KaGY+7I8/WkO8W5usZLZD2AeRIB4PEv/Lv2AWtr0GCNwdSgwBritHSRBVXO1EHVJhoqgLlKtRmW1Tx10pTGZyEyssZAFMwnlByKxgORzWbwR26xHF88rQIM5fyqvk7RXYWZs2kHLNU5TtxXaYjSE8b630JAYstHcU8q8iUH1QY1xQvRvsu06yel202bjFBCa4HHa/7GovoZdldSB5FgjvT8yHeExFra266CI3FkLYUQJbgHEFsMhrq8NutXg5mAUbOufs4oxoMfBwbqVLpWw8YTr0UTCDozgwsvQjHSPHyrLLz7cERCtkrb95X33u5iMbr8IXp9cr6Jj9eOJSIDobbrzJDidO9JRxMEyboyukv1Kg57sH4pNqCa1Tp0GuKktlq5GH0L/579ZVh/LkYZJev8iu9oE6a3OYD0m/K1 X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Mar 2026 07:46:19.8011 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: a8146aba-334b-4feb-52ab-08de88b045b7 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[satlexmb07.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BL6PEPF0001AB4C.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ1PR12MB6364 Content-Type: text/plain; charset="utf-8" Convert the xilinx-xadc.txt to DT schema and remove the old text binding. Update xilinx-xadc binding path to YAML format in MAINTAINERS file. The 'xlnx,channels' property is a container node(type: object) with a vendor prefix, which triggers the below warning: "properties:xlnx,channels:type: 'boolean' was expected" This cannot be changed because the original text binding specified 'xlnx,channels' since 2014, driver explicitly looks up "xlnx,channels" using device_get_named_child_node() and removing the vendor prefix would break backward compatibility with existing device trees. Also, keep all vendor-prefixed properties from the original binding to maintain backward compatibility with existing devicetrees and driver code. Signed-off-by: Sai Krishna Potthuri --- .../bindings/iio/adc/xilinx-xadc.txt | 141 ---------------- .../bindings/iio/adc/xlnx,axi-xadc.yaml | 154 ++++++++++++++++++ 2 files changed, 154 insertions(+), 141 deletions(-) delete mode 100644 Documentation/devicetree/bindings/iio/adc/xilinx-xadc.t= xt create mode 100644 Documentation/devicetree/bindings/iio/adc/xlnx,axi-xadc= .yaml diff --git a/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt b/Do= cumentation/devicetree/bindings/iio/adc/xilinx-xadc.txt deleted file mode 100644 index f42e18078376..000000000000 --- a/Documentation/devicetree/bindings/iio/adc/xilinx-xadc.txt +++ /dev/null @@ -1,141 +0,0 @@ -Xilinx XADC device driver - -This binding document describes the bindings for the Xilinx 7 Series XADC = as well -as the UltraScale/UltraScale+ System Monitor. - -The Xilinx XADC is an ADC that can be found in the Series 7 FPGAs from Xil= inx. -The XADC has a DRP interface for communication. Currently two different -frontends for the DRP interface exist. One that is only available on the Z= YNQ -family as a hardmacro in the SoC portion of the ZYNQ. The other one is ava= ilable -on all series 7 platforms and is a softmacro with a AXI interface. This bi= nding -document describes the bindings for both of them since the bindings are ve= ry -similar. - -The Xilinx System Monitor is an ADC that is found in the UltraScale and -UltraScale+ FPGAs from Xilinx. The System Monitor provides a DRP interface= for -communication. Xilinx provides a standard IP core that can be used to acce= ss the -System Monitor through an AXI interface in the FPGA fabric. This IP core is -called the Xilinx System Management Wizard. This document describes the bi= ndings -for this IP. - -Required properties: - - compatible: Should be one of - * "xlnx,zynq-xadc-1.00.a": When using the ZYNQ device - configuration interface to interface to the XADC hardmacro. - * "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to - interface to the XADC hardmacro. - * "xlnx,system-management-wiz-1.3": When using the - Xilinx System Management Wizard fabric IP core to access the - UltraScale and UltraScale+ System Monitor. - - reg: Address and length of the register set for the device - - interrupts: Interrupt for the XADC control interface. - - clocks: When using the ZYNQ this must be the ZYNQ PCAP clock, - when using the axi-xadc or the axi-system-management-wizard this must be - the clock that provides the clock to the AXI bus interface of the core. - -Optional properties: - - xlnx,external-mux: - * "none": No external multiplexer is used, this is the default - if the property is omitted. - * "single": External multiplexer mode is used with one - multiplexer. - * "dual": External multiplexer mode is used with two - multiplexers for simultaneous sampling. - - xlnx,external-mux-channel: Configures which pair of pins is used to - sample data in external mux mode. - Valid values for single external multiplexer mode are: - 0: VP/VN - 1: VAUXP[0]/VAUXN[0] - 2: VAUXP[1]/VAUXN[1] - ... - 16: VAUXP[15]/VAUXN[15] - Valid values for dual external multiplexer mode are: - 1: VAUXP[0]/VAUXN[0] - VAUXP[8]/VAUXN[8] - 2: VAUXP[1]/VAUXN[1] - VAUXP[9]/VAUXN[9] - ... - 8: VAUXP[7]/VAUXN[7] - VAUXP[15]/VAUXN[15] - - This property needs to be present if the device is configured for - external multiplexer mode (either single or dual). If the device is - not using external multiplexer mode the property is ignored. - - xnlx,channels: List of external channels that are connected to the ADC - Required properties: - * #address-cells: Should be 1. - * #size-cells: Should be 0. - - The child nodes of this node represent the external channels which are - connected to the ADC. If the property is no present no external - channels will be assumed to be connected. - - Each child node represents one channel and has the following - properties: - Required properties: - * reg: Pair of pins the channel is connected to. - 0: VP/VN - 1: VAUXP[0]/VAUXN[0] - 2: VAUXP[1]/VAUXN[1] - ... - 16: VAUXP[15]/VAUXN[15] - Note each channel number should only be used at most - once. - Optional properties: - * xlnx,bipolar: If set the channel is used in bipolar - mode. - - -Examples: - xadc@f8007100 { - compatible =3D "xlnx,zynq-xadc-1.00.a"; - reg =3D <0xf8007100 0x20>; - interrupts =3D <0 7 4>; - interrupt-parent =3D <&gic>; - clocks =3D <&pcap_clk>; - - xlnx,channels { - #address-cells =3D <1>; - #size-cells =3D <0>; - channel@0 { - reg =3D <0>; - }; - channel@1 { - reg =3D <1>; - }; - channel@8 { - reg =3D <8>; - }; - }; - }; - - xadc@43200000 { - compatible =3D "xlnx,axi-xadc-1.00.a"; - reg =3D <0x43200000 0x1000>; - interrupts =3D <0 53 4>; - interrupt-parent =3D <&gic>; - clocks =3D <&fpga1_clk>; - - xlnx,channels { - #address-cells =3D <1>; - #size-cells =3D <0>; - channel@0 { - reg =3D <0>; - xlnx,bipolar; - }; - }; - }; - - adc@80000000 { - compatible =3D "xlnx,system-management-wiz-1.3"; - reg =3D <0x80000000 0x1000>; - interrupts =3D <0 81 4>; - interrupt-parent =3D <&gic>; - clocks =3D <&fpga1_clk>; - - xlnx,channels { - #address-cells =3D <1>; - #size-cells =3D <0>; - channel@0 { - reg =3D <0>; - xlnx,bipolar; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/iio/adc/xlnx,axi-xadc.yaml b= /Documentation/devicetree/bindings/iio/adc/xlnx,axi-xadc.yaml new file mode 100644 index 000000000000..e384928d60eb --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/xlnx,axi-xadc.yaml @@ -0,0 +1,154 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/xlnx,axi-xadc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx XADC and System Monitor ADC + +description: + The Xilinx XADC is an ADC that can be found in the Series 7 FPGAs from + Xilinx. The XADC has a DRP interface for communication. Currently two + different frontends for the DRP interface exist. One that is only availa= ble + on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The ot= her + one is available on all series 7 platforms and is a softmacro with an AXI + interface. + + The Xilinx System Monitor is an ADC that is found in the UltraScale and + UltraScale+ FPGAs from Xilinx. The System Monitor provides a DRP interfa= ce + for communication. Xilinx provides a standard IP core that can be used to + access the System Monitor through an AXI interface in the FPGA fabric. T= his + IP core is called the Xilinx System Management Wizard. + +maintainers: + - Lars-Peter Clausen + - Sai Krishna Potthuri + +properties: + compatible: + enum: + - xlnx,zynq-xadc-1.00.a + - xlnx,axi-xadc-1.00.a + - xlnx,system-management-wiz-1.3 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + description: + When using the ZYNQ this must be the ZYNQ PCAP clock, + when using the axi-xadc or the axi-system-management-wizard this mus= t be + the clock that provides the clock to the AXI bus interface of the co= re. + + xlnx,external-mux: + $ref: /schemas/types.yaml#/definitions/string + enum: + - none + - single + - dual + default: none + description: | + External multiplexer configuration: + - "none": No external multiplexer is used + - "single": External multiplexer mode is used with one multiplexer + - "dual": External multiplexer mode is used with two multiplexers + for simultaneous sampling + + xlnx,external-mux-channel: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 16 + description: | + Configures which pair of pins is used to sample data in external mux= mode. + Valid values for single external multiplexer mode are 0-16: + 0: VP/VN + 1-16: VAUXP[0-15]/VAUXN[0-15] + Valid values for dual external multiplexer mode are 1-8: + 1-8: VAUXP[0-7]/VAUXN[0-7] - VAUXP[8-15]/VAUXN[8-15] + This property needs to be present if the device is configured for + external multiplexer mode (either single or dual). + + xlnx,channels: + description: List of external channels that are connected to the ADC + type: object + properties: + '#address-cells': + const: 1 + '#size-cells': + const: 0 + + patternProperties: + "^channel@([0-9]|1[0-6])$": + type: object + properties: + reg: + minimum: 0 + maximum: 16 + description: | + Pair of pins the channel is connected to: + 0: VP/VN + 1-16: VAUXP[0-15]/VAUXN[0-15] + Note each channel number should only be used at most once. + + xlnx,bipolar: + type: boolean + description: If set, the channel is used in bipolar mode + + required: + - reg + + additionalProperties: false + + required: + - '#address-cells' + - '#size-cells' + + additionalProperties: false + +allOf: + - if: + required: + - xlnx,external-mux + properties: + xlnx,external-mux: + enum: + - single + - dual + then: + required: + - xlnx,external-mux-channel + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + #include + adc@f8007100 { + compatible =3D "xlnx,zynq-xadc-1.00.a"; + reg =3D <0xf8007100 0x20>; + interrupts =3D ; + clocks =3D <&pcap_clk>; + + xlnx,channels { + #address-cells =3D <1>; + #size-cells =3D <0>; + channel@0 { + reg =3D <0>; + }; + channel@1 { + reg =3D <1>; + }; + channel@8 { + reg =3D <8>; + }; + }; + }; --=20 2.25.1