Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2196659/?format=api
{ "id": 2196659, "url": "http://patchwork.ozlabs.org/api/patches/2196659/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openbmc/patch/20260213070927.1114371-3-kchiu@axiado.com/", "project": { "id": 56, "url": "http://patchwork.ozlabs.org/api/projects/56/?format=api", "name": "OpenBMC development", "link_name": "openbmc", "list_id": "openbmc.lists.ozlabs.org", "list_email": "openbmc@lists.ozlabs.org", "web_url": "http://github.com/openbmc/", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260213070927.1114371-3-kchiu@axiado.com>", "list_archive_url": null, "date": "2026-02-13T07:09:26", "name": "[linux,dev-6.18,v1,2/3] spi: axiado: Add driver for Axiado SPI DB controller", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "404cbd48ebd9dfd0651303fc3d6129a8c68df27e", "submitter": { "id": 92340, "url": "http://patchwork.ozlabs.org/api/people/92340/?format=api", "name": "Kuan-Jui Chiu", "email": "kchiu@axiado.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/openbmc/patch/20260213070927.1114371-3-kchiu@axiado.com/mbox/", "series": [ { "id": 492236, "url": "http://patchwork.ozlabs.org/api/series/492236/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openbmc/list/?series=492236", "date": "2026-02-13T07:09:26", "name": "Axiado AX3000 SoC SPI DB controller driver", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/492236/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2196659/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2196659/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <openbmc+bounces-1368-incoming=patchwork.ozlabs.org@lists.ozlabs.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "openbmc@lists.ozlabs.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=axiado.com header.i=@axiado.com header.a=rsa-sha256\n header.s=selector1 header.b=nQIaBB31;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org\n (client-ip=112.213.38.117; helo=lists.ozlabs.org;\n envelope-from=openbmc+bounces-1368-incoming=patchwork.ozlabs.org@lists.ozlabs.org;\n receiver=patchwork.ozlabs.org)", "lists.ozlabs.org;\n arc=pass smtp.remote-ip=\"2a01:111:f403:c10d::3\" arc.chain=microsoft.com", "lists.ozlabs.org;\n dmarc=none (p=none dis=none) header.from=axiado.com", "lists.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=axiado.com header.i=@axiado.com header.a=rsa-sha256\n header.s=selector1 header.b=nQIaBB31;\n\tdkim-atps=neutral", "lists.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=axiado.com\n (client-ip=2a01:111:f403:c10d::3;\n helo=sn4pr0501cu005.outbound.protection.outlook.com;\n envelope-from=kchiu@axiado.com; receiver=lists.ozlabs.org)", "dkim=none (message not signed)\n header.d=none;dmarc=none action=none header.from=axiado.com;" ], "Received": [ "from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1 raw public key)\n server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fDgt62jNlz1xtN\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 16 Feb 2026 09:43:26 +1100 (AEDT)", "from boromir.ozlabs.org (localhost [127.0.0.1])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 4fDgsv0mymz2ydq;\n\tMon, 16 Feb 2026 09:43:15 +1100 (AEDT)", "from SN4PR0501CU005.outbound.protection.outlook.com\n (mail-southcentralusazlp170110003.outbound.protection.outlook.com\n [IPv6:2a01:111:f403:c10d::3])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange secp256r1 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 4fC3Gk03P6z30hg\n\tfor <openbmc@lists.ozlabs.org>; Fri, 13 Feb 2026 18:10:38 +1100 (AEDT)", "from SJ0PR18MB4479.namprd18.prod.outlook.com (2603:10b6:a03:37f::19)\n by BN9PR18MB4121.namprd18.prod.outlook.com (2603:10b6:408:132::10) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9611.10; Fri, 13 Feb\n 2026 07:10:07 +0000", "from SJ0PR18MB4479.namprd18.prod.outlook.com\n ([fe80::2bc8:6a5c:b10f:9e21]) by SJ0PR18MB4479.namprd18.prod.outlook.com\n ([fe80::2bc8:6a5c:b10f:9e21%3]) with mapi id 15.20.9611.012; Fri, 13 Feb 2026\n 07:10:06 +0000" ], "ARC-Seal": [ "i=2; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1770966639;\n\tcv=pass;\n b=QmzRfkuHql9TaHjSVwfLvBSzbohFfDnOFleqf6YA4brwjQN9WtZ8OAjeoWFEwA8/746mGyMi88QfVE0Y+CCQULJn0cEeHR55pPBD0+WOXJmJUYTp5OFqIUdyfeH46zhsTwwlGtM/oPT+zorgB4eTbqweLs2DO/yfyCdH2fDUlxESrzLb+BdL0Kk9bbBN0cYYlZlZn8S2xgnNmX9h9D+5CxDP84zZC1ZrPsR6u6zhiBO9ukRDlP2uIt8FO5icFs0rKjcn5J4oFq0sCDVGT433ahRBXPvf/IdfosB1qeC5Xbju51VCMs8w+ltUQCt9itv8t7VPkYYGKkXtRRSK5b8qWw==", "i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none;\n b=bOtaCRGqLyhS2Soyi/oysma+hiSU0a8c6zjlF8BFTrXFu7UVngck5T14bYQqK0Jc4oCpCmjdlrzoMw3wvON9FhhlVgAXnttVnMGkGALHwLF91MA6a6og12EyP+5eMk7b2ozJsYP+GcncKiQoG9l6bYMNirl117cHfWYHx3oGoRMY9mOBPq+CBGzWBsirk89xT+yAG/fMjt3+LAVNUJtkf9U017MRTJVdS05nVEey8mjdyZIhCemBodOSkfYFuR2ADblE9r9Qbzw0JEwGulmldIVlxLYt3GGW5u6Odo+HcQkrjZkPI0oB3FxWbx1/yqtwOGxUUbbQ+jrQ4VxazkcBcg==" ], "ARC-Message-Signature": [ "i=2; a=rsa-sha256; d=lists.ozlabs.org; s=201707;\n\tt=1770966639; c=relaxed/relaxed;\n\tbh=k09A2bqJMnV6tg/fdQuh3OodW9NTDN2zBcuk58GE5xk=;\n\th=From:To:Subject:Date:Message-Id:In-Reply-To:References:\n\t Content-Type:MIME-Version;\n b=P0fUnwc8Sl+6sdJtLi9e+tKBt8Gim8LI3KpjDWkHB73+L/ZFHO29e0Ko4nN/pAjD5U+7AG7oi8I78IHdPZA/rTVQzIjnVsKkm3xoFKGlWoVVBpU8b4Fyotn6QvBmj9pQa5laxdMbe7Wmu9MDM03hhbgYNc2aqCWGErth/YgpEogIM8/0cCqskzfHWGboE8J5LgBvy7V7+90hfsIxNNaH5+XA5+sdjSMTReXpDFfj0rkVbWqEKc+N2OEpJr4GY+1NYZVgVw6gG4mYKPzhLLTxwUEyxm85mhu9FoCtj+D/B/iPb6L0CHqf1YrsfEVXPi/TQTKQ083gYb/Wj9G0WXhc7Q==", "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector10001;\n 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;\n bh=k09A2bqJMnV6tg/fdQuh3OodW9NTDN2zBcuk58GE5xk=;\n b=RwiGKxxUvhW1yGsF747KjXEp/SgqCTVvYpss9G55XSMU+6qLuoDwkKid4YhgtTuDedwO0ENaY2sdZJDNFAfVKPyZQ2ia7U8yJiwtoJi27mXnmNnI6ZRmzorRigsAtKrQWzLvmJQkA3ebWj1kaUSqeqcCGt9/YBGrCRpeJRTOWevU3eOKHRgRjL5iiO2e76G0q8ixmUBqoEuP6V4bP7EbTJo1PdnCCSlHntx8bsfrv4GlFrrXl8SPnpYjUzSWErxNhgGavShDNvAMJKO8CSbFRKwZlkYcfD3rlzNp05Srp1g5UGBj7HIXyJD2BoyEzLH5KZZ+CnLSoU0Ych2yMEl8qw==" ], "ARC-Authentication-Results": [ "i=2; lists.ozlabs.org;\n dmarc=none (p=none dis=none) header.from=axiado.com; dkim=pass (2048-bit key;\n unprotected) header.d=axiado.com header.i=@axiado.com header.a=rsa-sha256\n header.s=selector1 header.b=nQIaBB31; dkim-atps=neutral;\n spf=pass (client-ip=2a01:111:f403:c10d::3;\n helo=sn4pr0501cu005.outbound.protection.outlook.com;\n envelope-from=kchiu@axiado.com;\n receiver=lists.ozlabs.org) smtp.mailfrom=axiado.com", "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=axiado.com; dmarc=pass action=none header.from=axiado.com;\n dkim=pass header.d=axiado.com; arc=none" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=axiado.com;\n s=selector1;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=k09A2bqJMnV6tg/fdQuh3OodW9NTDN2zBcuk58GE5xk=;\n b=nQIaBB31s5KtOYeMebAldx54pbJuaTCpCDZ9W89hQFDDS0G6EwjqcH9FDwyKc5DHH8SMJmb6ndeIs5AeSBr+VrW1Z5xFm1KXJu4HdMQBhuOZ7KUFupMbGoNSiILLhm+ikCGIn/S2Hy73ai9xEngapgzkPx1yn/9F1LhMYQ0Pnkia6vbV72FuroFJGG/W1SnA8bAcgVbQWKs2u7QCdc2tEU7CNkCzJLNugZbPyMYrW6DJF/xsN39WCVH1i67Q12cA8voH5aoZifYh/MqT5mdY/WLEy7JdChgEIhI6Ikh08EiMdlF4l7m6D/IYAX0LfGsoQ/w6cqB6LSx/BU2J+wjFpg==", "From": "Kuan-Jui Chiu <kchiu@axiado.com>", "To": "openbmc@lists.ozlabs.org,\n\tjoel@jms.id.au,\n\tandrew@codeconstruct.com.au", "Subject": "[PATCH linux dev-6.18 v1 2/3] spi: axiado: Add driver for Axiado SPI\n DB controller", "Date": "Thu, 12 Feb 2026 23:09:26 -0800", "Message-Id": "<20260213070927.1114371-3-kchiu@axiado.com>", "X-Mailer": "git-send-email 2.34.1", "In-Reply-To": "<20260213070927.1114371-1-kchiu@axiado.com>", "References": "<20260213070927.1114371-1-kchiu@axiado.com>", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "X-ClientProxiedBy": "PH8P221CA0018.NAMP221.PROD.OUTLOOK.COM\n (2603:10b6:510:2d8::19) To SJ0PR18MB4479.namprd18.prod.outlook.com\n (2603:10b6:a03:37f::19)", "X-Mailing-List": "openbmc@lists.ozlabs.org", "List-Id": "<openbmc.lists.ozlabs.org>", "List-Help": "<mailto:openbmc+help@lists.ozlabs.org>", "List-Owner": "<mailto:openbmc+owner@lists.ozlabs.org>", "List-Post": "<mailto:openbmc@lists.ozlabs.org>", "List-Subscribe": "<mailto:openbmc+subscribe@lists.ozlabs.org>,\n <mailto:openbmc+subscribe-digest@lists.ozlabs.org>,\n <mailto:openbmc+subscribe-nomail@lists.ozlabs.org>", "List-Unsubscribe": "<mailto:openbmc+unsubscribe@lists.ozlabs.org>", "Precedence": "list", "MIME-Version": "1.0", "X-MS-PublicTrafficType": "Email", "X-MS-TrafficTypeDiagnostic": "SJ0PR18MB4479:EE_|BN9PR18MB4121:EE_", "X-MS-Office365-Filtering-Correlation-Id": "1a6e9d37-126c-46ce-bc80-08de6acee9d2", "X-MS-Exchange-SenderADCheck": "1", "X-MS-Exchange-AntiSpam-Relay": "0", "X-Microsoft-Antispam": "\n\tBCL:0;ARA:13230040|366016|376014|52116014|1800799024|38350700014;", "X-Microsoft-Antispam-Message-Info": "=?utf-8?q?vT8EyBIuqBfFoTX4USRan98W7OFAr7f?=\n\t=?utf-8?q?BlNzWs0pvZJX87ATxMJi8AnnHr450wo/eP38zhbpo/kmlXsSgOUMj5ORlrj/ubhJs?=\n\t=?utf-8?q?IG2VO6DKFcPyDekyk6lLr51RpNI9YKLwEcyBipDM4qqQ+RpdCqWH3oszh339Rc2na?=\n\t=?utf-8?q?GFac+kW5nE62Sa6t9sII62fAf71rBE7dDRA65REC99SaP0+VFomSfhPBc5VtH2Cyo?=\n\t=?utf-8?q?UlfFDTfLrmFZaBzV8UbdlX7rGNvWBi1h0iAOUrMZVf6twkgEybSdTQBnfkXgvaVjy?=\n\t=?utf-8?q?uw0NY+HyIY0Crz0+NWw4J0756+k9/ZSCFmo8RVkVWk3YGfgzcgoF7txw25IBriTyR?=\n\t=?utf-8?q?A/D2FJ1jqQZaNRhpcHcmvR3A298/SvoM8okR1+KUEEOYWew151dCNhlqZ+1dkLzsa?=\n\t=?utf-8?q?5KFNpJkRnXN11PTFMySG8Kd22L7j8sMDeh01CTp5YyrsnmLqMsC59Y8YhKIJ3wztF?=\n\t=?utf-8?q?8aZ/0IuBJrJUtoZAIOqEg9pvGwJZX+u/icFkhVVrIn+g8E9GLMHM1vPOX3IuAtXGS?=\n\t=?utf-8?q?9QHjYTsV0OaNSWnADLMGuYLRlLSECpYTEZp6MZX7OCi2JYqMR4mMrVXmNmuF4wisA?=\n\t=?utf-8?q?+DWY0SgfAfP3XoiRgz64whYfpkf2mOCFdci0OEwQyGBg+lVNq7TK/YrTsH/X3jdri?=\n\t=?utf-8?q?jdIRde08+dZONEim4bjD+lwJpNyJZ8PIKO6d+8iRD+Fc30sBnlwh3bJGqKUIBWJwK?=\n\t=?utf-8?q?6v+nLXxDd0xvergOBXCFrm7eV/rR54eTUVqjoGtuqfaujZDyPBlc9UIxywo34Urmh?=\n\t=?utf-8?q?QHGm519Ol/SoO5bs8NOpFoXyl2leu/wDXakDQYgqIDggIwHS/tmkBuBDxciQWxJKZ?=\n\t=?utf-8?q?BJiCgYhm9LX2K7lIwZQrttShUnr8pF7yfoas+lZ7jyyyH1uoVhsjS2l3Lm3VlQGh0?=\n\t=?utf-8?q?BJu1689HTm9qOpX6Qt+jLKea0apWkxEvyoHyQh8jKE/JQGmTcSIewgPbPJQak8lSn?=\n\t=?utf-8?q?55XOOJSgfYQmXTE471/myXsiQTISQV/Ts6EcnvK++fbGWUFwtZqpGxqKxfKulcrA5?=\n\t=?utf-8?q?oqkz94sAxtvpPHC5+BP2QeBxqjTbIvld7hmqdw9fvNRG1GCs2Gj3IC8nHAfkA55FX?=\n\t=?utf-8?q?VmBfz7aARHx9SivZaSZEP8nxnO+FN1Z7MUIlGQXUshKAkjN7vfy5/ano5yW5udnyU?=\n\t=?utf-8?q?1hrKGlhxjHJOffutZNyswjwy5AXdxHAeIXLYzfluNUtohS5Ux9I1aBnKpSAYmhn1Z?=\n\t=?utf-8?q?pd2lWT3G5jOn+f6xNSPgjdKvvarfnOeNXsd/a53W+stm/P+zc9QA/jQ1E9dqTvL24?=\n\t=?utf-8?q?EBptOdkDnfcxVCWQLDj2b1syWgAMclLlVnYhN+hROrGOcU5oimucvgbKYg0AzodEb?=\n\t=?utf-8?q?WpvoOVswcFhWwkYouUQcOBTZXaSUw25ZweNrfDhRQK4IlxoLnU96oz+1NEwOM+h9W?=\n\t=?utf-8?q?0IiCFLzdQw1rrSoM65iBmC36VCVTg5KPR433DVkdY6ebyiCVmCmvlP+nN8q3o+yPS?=\n\t=?utf-8?q?kDZSn/uaTjlFytL5bvzCduSGACCqi/xw6F7P+/kBP+sh6cdhChqs6NKscTMdQ+Yt1?=\n\t=?utf-8?q?Yv2NyyNrz?=", "X-Forefront-Antispam-Report": "\n\tCIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SJ0PR18MB4479.namprd18.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(366016)(376014)(52116014)(1800799024)(38350700014);DIR:OUT;SFP:1102;", "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1", "X-MS-Exchange-AntiSpam-MessageData-0": "=?utf-8?q?p25CESkCqh9kYl+KfBmrFxhiAuma?=\n\t=?utf-8?q?drqgItjKxfVFpc4EiJHF19pG+gW1YOypqhim8W7zG9eky8jH/komMO/fivIyQcVLk?=\n\t=?utf-8?q?a/duSmshbZcpnwms36xhNu9eWY3450QDC79HP8f3swACCWRO98LMi729xrygqwqFk?=\n\t=?utf-8?q?wvoTZLAm4tznOsF7y7mf1cyLzBtcZ1gOS5Q2BCAzs6fDI5RgrD4ip5ggvtz/nOux1?=\n\t=?utf-8?q?7OfGkwUDoKIbqXB6LC0vP+HTPqgHrfhluHaSpB9sso9KlQd57VO12ZAuudXprXS+W?=\n\t=?utf-8?q?MoKvOmfjJF9OYgPAN5ZX8KUw9ZfZQM2IQ91soeiGkT5mJuqL8nyzkpPYijYs2/+rT?=\n\t=?utf-8?q?IsDzTlz2sTQ+HHqb2BGQ0ErRCUI5gZlpSvtDg8vFfTjG5fg3h6allNOPDgd53gfLH?=\n\t=?utf-8?q?hKUDnQeQHquyIp+atVs4QBJbcpIiAz+R9i24cWEwS9Dx55f9lK4zjNIRIPQFSxBN5?=\n\t=?utf-8?q?5Jvz2GPMmVLt8yjvd6jxdeunIzh3AjHODCA5zeZqlyQjWmQAa406cVherA8Nb+v36?=\n\t=?utf-8?q?QZO7BHtGWjXSQEoCiWTkFihckgToRaj2KRJP6GQwORJYhl/UJJI2/mBqyYR1x9IyI?=\n\t=?utf-8?q?+6Qa2AU5H5YTdqsnfmnx+PhHMaDjABxNie7gzS33NpHkwkdPFgdtR+mvmccQ40T0u?=\n\t=?utf-8?q?Xg9hBkLE8ja7WyBfpVg8bVHI7uC2R3HIKEPOF2560UcNmRMQRtFZZf5u8gT7CRa3Z?=\n\t=?utf-8?q?JkrdxMBMymyEO/CY/q0wxEA9oBZIt7OGBeGLYhkuikliJyChupVvwcaAVXxlt28zj?=\n\t=?utf-8?q?zhi4HEFqJW56uaPr9ws43NGgBWGkRogcDlWlOrtZReg5aOvgjD6Lskp+mIETA9HwI?=\n\t=?utf-8?q?JRxsYT05TDSEloVO1hGyDBwcL0FlQF+wtaeORL/x8RBedRfzLFqq1hqwLt2ppJkHS?=\n\t=?utf-8?q?EwAdc83knm4G8aP+bmafYm3uBDEh7A5Ppmx6JFq+PUicOF3Qte2WMlCeXKLTkqG2z?=\n\t=?utf-8?q?kd+pzJTRMysMX3VBpWDjCZstbZqGY1owl5tXwBlTSO9Thu7wtTLatpfly9SWmsqTa?=\n\t=?utf-8?q?BXG+vRx9NP2hlSY3r84hvpnM1qj6uq27PLLgyq84DmC7VvUYAmfpQDHWxOz/Iu7AN?=\n\t=?utf-8?q?uhqH6QuY7ufMEVfkkSddgwSQFHt1Wy4cnQo0jX68t76ENkwWw7fpC6STOG7zDe9Po?=\n\t=?utf-8?q?WDPZmCn/4YQxlZCNxUN+PCHAIQhOuHjOqV7qaV9GG3rjPm3OkZ+QRjymQZlmLO/en?=\n\t=?utf-8?q?6Nha91Uv3q5srvM4nlvg+MksCBPKRGFyixymQMInRSzMcJEjRmTMTo7iyr+AoC7M9?=\n\t=?utf-8?q?RdNvNIr2mvCSwbIYu0Vi3EuIVLLMgH4leyikblfMIgWhgYb8UvhXAvT4LSvspCV12?=\n\t=?utf-8?q?du3KNmjE661O5qK9+C72ixrYlWzzq3/HZNsk/OKXKWd7qUSdHii3N1gLO4okNwDwR?=\n\t=?utf-8?q?BX9cE+yJ0jZXbZtLts3ghZkX6El6bBeusv5FqKNsNbC/jZjs/Rz/bQu3xHJ2dWg0F?=\n\t=?utf-8?q?6TBiYzdfL/JskEIs3kc4FLUvxSQ1bnPCUiZQafPEyOxSZC3YqNjbYLlVe/dahTcwl?=\n\t=?utf-8?q?3Tv8OgBpRS3J7W5KTqXy6ea4JFbS68vOec2eKljhp8nxGdNd6AR4nZls9jALxqPyd?=\n\t=?utf-8?q?hx4OxOSSBZiyMLxlbroVSIHoxFTASIG01D5lyV7C3sUqhBJo6lAY3HAToYObqLIau?=\n\t=?utf-8?q?QkBWDMN6Dv?=", "X-OriginatorOrg": "axiado.com", "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 1a6e9d37-126c-46ce-bc80-08de6acee9d2", "X-MS-Exchange-CrossTenant-AuthSource": "SJ0PR18MB4479.namprd18.prod.outlook.com", "X-MS-Exchange-CrossTenant-AuthAs": "Internal", "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "13 Feb 2026 07:10:05.9948\n (UTC)", "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted", "X-MS-Exchange-CrossTenant-Id": "ff2db17c-4338-408e-9036-2dee8e3e17d7", "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED", "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n v9occIGF1d2bXaBS+iEZmPNwlmgTf2HbdgCJm1BYF2Ftmq6YDZuapR/k6NdhrZVaHX1fomxGiYvLDTG53uDxHw==", "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "BN9PR18MB4121", "X-Spam-Status": "No, score=-0.2 required=5.0 tests=ARC_SIGNED,ARC_VALID,\n\tDKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,\n\tSPF_PASS autolearn=disabled version=4.0.1", "X-Spam-Checker-Version": "SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org" }, "content": "From: Vladimir Moravcevic <vmoravcevic@axiado.com>\n\nThe Axiado SPI controller is present in AX3000 SoC and Evaluation Board.\nThis controller is operating in Host only mode.\n\nCo-developed-by: Prasad Bolisetty <pbolisetty@axiado.com>\nSigned-off-by: Prasad Bolisetty <pbolisetty@axiado.com>\nSigned-off-by: Vladimir Moravcevic <vmoravcevic@axiado.com>\nLink: https://patch.msgid.link/20260107-axiado-ax3000-soc-spi-db-controller-driver-v3-2-726e70cf19ad@axiado.com\nSigned-off-by: Mark Brown <broonie@kernel.org>\n(cherry picked from commit e75a6b00ad7962a7ed1c9c777e9ab1eb29043ec8)\nSigned-off-by: Kuan-Jui Chiu <kchiu@axiado.com>\n---\n drivers/spi/Kconfig | 10 +\n drivers/spi/Makefile | 1 +\n drivers/spi/spi-axiado.c | 1007 ++++++++++++++++++++++++++++++++++++++\n drivers/spi/spi-axiado.h | 133 +++++\n 4 files changed, 1151 insertions(+)\n create mode 100644 drivers/spi/spi-axiado.c\n create mode 100644 drivers/spi/spi-axiado.h", "diff": "diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig\nindex 1872f9d54a5c..fa7836f5e6d2 100644\n--- a/drivers/spi/Kconfig\n+++ b/drivers/spi/Kconfig\n@@ -204,6 +204,16 @@ config SPI_AXI_SPI_ENGINE\n \t It is part of the SPI Engine framework that is used in some Analog Devices\n \t reference designs for FPGAs.\n \n+config SPI_AXIADO\n+\ttristate \"Axiado DB-H SPI controller\"\n+\tdepends on SPI_MEM\n+\thelp\n+\t Enable support for the SPI controller present on Axiado AX3000 SoCs.\n+\n+\t The implementation supports host-only mode and does not provide target\n+\t functionality. It is intended for use cases where the SoC acts as the SPI\n+\t host, communicating with peripheral devices such as flash memory.\n+\n config SPI_BCM2835\n \ttristate \"BCM2835 SPI controller\"\n \tdepends on GPIOLIB\ndiff --git a/drivers/spi/Makefile b/drivers/spi/Makefile\nindex 1f7c06a3091d..0cfc33a005e3 100644\n--- a/drivers/spi/Makefile\n+++ b/drivers/spi/Makefile\n@@ -32,6 +32,7 @@ obj-$(CONFIG_SPI_AT91_USART)\t\t+= spi-at91-usart.o\n obj-$(CONFIG_SPI_ATH79)\t\t\t+= spi-ath79.o\n obj-$(CONFIG_SPI_AU1550)\t\t+= spi-au1550.o\n obj-$(CONFIG_SPI_AXI_SPI_ENGINE)\t+= spi-axi-spi-engine.o\n+obj-$(CONFIG_SPI_AXIADO)\t\t+= spi-axiado.o\n obj-$(CONFIG_SPI_BCM2835)\t\t+= spi-bcm2835.o\n obj-$(CONFIG_SPI_BCM2835AUX)\t\t+= spi-bcm2835aux.o\n obj-$(CONFIG_SPI_BCM63XX)\t\t+= spi-bcm63xx.o\ndiff --git a/drivers/spi/spi-axiado.c b/drivers/spi/spi-axiado.c\nnew file mode 100644\nindex 000000000000..8cea81432c5b\n--- /dev/null\n+++ b/drivers/spi/spi-axiado.c\n@@ -0,0 +1,1007 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+//\n+// Axiado SPI controller driver (Host mode only)\n+//\n+// Copyright (C) 2022-2025 Axiado Corporation (or its affiliates).\n+//\n+\n+#include <linux/clk.h>\n+#include <linux/delay.h>\n+#include <linux/gpio/consumer.h>\n+#include <linux/interrupt.h>\n+#include <linux/io.h>\n+#include <linux/module.h>\n+#include <linux/of_irq.h>\n+#include <linux/of_address.h>\n+#include <linux/platform_device.h>\n+#include <linux/pm_runtime.h>\n+#include <linux/spi/spi.h>\n+#include <linux/spi/spi-mem.h>\n+#include <linux/sizes.h>\n+\n+#include \"spi-axiado.h\"\n+\n+/**\n+ * ax_spi_read - Register Read - 32 bit per word\n+ * @xspi:\tPointer to the ax_spi structure\n+ * @offset:\tRegister offset address\n+ *\n+ * @return:\tReturns the value of that register\n+ */\n+static inline u32 ax_spi_read(struct ax_spi *xspi, u32 offset)\n+{\n+\treturn readl_relaxed(xspi->regs + offset);\n+}\n+\n+/**\n+ * ax_spi_write - Register write - 32 bit per word\n+ * @xspi:\tPointer to the ax_spi structure\n+ * @offset:\tRegister offset address\n+ * @val:\tValue to write into that register\n+ */\n+static inline void ax_spi_write(struct ax_spi *xspi, u32 offset, u32 val)\n+{\n+\twritel_relaxed(val, xspi->regs + offset);\n+}\n+\n+/**\n+ * ax_spi_write_b - Register Read - 8 bit per word\n+ * @xspi:\tPointer to the ax_spi structure\n+ * @offset:\tRegister offset address\n+ * @val:\tValue to write into that register\n+ */\n+static inline void ax_spi_write_b(struct ax_spi *xspi, u32 offset, u8 val)\n+{\n+\twriteb_relaxed(val, xspi->regs + offset);\n+}\n+\n+/**\n+ * ax_spi_init_hw - Initialize the hardware and configure the SPI controller\n+ * @xspi:\tPointer to the ax_spi structure\n+ *\n+ * * On reset the SPI controller is configured to be in host mode.\n+ * In host mode baud rate divisor is set to 4, threshold value for TX FIFO\n+ * not full interrupt is set to 1 and size of the word to be transferred as 8 bit.\n+ *\n+ * This function initializes the SPI controller to disable and clear all the\n+ * interrupts, enable manual target select and manual start, deselect all the\n+ * chip select lines, and enable the SPI controller.\n+ */\n+static void ax_spi_init_hw(struct ax_spi *xspi)\n+{\n+\tu32 reg_value;\n+\n+\t/* Clear CR1 */\n+\tax_spi_write(xspi, AX_SPI_CR1, AX_SPI_CR1_CLR);\n+\n+\t/* CR1 - CPO CHP MSS SCE SCR */\n+\treg_value = ax_spi_read(xspi, AX_SPI_CR1);\n+\treg_value |= AX_SPI_CR1_SCR | AX_SPI_CR1_SCE;\n+\n+\tax_spi_write(xspi, AX_SPI_CR1, reg_value);\n+\n+\t/* CR2 - MTE SRD SWD SSO */\n+\treg_value = ax_spi_read(xspi, AX_SPI_CR2);\n+\treg_value |= AX_SPI_CR2_SWD | AX_SPI_CR2_SRD;\n+\n+\tax_spi_write(xspi, AX_SPI_CR2, reg_value);\n+\n+\t/* CR3 - Reserverd bits S3W SDL */\n+\tax_spi_write(xspi, AX_SPI_CR3, AX_SPI_CR3_SDL);\n+\n+\t/* SCDR - Reserved bits SCS SCD */\n+\tax_spi_write(xspi, AX_SPI_SCDR, (AX_SPI_SCDR_SCS | AX_SPI_SCD_DEFAULT));\n+\n+\t/* IMR */\n+\tax_spi_write(xspi, AX_SPI_IMR, AX_SPI_IMR_CLR);\n+\n+\t/* ISR - Clear all the interrupt */\n+\tax_spi_write(xspi, AX_SPI_ISR, AX_SPI_ISR_CLR);\n+}\n+\n+/**\n+ * ax_spi_chipselect - Select or deselect the chip select line\n+ * @spi:\tPointer to the spi_device structure\n+ * @is_high:\tSelect(0) or deselect (1) the chip select line\n+ */\n+static void ax_spi_chipselect(struct spi_device *spi, bool is_high)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(spi->controller);\n+\tu32 ctrl_reg;\n+\n+\tctrl_reg = ax_spi_read(xspi, AX_SPI_CR2);\n+\t/* Reset the chip select */\n+\tctrl_reg &= ~AX_SPI_DEFAULT_TS_MASK;\n+\tctrl_reg |= spi_get_chipselect(spi, 0);\n+\n+\tax_spi_write(xspi, AX_SPI_CR2, ctrl_reg);\n+}\n+\n+/**\n+ * ax_spi_config_clock_mode - Sets clock polarity and phase\n+ * @spi:\tPointer to the spi_device structure\n+ *\n+ * Sets the requested clock polarity and phase.\n+ */\n+static void ax_spi_config_clock_mode(struct spi_device *spi)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(spi->controller);\n+\tu32 ctrl_reg, new_ctrl_reg;\n+\n+\tnew_ctrl_reg = ax_spi_read(xspi, AX_SPI_CR1);\n+\tctrl_reg = new_ctrl_reg;\n+\n+\t/* Set the SPI clock phase and clock polarity */\n+\tnew_ctrl_reg &= ~(AX_SPI_CR1_CPHA | AX_SPI_CR1_CPOL);\n+\tif (spi->mode & SPI_CPHA)\n+\t\tnew_ctrl_reg |= AX_SPI_CR1_CPHA;\n+\tif (spi->mode & SPI_CPOL)\n+\t\tnew_ctrl_reg |= AX_SPI_CR1_CPOL;\n+\n+\tif (new_ctrl_reg != ctrl_reg)\n+\t\tax_spi_write(xspi, AX_SPI_CR1, new_ctrl_reg);\n+\tax_spi_write(xspi, AX_SPI_CR1, 0x03);\n+}\n+\n+/**\n+ * ax_spi_config_clock_freq - Sets clock frequency\n+ * @spi:\tPointer to the spi_device structure\n+ * @transfer:\tPointer to the spi_transfer structure which provides\n+ *\t\tinformation about next transfer setup parameters\n+ *\n+ * Sets the requested clock frequency.\n+ * Note: If the requested frequency is not an exact match with what can be\n+ * obtained using the prescalar value the driver sets the clock frequency which\n+ * is lower than the requested frequency (maximum lower) for the transfer. If\n+ * the requested frequency is higher or lower than that is supported by the SPI\n+ * controller the driver will set the highest or lowest frequency supported by\n+ * controller.\n+ */\n+static void ax_spi_config_clock_freq(struct spi_device *spi,\n+\t\t\t\t struct spi_transfer *transfer)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(spi->controller);\n+\n+\tax_spi_write(xspi, AX_SPI_SCDR, (AX_SPI_SCDR_SCS | AX_SPI_SCD_DEFAULT));\n+}\n+\n+/**\n+ * ax_spi_setup_transfer - Configure SPI controller for specified transfer\n+ * @spi:\tPointer to the spi_device structure\n+ * @transfer:\tPointer to the spi_transfer structure which provides\n+ *\t\tinformation about next transfer setup parameters\n+ *\n+ * Sets the operational mode of SPI controller for the next SPI transfer and\n+ * sets the requested clock frequency.\n+ *\n+ */\n+static void ax_spi_setup_transfer(struct spi_device *spi,\n+\t\t\t\t struct spi_transfer *transfer)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(spi->controller);\n+\n+\tax_spi_config_clock_freq(spi, transfer);\n+\n+\tdev_dbg(&spi->dev, \"%s, mode %d, %u bits/w, %u clock speed\\n\",\n+\t\t__func__, spi->mode, spi->bits_per_word,\n+\t\txspi->speed_hz);\n+}\n+\n+/**\n+ * ax_spi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible\n+ * @xspi:\tPointer to the ax_spi structure\n+ */\n+static void ax_spi_fill_tx_fifo(struct ax_spi *xspi)\n+{\n+\tunsigned long trans_cnt = 0;\n+\n+\twhile ((trans_cnt < xspi->tx_fifo_depth) &&\n+\t (xspi->tx_bytes > 0)) {\n+\t\t/* When xspi in busy condition, bytes may send failed,\n+\t\t * then spi control did't work thoroughly, add one byte delay\n+\t\t */\n+\t\tif (ax_spi_read(xspi, AX_SPI_IVR) & AX_SPI_IVR_TFOV)\n+\t\t\tusleep_range(10, 10);\n+\t\tif (xspi->tx_buf)\n+\t\t\tax_spi_write_b(xspi, AX_SPI_TXFIFO, *xspi->tx_buf++);\n+\t\telse\n+\t\t\tax_spi_write_b(xspi, AX_SPI_TXFIFO, 0);\n+\n+\t\txspi->tx_bytes--;\n+\t\ttrans_cnt++;\n+\t}\n+}\n+\n+/**\n+ * ax_spi_get_rx_byte - Gets a byte from the RX FIFO buffer\n+ * @xspi: Controller private data (struct ax_spi *)\n+ *\n+ * This function handles the logic of extracting bytes from the 32-bit RX FIFO.\n+ * It reads a new 32-bit word from AX_SPI_RXFIFO only when the current buffered\n+ * word has been fully processed (all 4 bytes extracted). It then extracts\n+ * bytes one by one, assuming the controller is little-endian.\n+ *\n+ * Returns: The next 8-bit byte read from the RX FIFO stream.\n+ */\n+static u8 ax_spi_get_rx_byte_for_irq(struct ax_spi *xspi)\n+{\n+\tu8 byte_val;\n+\n+\t/* If all bytes from the current 32-bit word have been extracted,\n+\t * read a new word from the hardware RX FIFO.\n+\t */\n+\tif (xspi->bytes_left_in_current_rx_word_for_irq == 0) {\n+\t\txspi->current_rx_fifo_word_for_irq = ax_spi_read(xspi, AX_SPI_RXFIFO);\n+\t\txspi->bytes_left_in_current_rx_word_for_irq = 4; // A new 32-bit word has 4 bytes\n+\t}\n+\n+\t/* Extract the least significant byte from the current 32-bit word */\n+\tbyte_val = (u8)(xspi->current_rx_fifo_word_for_irq & 0xFF);\n+\n+\t/* Shift the word right by 8 bits to prepare the next byte for extraction */\n+\txspi->current_rx_fifo_word_for_irq >>= 8;\n+\txspi->bytes_left_in_current_rx_word_for_irq--;\n+\n+\treturn byte_val;\n+}\n+\n+/**\n+ * Helper function to process received bytes and check for transfer completion.\n+ * This avoids code duplication and centralizes the completion logic.\n+ * Returns true if the transfer was finalized.\n+ */\n+static bool ax_spi_process_rx_and_finalize(struct spi_controller *ctlr)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\n+\t/* Process any remaining bytes in the RX FIFO */\n+\tu32 avail_bytes = ax_spi_read(xspi, AX_SPI_RX_FBCAR);\n+\n+\t/* This loop handles bytes that are already staged from a previous word read */\n+\twhile (xspi->bytes_left_in_current_rx_word_for_irq &&\n+\t (xspi->rx_copy_remaining || xspi->rx_discard)) {\n+\t\tu8 b = ax_spi_get_rx_byte_for_irq(xspi);\n+\n+\t\tif (xspi->rx_discard) {\n+\t\t\txspi->rx_discard--;\n+\t\t} else {\n+\t\t\t*xspi->rx_buf++ = b;\n+\t\t\txspi->rx_copy_remaining--;\n+\t\t}\n+\t}\n+\n+\t/* This loop processes new words directly from the FIFO */\n+\twhile (avail_bytes >= 4 && (xspi->rx_copy_remaining || xspi->rx_discard)) {\n+\t\t/* This function should handle reading from the FIFO */\n+\t\tu8 b = ax_spi_get_rx_byte_for_irq(xspi);\n+\n+\t\tif (xspi->rx_discard) {\n+\t\t\txspi->rx_discard--;\n+\t\t} else {\n+\t\t\t*xspi->rx_buf++ = b;\n+\t\t\txspi->rx_copy_remaining--;\n+\t\t}\n+\t\t/* ax_spi_get_rx_byte_for_irq fetches a new word when needed\n+\t\t * and updates internal state.\n+\t\t */\n+\t\tif (xspi->bytes_left_in_current_rx_word_for_irq == 3)\n+\t\t\tavail_bytes -= 4;\n+\t}\n+\n+\t/* Completion Check: The transfer is truly complete if all expected\n+\t * RX bytes have been copied or discarded.\n+\t */\n+\tif (xspi->rx_copy_remaining == 0 && xspi->rx_discard == 0) {\n+\t\t/* Defensive drain: If for some reason there are leftover bytes\n+\t\t * in the HW FIFO after we've logically finished,\n+\t\t * read and discard them to prevent them from corrupting the next transfer.\n+\t\t * This should be a bounded operation.\n+\t\t */\n+\t\tint safety_words = AX_SPI_RX_FIFO_DRAIN_LIMIT; // Limit to avoid getting stuck\n+\n+\t\twhile (ax_spi_read(xspi, AX_SPI_RX_FBCAR) > 0 && safety_words-- > 0)\n+\t\t\tax_spi_read(xspi, AX_SPI_RXFIFO);\n+\n+\t\t/* Disable all interrupts for this transfer and finalize. */\n+\t\tax_spi_write(xspi, AX_SPI_IMR, 0x00);\n+\t\tspi_finalize_current_transfer(ctlr);\n+\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n+/**\n+ * ax_spi_irq - Interrupt service routine of the SPI controller\n+ * @irq:\tIRQ number\n+ * @dev_id:\tPointer to the xspi structure\n+ *\n+ * This function handles RX FIFO almost full and Host Transfer Completed interrupts only.\n+ * On RX FIFO amlost full interrupt this function reads the received data from RX FIFO and\n+ * fills the TX FIFO if there is any data remaining to be transferred.\n+ * On Host Transfer Completed interrupt this function indicates that transfer is completed,\n+ * the SPI subsystem will clear MTC bit.\n+ *\n+ * Return:\tIRQ_HANDLED when handled; IRQ_NONE otherwise.\n+ */\n+static irqreturn_t ax_spi_irq(int irq, void *dev_id)\n+{\n+\tstruct spi_controller *ctlr = dev_id;\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\tu32 intr_status;\n+\n+\tintr_status = ax_spi_read(xspi, AX_SPI_IVR);\n+\tif (!intr_status)\n+\t\treturn IRQ_NONE;\n+\n+\t/* Handle \"Message Transfer Complete\" interrupt.\n+\t * This means all bytes have been shifted out of the TX FIFO.\n+\t * It's time to harvest the final incoming bytes from the RX FIFO.\n+\t */\n+\tif (intr_status & AX_SPI_IVR_MTCV) {\n+\t\t/* Clear the MTC interrupt flag immediately. */\n+\t\tax_spi_write(xspi, AX_SPI_ISR, AX_SPI_ISR_MTC);\n+\n+\t\t/* For a TX-only transfer, rx_buf would be NULL.\n+\t\t * In the spi-core, rx_copy_remaining would be 0.\n+\t\t * So we can finalize immediately.\n+\t\t */\n+\t\tif (!xspi->rx_buf) {\n+\t\t\tax_spi_write(xspi, AX_SPI_IMR, 0x00);\n+\t\t\tspi_finalize_current_transfer(ctlr);\n+\t\t\treturn IRQ_HANDLED;\n+\t\t}\n+\t\t/* For a full-duplex transfer, process any remaining RX data.\n+\t\t * The helper function will handle finalization if everything is received.\n+\t\t */\n+\t\tax_spi_process_rx_and_finalize(ctlr);\n+\t\treturn IRQ_HANDLED;\n+\t}\n+\n+\t/* Handle \"RX FIFO Full / Threshold Met\" interrupt.\n+\t * This means we need to make space in the RX FIFO by reading from it.\n+\t */\n+\tif (intr_status & AX_SPI_IVR_RFFV) {\n+\t\tif (ax_spi_process_rx_and_finalize(ctlr)) {\n+\t\t\t/* Transfer was finalized inside the helper, we are done. */\n+\t\t} else {\n+\t\t\t/* RX is not yet complete. If there are still TX bytes to send\n+\t\t\t * (for very long transfers), we can fill the TX FIFO again.\n+\t\t\t */\n+\t\t\tif (xspi->tx_bytes)\n+\t\t\t\tax_spi_fill_tx_fifo(xspi);\n+\t\t}\n+\t\treturn IRQ_HANDLED;\n+\t}\n+\n+\treturn IRQ_NONE;\n+}\n+\n+static int ax_prepare_message(struct spi_controller *ctlr,\n+\t\t\t struct spi_message *msg)\n+{\n+\tax_spi_config_clock_mode(msg->spi);\n+\treturn 0;\n+}\n+\n+/**\n+ * ax_transfer_one - Initiates the SPI transfer\n+ * @ctlr:\tPointer to spi_controller structure\n+ * @spi:\tPointer to the spi_device structure\n+ * @transfer:\tPointer to the spi_transfer structure which provides\n+ *\t\tinformation about next transfer parameters\n+ *\n+ * This function fills the TX FIFO, starts the SPI transfer and\n+ * returns a positive transfer count so that core will wait for completion.\n+ *\n+ * Return:\tNumber of bytes transferred in the last transfer\n+ */\n+static int ax_transfer_one(struct spi_controller *ctlr,\n+\t\t\t struct spi_device *spi,\n+\t\t\t struct spi_transfer *transfer)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\tint drain_limit;\n+\n+\t/* Pre-transfer cleanup:Flush the RX FIFO to discard any stale data.\n+\t * This is the crucial part. Before every new transfer, we must ensure\n+\t * the HW is in a clean state to avoid processing stale data\n+\t * from a previous, possibly failed or interrupted, transfer.\n+\t */\n+\tdrain_limit = AX_SPI_RX_FIFO_DRAIN_LIMIT; // Sane limit to prevent infinite loop on HW error\n+\twhile (ax_spi_read(xspi, AX_SPI_RX_FBCAR) > 0 && drain_limit-- > 0)\n+\t\tax_spi_read(xspi, AX_SPI_RXFIFO); // Read and discard\n+\n+\tif (drain_limit <= 0)\n+\t\tdev_warn(&ctlr->dev, \"RX FIFO drain timeout before transfer\\n\");\n+\n+\t/* Clear any stale interrupt flags from a previous transfer.\n+\t * This prevents an immediate, false interrupt trigger.\n+\t */\n+\tax_spi_write(xspi, AX_SPI_ISR, AX_SPI_ISR_CLR);\n+\n+\txspi->tx_buf = transfer->tx_buf;\n+\txspi->rx_buf = transfer->rx_buf;\n+\txspi->tx_bytes = transfer->len;\n+\txspi->rx_bytes = transfer->len;\n+\n+\t/* Reset RX 32-bit to byte buffer for each new transfer */\n+\tif (transfer->tx_buf && !transfer->rx_buf) {\n+\t\t/* TX mode: discard all received data */\n+\t\txspi->rx_discard = transfer->len;\n+\t\txspi->rx_copy_remaining = 0;\n+\t} else if ((!transfer->tx_buf && transfer->rx_buf) ||\n+\t\t (transfer->tx_buf && transfer->rx_buf)) {\n+\t\t/* RX mode: generate clock by filling TX FIFO with dummy bytes\n+\t\t * Full-duplex mode: generate clock by filling TX FIFO\n+\t\t */\n+\t\txspi->rx_discard = 0;\n+\t\txspi->rx_copy_remaining = transfer->len;\n+\t} else {\n+\t\t/* No TX and RX */\n+\t\txspi->rx_discard = 0;\n+\t\txspi->rx_copy_remaining = transfer->len;\n+\t}\n+\n+\tax_spi_setup_transfer(spi, transfer);\n+\tax_spi_fill_tx_fifo(xspi);\n+\tax_spi_write(xspi, AX_SPI_CR2, (AX_SPI_CR2_HTE | AX_SPI_CR2_SRD | AX_SPI_CR2_SWD));\n+\n+\tax_spi_write(xspi, AX_SPI_IMR, (AX_SPI_IMR_MTCM | AX_SPI_IMR_RFFM));\n+\treturn transfer->len;\n+}\n+\n+/**\n+ * ax_prepare_transfer_hardware - Prepares hardware for transfer.\n+ * @ctlr:\tPointer to the spi_controller structure which provides\n+ *\t\tinformation about the controller.\n+ *\n+ * This function enables SPI host controller.\n+ *\n+ * Return:\t0 always\n+ */\n+static int ax_prepare_transfer_hardware(struct spi_controller *ctlr)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\n+\tu32 reg_value;\n+\n+\treg_value = ax_spi_read(xspi, AX_SPI_CR1);\n+\treg_value |= AX_SPI_CR1_SCE;\n+\n+\tax_spi_write(xspi, AX_SPI_CR1, reg_value);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ax_unprepare_transfer_hardware - Relaxes hardware after transfer\n+ * @ctlr:\tPointer to the spi_controller structure which provides\n+ *\t\tinformation about the controller.\n+ *\n+ * This function disables the SPI host controller when no target selected.\n+ *\n+ * Return:\t0 always\n+ */\n+static int ax_unprepare_transfer_hardware(struct spi_controller *ctlr)\n+{\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\n+\tu32 reg_value;\n+\n+\t/* Disable the SPI if target is deselected */\n+\treg_value = ax_spi_read(xspi, AX_SPI_CR1);\n+\treg_value &= ~AX_SPI_CR1_SCE;\n+\n+\tax_spi_write(xspi, AX_SPI_CR1, reg_value);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ax_spi_detect_fifo_depth - Detect the FIFO depth of the hardware\n+ * @xspi:\tPointer to the ax_spi structure\n+ *\n+ * The depth of the TX FIFO is a synthesis configuration parameter of the SPI\n+ * IP. The FIFO threshold register is sized so that its maximum value can be the\n+ * FIFO size - 1. This is used to detect the size of the FIFO.\n+ */\n+static void ax_spi_detect_fifo_depth(struct ax_spi *xspi)\n+{\n+\t/* The MSBs will get truncated giving us the size of the FIFO */\n+\tax_spi_write(xspi, AX_SPI_TX_FAETR, ALMOST_EMPTY_TRESHOLD);\n+\txspi->tx_fifo_depth = FIFO_DEPTH;\n+\n+\t/* Set the threshold limit */\n+\tax_spi_write(xspi, AX_SPI_TX_FAETR, ALMOST_EMPTY_TRESHOLD);\n+\tax_spi_write(xspi, AX_SPI_RX_FAFTR, ALMOST_FULL_TRESHOLD);\n+}\n+\n+/* --- Internal Helper Function for 32-bit RX FIFO Read --- */\n+/**\n+ * ax_spi_get_rx_byte - Gets a byte from the RX FIFO buffer\n+ * @xspi: Controller private data (struct ax_spi *)\n+ *\n+ * This function handles the logic of extracting bytes from the 32-bit RX FIFO.\n+ * It reads a new 32-bit word from AX_SPI_RXFIFO only when the current buffered\n+ * word has been fully processed (all 4 bytes extracted). It then extracts\n+ * bytes one by one, assuming the controller is little-endian.\n+ *\n+ * Returns: The next 8-bit byte read from the RX FIFO stream.\n+ */\n+static u8 ax_spi_get_rx_byte(struct ax_spi *xspi)\n+{\n+\tu8 byte_val;\n+\n+\t/* If all bytes from the current 32-bit word have been extracted,\n+\t * read a new word from the hardware RX FIFO.\n+\t */\n+\tif (xspi->bytes_left_in_current_rx_word == 0) {\n+\t\txspi->current_rx_fifo_word = ax_spi_read(xspi, AX_SPI_RXFIFO);\n+\t\txspi->bytes_left_in_current_rx_word = 4; // A new 32-bit word has 4 bytes\n+\t}\n+\n+\t/* Extract the least significant byte from the current 32-bit word */\n+\tbyte_val = (u8)(xspi->current_rx_fifo_word & 0xFF);\n+\n+\t/* Shift the word right by 8 bits to prepare the next byte for extraction */\n+\txspi->current_rx_fifo_word >>= 8;\n+\txspi->bytes_left_in_current_rx_word--;\n+\n+\treturn byte_val;\n+}\n+\n+static int ax_spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)\n+{\n+\tstruct spi_device *spi = mem->spi;\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(spi->controller);\n+\tu32 reg_val;\n+\tint ret = 0;\n+\tu8 cmd_buf[AX_SPI_COMMAND_BUFFER_SIZE];\n+\tint cmd_len = 0;\n+\tint i = 0, timeout = AX_SPI_TRX_FIFO_TIMEOUT;\n+\tint bytes_to_discard_from_rx;\n+\tu8 *rx_buf_ptr = (u8 *)op->data.buf.in;\n+\tu8 *tx_buf_ptr = (u8 *)op->data.buf.out;\n+\tu32 rx_count_reg = 0;\n+\n+\tdev_dbg(&spi->dev,\n+\t\t\"%s: cmd:%02x mode:%d.%d.%d.%d addr:%llx len:%d\\n\",\n+\t\t__func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,\n+\t\top->dummy.buswidth, op->data.buswidth, op->addr.val,\n+\t\top->data.nbytes);\n+\n+\t/* Validate operation parameters: Only 1-bit bus width supported */\n+\tif (op->cmd.buswidth != 1 ||\n+\t (op->addr.nbytes && op->addr.buswidth != 0 &&\n+\t op->addr.buswidth != 1) ||\n+\t (op->dummy.nbytes && op->dummy.buswidth != 0 &&\n+\t op->dummy.buswidth != 1) ||\n+\t (op->data.nbytes && op->data.buswidth != 1)) {\n+\t\tdev_err(&spi->dev, \"Unsupported bus width, only 1-bit bus width supported\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\t/* Initialize controller hardware */\n+\tax_spi_init_hw(xspi);\n+\n+\t/* Assert chip select (pull low) */\n+\tax_spi_chipselect(spi, false);\n+\n+\t/* Build command phase: Copy opcode to cmd_buf */\n+\tif (op->cmd.nbytes == 2) {\n+\t\tcmd_buf[cmd_len++] = (op->cmd.opcode >> 8) & 0xFF;\n+\t\tcmd_buf[cmd_len++] = op->cmd.opcode & 0xFF;\n+\t} else {\n+\t\tcmd_buf[cmd_len++] = op->cmd.opcode;\n+\t}\n+\n+\t/* Put address bytes to cmd_buf */\n+\tif (op->addr.nbytes) {\n+\t\tfor (i = op->addr.nbytes - 1; i >= 0; i--) {\n+\t\t\tcmd_buf[cmd_len] = (op->addr.val >> (i * 8)) & 0xFF;\n+\t\t\tcmd_len++;\n+\t\t}\n+\t}\n+\n+\t/* Configure controller for desired operation mode (write/read) */\n+\treg_val = ax_spi_read(xspi, AX_SPI_CR2);\n+\treg_val |= AX_SPI_CR2_SWD | AX_SPI_CR2_SRI | AX_SPI_CR2_SRD;\n+\tax_spi_write(xspi, AX_SPI_CR2, reg_val);\n+\n+\t/* Write command and address bytes to TX_FIFO */\n+\tfor (i = 0; i < cmd_len; i++)\n+\t\tax_spi_write_b(xspi, AX_SPI_TXFIFO, cmd_buf[i]);\n+\n+\t/* Add dummy bytes (for clock generation) or actual data bytes to TX_FIFO */\n+\tif (op->data.dir == SPI_MEM_DATA_IN) {\n+\t\tfor (i = 0; i < op->dummy.nbytes; i++)\n+\t\t\tax_spi_write_b(xspi, AX_SPI_TXFIFO, 0x00);\n+\t\tfor (i = 0; i < op->data.nbytes; i++)\n+\t\t\tax_spi_write_b(xspi, AX_SPI_TXFIFO, 0x00);\n+\t} else {\n+\t\tfor (i = 0; i < op->data.nbytes; i++)\n+\t\t\tax_spi_write_b(xspi, AX_SPI_TXFIFO, tx_buf_ptr[i]);\n+\t}\n+\n+\t/* Start the SPI transmission */\n+\treg_val = ax_spi_read(xspi, AX_SPI_CR2);\n+\treg_val |= AX_SPI_CR2_HTE;\n+\tax_spi_write(xspi, AX_SPI_CR2, reg_val);\n+\n+\t/* Wait for TX FIFO to become empty */\n+\twhile (timeout-- > 0) {\n+\t\tu32 tx_count_reg = ax_spi_read(xspi, AX_SPI_TX_FBCAR);\n+\n+\t\tif (tx_count_reg == 0) {\n+\t\t\tudelay(1);\n+\t\t\tbreak;\n+\t\t}\n+\t\tudelay(1);\n+\t}\n+\n+\t/* Handle Data Reception (for read operations) */\n+\tif (op->data.dir == SPI_MEM_DATA_IN) {\n+\t\t/* Reset the internal RX byte buffer for this new operation.\n+\t\t * This ensures ax_spi_get_rx_byte starts fresh for each exec_op call.\n+\t\t */\n+\t\txspi->bytes_left_in_current_rx_word = 0;\n+\t\txspi->current_rx_fifo_word = 0;\n+\n+\t\ttimeout = AX_SPI_TRX_FIFO_TIMEOUT;\n+\t\twhile (timeout-- > 0) {\n+\t\t\trx_count_reg = ax_spi_read(xspi, AX_SPI_RX_FBCAR);\n+\t\t\tif (rx_count_reg >= op->data.nbytes)\n+\t\t\t\tbreak;\n+\t\t\tudelay(1); /* Small delay to prevent aggressive busy-waiting */\n+\t\t}\n+\n+\t\tif (timeout < 0) {\n+\t\t\tret = -ETIMEDOUT;\n+\t\t\tgoto out_unlock;\n+\t\t}\n+\n+\t\t/* Calculate how many bytes we need to discard from the RX FIFO.\n+\t\t * Since we set SRI, we only need to discard the address bytes and\n+\t\t * dummy bytes from the RX FIFO.\n+\t\t */\n+\t\tbytes_to_discard_from_rx = op->addr.nbytes + op->dummy.nbytes;\n+\t\tfor (i = 0; i < bytes_to_discard_from_rx; i++)\n+\t\t\tax_spi_get_rx_byte(xspi);\n+\n+\t\t/* Read actual data bytes into op->data.buf.in */\n+\t\tfor (i = 0; i < op->data.nbytes; i++) {\n+\t\t\t*rx_buf_ptr = ax_spi_get_rx_byte(xspi);\n+\t\t\trx_buf_ptr++;\n+\t\t}\n+\t} else if (op->data.dir == SPI_MEM_DATA_OUT) {\n+\t\ttimeout = AX_SPI_TRX_FIFO_TIMEOUT;\n+\t\twhile (timeout-- > 0) {\n+\t\t\tu32 tx_fifo_level = ax_spi_read(xspi, AX_SPI_TX_FBCAR);\n+\n+\t\t\tif (tx_fifo_level == 0)\n+\t\t\t\tbreak;\n+\t\t\tudelay(1);\n+\t\t}\n+\t\tif (timeout < 0) {\n+\t\t\tret = -ETIMEDOUT;\n+\t\t\tgoto out_unlock;\n+\t\t}\n+\t}\n+\n+out_unlock:\n+\t/* Deassert chip select (pull high) */\n+\tax_spi_chipselect(spi, true);\n+\n+\treturn ret;\n+}\n+\n+static int ax_spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)\n+{\n+\tstruct spi_device *spi = mem->spi;\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(spi->controller);\n+\tsize_t max_transfer_payload_bytes;\n+\tsize_t fifo_total_bytes;\n+\tsize_t protocol_overhead_bytes;\n+\n+\tfifo_total_bytes = xspi->tx_fifo_depth;\n+\t/* Calculate protocol overhead bytes according to the real operation each time. */\n+\tprotocol_overhead_bytes = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;\n+\n+\t/* Calculate the maximum data payload that can fit into the FIFO. */\n+\tif (fifo_total_bytes <= protocol_overhead_bytes) {\n+\t\tmax_transfer_payload_bytes = 0;\n+\t\tdev_warn_once(&spi->dev, \"SPI FIFO (%zu bytes) is too small for protocol overhead (%zu bytes)! Max data size forced to 0.\\n\",\n+\t\t\t fifo_total_bytes, protocol_overhead_bytes);\n+\t} else {\n+\t\tmax_transfer_payload_bytes = fifo_total_bytes - protocol_overhead_bytes;\n+\t}\n+\n+\t/* Limit op->data.nbytes based on the calculated max payload and SZ_64K.\n+\t * This is the value that spi-mem will then use to split requests.\n+\t */\n+\tif (op->data.nbytes > max_transfer_payload_bytes) {\n+\t\top->data.nbytes = max_transfer_payload_bytes;\n+\t\tdev_dbg(&spi->dev, \"%s %d: op->data.nbytes adjusted to %u due to FIFO overhead\\n\",\n+\t\t\t__func__, __LINE__, op->data.nbytes);\n+\t}\n+\n+\t/* Also apply the overall max transfer size */\n+\tif (op->data.nbytes > SZ_64K) {\n+\t\top->data.nbytes = SZ_64K;\n+\t\tdev_dbg(&spi->dev, \"%s %d: op->data.nbytes adjusted to %u due to SZ_64K limit\\n\",\n+\t\t\t__func__, __LINE__, op->data.nbytes);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static const struct spi_controller_mem_ops ax_spi_mem_ops = {\n+\t.exec_op = ax_spi_mem_exec_op,\n+\t.adjust_op_size = ax_spi_mem_adjust_op_size,\n+};\n+\n+/**\n+ * ax_spi_probe - Probe method for the SPI driver\n+ * @pdev:\tPointer to the platform_device structure\n+ *\n+ * This function initializes the driver data structures and the hardware.\n+ *\n+ * Return:\t0 on success and error value on error\n+ */\n+static int ax_spi_probe(struct platform_device *pdev)\n+{\n+\tint ret = 0, irq;\n+\tstruct spi_controller *ctlr;\n+\tstruct ax_spi *xspi;\n+\tu32 num_cs;\n+\n+\tctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*xspi));\n+\tif (!ctlr)\n+\t\treturn -ENOMEM;\n+\n+\txspi = spi_controller_get_devdata(ctlr);\n+\tctlr->dev.of_node = pdev->dev.of_node;\n+\tplatform_set_drvdata(pdev, ctlr);\n+\n+\txspi->regs = devm_platform_ioremap_resource(pdev, 0);\n+\tif (IS_ERR(xspi->regs)) {\n+\t\tret = PTR_ERR(xspi->regs);\n+\t\tgoto remove_ctlr;\n+\t}\n+\n+\txspi->pclk = devm_clk_get(&pdev->dev, \"pclk\");\n+\tif (IS_ERR(xspi->pclk)) {\n+\t\tdev_err(&pdev->dev, \"pclk clock not found.\\n\");\n+\t\tret = PTR_ERR(xspi->pclk);\n+\t\tgoto remove_ctlr;\n+\t}\n+\n+\txspi->ref_clk = devm_clk_get(&pdev->dev, \"ref\");\n+\tif (IS_ERR(xspi->ref_clk)) {\n+\t\tdev_err(&pdev->dev, \"ref clock not found.\\n\");\n+\t\tret = PTR_ERR(xspi->ref_clk);\n+\t\tgoto remove_ctlr;\n+\t}\n+\n+\tret = clk_prepare_enable(xspi->pclk);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Unable to enable APB clock.\\n\");\n+\t\tgoto remove_ctlr;\n+\t}\n+\n+\tret = clk_prepare_enable(xspi->ref_clk);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Unable to enable device clock.\\n\");\n+\t\tgoto clk_dis_apb;\n+\t}\n+\n+\tpm_runtime_use_autosuspend(&pdev->dev);\n+\tpm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);\n+\tpm_runtime_get_noresume(&pdev->dev);\n+\tpm_runtime_set_active(&pdev->dev);\n+\tpm_runtime_enable(&pdev->dev);\n+\n+\tret = of_property_read_u32(pdev->dev.of_node, \"num-cs\", &num_cs);\n+\tif (ret < 0)\n+\t\tctlr->num_chipselect = AX_SPI_DEFAULT_NUM_CS;\n+\telse\n+\t\tctlr->num_chipselect = num_cs;\n+\n+\tax_spi_detect_fifo_depth(xspi);\n+\n+\txspi->current_rx_fifo_word = 0;\n+\txspi->bytes_left_in_current_rx_word = 0;\n+\n+\t/* Initialize IRQ-related variables */\n+\txspi->bytes_left_in_current_rx_word_for_irq = 0;\n+\txspi->current_rx_fifo_word_for_irq = 0;\n+\n+\t/* SPI controller initializations */\n+\tax_spi_init_hw(xspi);\n+\n+\tirq = platform_get_irq(pdev, 0);\n+\tif (irq <= 0) {\n+\t\tret = -ENXIO;\n+\t\tgoto clk_dis_all;\n+\t}\n+\n+\tret = devm_request_irq(&pdev->dev, irq, ax_spi_irq,\n+\t\t\t 0, pdev->name, ctlr);\n+\tif (ret != 0) {\n+\t\tret = -ENXIO;\n+\t\tdev_err(&pdev->dev, \"request_irq failed\\n\");\n+\t\tgoto clk_dis_all;\n+\t}\n+\n+\tctlr->use_gpio_descriptors = true;\n+\tctlr->prepare_transfer_hardware = ax_prepare_transfer_hardware;\n+\tctlr->prepare_message = ax_prepare_message;\n+\tctlr->transfer_one = ax_transfer_one;\n+\tctlr->unprepare_transfer_hardware = ax_unprepare_transfer_hardware;\n+\tctlr->set_cs = ax_spi_chipselect;\n+\tctlr->auto_runtime_pm = true;\n+\tctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;\n+\n+\txspi->clk_rate = clk_get_rate(xspi->ref_clk);\n+\t/* Set to default valid value */\n+\tctlr->max_speed_hz = xspi->clk_rate / 2;\n+\txspi->speed_hz = ctlr->max_speed_hz;\n+\n+\tctlr->bits_per_word_mask = SPI_BPW_MASK(8);\n+\n+\tpm_runtime_mark_last_busy(&pdev->dev);\n+\tpm_runtime_put_autosuspend(&pdev->dev);\n+\n+\tctlr->mem_ops = &ax_spi_mem_ops;\n+\n+\tret = spi_register_controller(ctlr);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"spi_register_controller failed\\n\");\n+\t\tgoto clk_dis_all;\n+\t}\n+\n+\treturn ret;\n+\n+clk_dis_all:\n+\tpm_runtime_set_suspended(&pdev->dev);\n+\tpm_runtime_disable(&pdev->dev);\n+\tclk_disable_unprepare(xspi->ref_clk);\n+clk_dis_apb:\n+\tclk_disable_unprepare(xspi->pclk);\n+remove_ctlr:\n+\tspi_controller_put(ctlr);\n+\treturn ret;\n+}\n+\n+/**\n+ * ax_spi_remove - Remove method for the SPI driver\n+ * @pdev:\tPointer to the platform_device structure\n+ *\n+ * This function is called if a device is physically removed from the system or\n+ * if the driver module is being unloaded. It frees all resources allocated to\n+ * the device.\n+ */\n+static void ax_spi_remove(struct platform_device *pdev)\n+{\n+\tstruct spi_controller *ctlr = platform_get_drvdata(pdev);\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\n+\tspi_unregister_controller(ctlr);\n+\n+\tpm_runtime_set_suspended(&pdev->dev);\n+\tpm_runtime_disable(&pdev->dev);\n+\n+\tclk_disable_unprepare(xspi->ref_clk);\n+\tclk_disable_unprepare(xspi->pclk);\n+}\n+\n+/**\n+ * ax_spi_suspend - Suspend method for the SPI driver\n+ * @dev:\tAddress of the platform_device structure\n+ *\n+ * This function disables the SPI controller and\n+ * changes the driver state to \"suspend\"\n+ *\n+ * Return:\t0 on success and error value on error\n+ */\n+static int __maybe_unused ax_spi_suspend(struct device *dev)\n+{\n+\tstruct spi_controller *ctlr = dev_get_drvdata(dev);\n+\n+\treturn spi_controller_suspend(ctlr);\n+}\n+\n+/**\n+ * ax_spi_resume - Resume method for the SPI driver\n+ * @dev:\tAddress of the platform_device structure\n+ *\n+ * This function changes the driver state to \"ready\"\n+ *\n+ * Return:\t0 on success and error value on error\n+ */\n+static int __maybe_unused ax_spi_resume(struct device *dev)\n+{\n+\tstruct spi_controller *ctlr = dev_get_drvdata(dev);\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\n+\tax_spi_init_hw(xspi);\n+\treturn spi_controller_resume(ctlr);\n+}\n+\n+/**\n+ * ax_spi_runtime_resume - Runtime resume method for the SPI driver\n+ * @dev:\tAddress of the platform_device structure\n+ *\n+ * This function enables the clocks\n+ *\n+ * Return:\t0 on success and error value on error\n+ */\n+static int __maybe_unused ax_spi_runtime_resume(struct device *dev)\n+{\n+\tstruct spi_controller *ctlr = dev_get_drvdata(dev);\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\tint ret;\n+\n+\tret = clk_prepare_enable(xspi->pclk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Cannot enable APB clock.\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = clk_prepare_enable(xspi->ref_clk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Cannot enable device clock.\\n\");\n+\t\tclk_disable_unprepare(xspi->pclk);\n+\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * ax_spi_runtime_suspend - Runtime suspend method for the SPI driver\n+ * @dev:\tAddress of the platform_device structure\n+ *\n+ * This function disables the clocks\n+ *\n+ * Return:\tAlways 0\n+ */\n+static int __maybe_unused ax_spi_runtime_suspend(struct device *dev)\n+{\n+\tstruct spi_controller *ctlr = dev_get_drvdata(dev);\n+\tstruct ax_spi *xspi = spi_controller_get_devdata(ctlr);\n+\n+\tclk_disable_unprepare(xspi->ref_clk);\n+\tclk_disable_unprepare(xspi->pclk);\n+\n+\treturn 0;\n+}\n+\n+static const struct dev_pm_ops ax_spi_dev_pm_ops = {\n+\tSET_RUNTIME_PM_OPS(ax_spi_runtime_suspend,\n+\t\t\t ax_spi_runtime_resume, NULL)\n+\tSET_SYSTEM_SLEEP_PM_OPS(ax_spi_suspend, ax_spi_resume)\n+};\n+\n+static const struct of_device_id ax_spi_of_match[] = {\n+\t{ .compatible = \"axiado,ax3000-spi\" },\n+\t{ /* end of table */ }\n+};\n+MODULE_DEVICE_TABLE(of, ax_spi_of_match);\n+\n+/* ax_spi_driver - This structure defines the SPI subsystem platform driver */\n+static struct platform_driver ax_spi_driver = {\n+\t.probe\t= ax_spi_probe,\n+\t.remove\t= ax_spi_remove,\n+\t.driver = {\n+\t\t.name = AX_SPI_NAME,\n+\t\t.of_match_table = ax_spi_of_match,\n+\t\t.pm = &ax_spi_dev_pm_ops,\n+\t},\n+};\n+\n+module_platform_driver(ax_spi_driver);\n+\n+MODULE_AUTHOR(\"Axiado Corporation\");\n+MODULE_DESCRIPTION(\"Axiado SPI Host driver\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/spi/spi-axiado.h b/drivers/spi/spi-axiado.h\nnew file mode 100644\nindex 000000000000..6cf0e5bf5879\n--- /dev/null\n+++ b/drivers/spi/spi-axiado.h\n@@ -0,0 +1,133 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Axiado SPI controller driver (Host mode only)\n+ *\n+ * Copyright (C) 2022-2025 Axiado Corporation (or its affiliates).\n+ */\n+\n+#ifndef SPI_AXIADO_H\n+#define SPI_AXIADO_H\n+\n+/* Name of this driver */\n+#define AX_SPI_NAME\t\t\t\"axiado-db-spi\"\n+\n+/* Axiado - SPI Digital Blocks IP design registers */\n+#define AX_SPI_TX_FAETR\t\t\t0x18 // TX-FAETR\n+#define ALMOST_EMPTY_TRESHOLD\t\t0x00\t// Programmed threshold value\n+#define AX_SPI_RX_FAFTR\t\t\t0x28 // RX-FAETR\n+#define ALMOST_FULL_TRESHOLD\t\t0x0c\t// Programmed threshold value\n+#define FIFO_DEPTH\t\t\t256\t// 256 bytes\n+\n+#define AX_SPI_CR1\t\t\t0x00\t// CR1\n+#define AX_SPI_CR1_CLR\t\t\t0x00\t// CR1 - Clear\n+#define AX_SPI_CR1_SCR\t\t\t0x01\t// CR1 - controller reset\n+#define AX_SPI_CR1_SCE\t\t\t0x02\t// CR1 - Controller Enable/Disable\n+#define AX_SPI_CR1_CPHA\t\t\t0x08\t// CR1 - CPH\n+#define AX_SPI_CR1_CPOL\t\t\t0x10\t// CR1 - CPO\n+\n+#define AX_SPI_CR2\t\t\t0x04\t// CR2\n+#define AX_SPI_CR2_SWD\t\t\t0x04\t// CR2 - Write Enabel/Disable\n+#define AX_SPI_CR2_SRD\t\t\t0x08\t// CR2 - Read Enable/Disable\n+#define AX_SPI_CR2_SRI\t\t\t0x10\t// CR2 - Read First Byte Ignore\n+#define AX_SPI_CR2_HTE\t\t\t0x40\t// CR2 - Host Transmit Enable\n+#define AX_SPI_CR3\t\t\t0x08\t// CR3\n+#define AX_SPI_CR3_SDL\t\t\t0x00\t// CR3 - Data lines\n+#define AX_SPI_CR3_QUAD\t\t\t0x02\t// CR3 - Data lines\n+\n+/* As per Digital Blocks datasheet clock frequency range\n+ * Min - 244KHz\n+ * Max - 62.5MHz\n+ * SCK Clock Divider Register Values\n+ */\n+#define AX_SPI_RX_FBCAR\t\t\t0x24\t// RX_FBCAR\n+#define AX_SPI_TX_FBCAR\t\t\t0x14\t// TX_FBCAR\n+#define AX_SPI_SCDR\t\t\t0x2c\t// SCDR\n+#define AX_SPI_SCD_MIN\t\t\t0x1fe\t// Valid SCD (SCK Clock Divider Register)\n+#define AX_SPI_SCD_DEFAULT\t\t0x06\t// Default SCD (SCK Clock Divider Register)\n+#define AX_SPI_SCD_MAX\t\t\t0x00\t// Valid SCD (SCK Clock Divider Register)\n+#define AX_SPI_SCDR_SCS\t\t\t0x0200\t// SCDR - AMBA Bus Clock source\n+\n+#define AX_SPI_IMR\t\t\t0x34\t// IMR\n+#define AX_SPI_IMR_CLR\t\t\t0x00\t// IMR - Clear\n+#define AX_SPI_IMR_TFOM\t\t\t0x02\t// IMR - TFO\n+#define AX_SPI_IMR_MTCM\t\t\t0x40\t// IMR - MTC\n+#define AX_SPI_IMR_TFEM\t\t\t0x10\t// IMR - TFE\n+#define AX_SPI_IMR_RFFM\t\t\t0x20\t// IMR - RFFM\n+\n+#define AX_SPI_ISR\t\t\t0x30\t// ISR\n+#define AX_SPI_ISR_CLR\t\t\t0xff\t// ISR - Clear\n+#define AX_SPI_ISR_MTC\t\t\t0x40\t// ISR - MTC\n+#define AX_SPI_ISR_TFE\t\t\t0x10\t// ISR - TFE\n+#define AX_SPI_ISR_RFF\t\t\t0x20\t// ISR - RFF\n+\n+#define AX_SPI_IVR\t\t\t0x38\t// IVR\n+#define AX_SPI_IVR_TFOV\t\t\t0x02\t// IVR - TFOV\n+#define AX_SPI_IVR_MTCV\t\t\t0x40\t// IVR - MTCV\n+#define AX_SPI_IVR_TFEV\t\t\t0x10\t// IVR - TFEV\n+#define AX_SPI_IVR_RFFV\t\t\t0x20\t// IVR - RFFV\n+\n+#define AX_SPI_TXFIFO\t\t\t0x0c\t// TX_FIFO\n+#define AX_SPI_TX_RX_FBCR\t\t0x10\t// TX_RX_FBCR\n+#define AX_SPI_RXFIFO\t\t\t0x1c\t// RX_FIFO\n+\n+#define AX_SPI_TS0\t\t\t0x00\t// Target select 0\n+#define AX_SPI_TS1\t\t\t0x01\t// Target select 1\n+#define AX_SPI_TS2\t\t\t0x10\t// Target select 2\n+#define AX_SPI_TS3\t\t\t0x11\t// Target select 3\n+\n+#define SPI_AUTOSUSPEND_TIMEOUT\t\t3000\n+\n+/* Default number of chip select lines also used as maximum number of chip select lines */\n+#define AX_SPI_DEFAULT_NUM_CS\t\t4\n+\n+/* Default number of command buffer size */\n+#define AX_SPI_COMMAND_BUFFER_SIZE\t16\t//Command + address bytes\n+\n+/* Target select mask\n+ * 00 – TS0\n+ * 01 – TS1\n+ * 10 – TS2\n+ * 11 – TS3\n+ */\n+#define AX_SPI_DEFAULT_TS_MASK\t\t0x03\n+\n+#define AX_SPI_RX_FIFO_DRAIN_LIMIT\t24\n+#define AX_SPI_TRX_FIFO_TIMEOUT\t\t1000\n+/**\n+ * struct ax_spi - This definition defines spi driver instance\n+ * @regs:\t\t\t\t\tVirtual address of the SPI controller registers\n+ * @ref_clk:\t\t\t\t\tPointer to the peripheral clock\n+ * @pclk:\t\t\t\t\tPointer to the APB clock\n+ * @speed_hz:\t\t\t\t\tCurrent SPI bus clock speed in Hz\n+ * @txbuf:\t\t\t\t\tPointer\tto the TX buffer\n+ * @rxbuf:\t\t\t\t\tPointer to the RX buffer\n+ * @tx_bytes:\t\t\t\t\tNumber of bytes left to transfer\n+ * @rx_bytes:\t\t\t\t\tNumber of bytes requested\n+ * @tx_fifo_depth:\t\t\t\tDepth of the TX FIFO\n+ * @current_rx_fifo_word:\t\t\tBuffers the 32-bit word read from RXFIFO\n+ * @bytes_left_in_current_rx_word:\t\tBytes to be extracted from current 32-bit word\n+ * @current_rx_fifo_word_for_irq:\t\tBuffers the 32-bit word read from RXFIFO for IRQ\n+ * @bytes_left_in_current_rx_word_for_irq:\tIRQ bytes to be extracted from current 32-bit word\n+ * @rx_discard:\t\t\t\t\tNumber of bytes to discard\n+ * @rx_copy_remaining:\t\t\t\tNumber of bytes to copy\n+ */\n+struct ax_spi {\n+\tvoid __iomem *regs;\n+\tstruct clk *ref_clk;\n+\tstruct clk *pclk;\n+\tunsigned int clk_rate;\n+\tu32 speed_hz;\n+\tconst u8 *tx_buf;\n+\tu8 *rx_buf;\n+\tint tx_bytes;\n+\tint rx_bytes;\n+\tunsigned int tx_fifo_depth;\n+\tu32 current_rx_fifo_word;\n+\tint bytes_left_in_current_rx_word;\n+\tu32 current_rx_fifo_word_for_irq;\n+\tint bytes_left_in_current_rx_word_for_irq;\n+\tint rx_discard;\n+\tint rx_copy_remaining;\n+};\n+\n+#endif /* SPI_AXIADO_H */\n", "prefixes": [ "linux", "dev-6.18", "v1", "2/3" ] }