Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2227897/?format=api
{ "id": 2227897, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2227897/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/patch/20260424111330.702272-3-changhuang.liang@starfivetech.com/", "project": { "id": 42, "url": "http://patchwork.ozlabs.org/api/1.1/projects/42/?format=api", "name": "Linux GPIO development", "link_name": "linux-gpio", "list_id": "linux-gpio.vger.kernel.org", "list_email": "linux-gpio@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260424111330.702272-3-changhuang.liang@starfivetech.com>", "date": "2026-04-24T11:13:12", "name": "[v1,02/20] pinctrl: starfive: Add StarFive JHB100 sys0 controller driver", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "fcadc7b47fd4b3fab19877e0e2dd863d07d6134a", "submitter": { "id": 85771, "url": "http://patchwork.ozlabs.org/api/1.1/people/85771/?format=api", "name": "Changhuang Liang", "email": "changhuang.liang@starfivetech.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-gpio/patch/20260424111330.702272-3-changhuang.liang@starfivetech.com/mbox/", "series": [ { "id": 501347, "url": "http://patchwork.ozlabs.org/api/1.1/series/501347/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-gpio/list/?series=501347", "date": "2026-04-24T11:13:16", "name": "Add basic pinctrl drivers for JHB100 SoC", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501347/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2227897/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2227897/checks/", "tags": {}, "headers": { "Return-Path": "\n <linux-gpio+bounces-35499-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-gpio@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-gpio+bounces-35499-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n arc=fail smtp.client-ip=139.219.17.110", "smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=starfivetech.com", "dkim=none (message not signed)\n header.d=none;dmarc=none action=none header.from=starfivetech.com;" ], "Received": [ "from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g2CSl4NSzz1yDD\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 22:48:55 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 54C4130166F6\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 24 Apr 2026 12:48:11 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id BB4E03BED10;\n\tFri, 24 Apr 2026 12:48:09 +0000 (UTC)", "from CHN02-BJS-obe.outbound.protection.partner.outlook.cn\n (mail-bjschn02on2110.outbound.protection.partner.outlook.cn [139.219.17.110])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 7000B218E91;\n\tFri, 24 Apr 2026 12:48:00 +0000 (UTC)", "from ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn\n (2406:e500:c550:17::6) by ZQ4PR01MB1299.CHNPR01.prod.partner.outlook.cn\n (2406:e500:c550:15::9) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.22; Fri, 24 Apr\n 2026 11:13:41 +0000", "from ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn\n ([fe80::e7d4:256c:b066:850d]) by\n ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn ([fe80::e7d4:256c:b066:850d%5])\n with mapi id 15.20.9846.021; Fri, 24 Apr 2026 11:13:41 +0000" ], "ARC-Seal": [ "i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777034889; cv=fail;\n b=eDtTtpqSQA9PwdcVtCgdqJhfg5VN2MkvOKXS93V9aT+uNjR4VuKL/4HG696ykjJHKc3eeIwKPna72VJ6zX326FxgcOcFXVftImp8SbsASW2o2ah3dGSBp+/zWLClWAR2X2bCXkAtagyzv2f7h8/rRVw7kGJPEMgew47ohf1lgGs=", "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=MDl+kyqNHE5DKwiz2GL/MIbp9YskBSikn746mOOYRC+UzlQ5pNCbuEeC0S0j4/a+BOS49PY60XM5y9B8tHuG3ZNKnyRH/gLIKk68carGvTAcpun4XjGudaFU4egGFdgIQWJlqovNqRtPuPZfthMzQkDVl0oIpBNKEZYOYXwn8vjrn2CHlyEtAe/nzgyblUpGFhQ9rwL4XuNOpTJIO6HWR6xDxkfjPBgBcUYG4+DbxA+YUCsz8FoFcbJPePYwndrXK3DLZZ+hDVPmBXbZuXp8RtPHHd8eUnjsZ+qKy227t0argeAo7lQLTkrNRpb782aRlbsGwNGfbAEEiwpZRQBGww==" ], "ARC-Message-Signature": [ "i=2; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777034889; c=relaxed/simple;\n\tbh=4KnnCXtoez61Wm9uIN/+gOjrDhubC7t+3SBbAVwFTZ4=;\n\th=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:\n\t Content-Type:MIME-Version;\n b=irZLLRDM71manUBPTufrX6GKRhoyp1TbUdfssjJGmFLv8/+4UIvEJ4N/HcMVsWTOcjTQoRn2MIQl0copQlKM+P0zNvzHCTeQvUidEWNGm0/hT90cf0ne1Yyf2TATjfpMZCbx0FfJQFWLz02c78llp74M1BQq3/8qm7mUVXRp1SU=", "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\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=OmyAqbLBFLgZjakgmotRvVeN8iSLt8KJ5aJAdXjdaVk=;\n b=bY0C2N42VdKv1RNFyJoZ59dEPiyeLHJH4Zz3CzUtu3vXh/qZ2R/8YsbZAEn7GSiXi312Grco4eOlfch+M/w0PtbNPHr9LcSP4mt25W4sjOdcXDxzJ+2RhiRhCfjvxheJdwEqimTEfpN3l2KHYJbY3fy66r/63M7ailTKU7KZhOuAQkMWQv1UfrYpMzK5gRW07dkh5VlsEJZbtp74zzEwwCIIU07oCormJ/TvMihBftFTGEZqDwQJXrBN13qfPaGkldOeubNmE1Gac3G16EvVYLLMEdGuLQ6zIYzfiVa/unJXxCEBwfnzZjNpK/djnKNjaQNK3nhvAnT/zzZbY1d5HQ==" ], "ARC-Authentication-Results": [ "i=2; smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=starfivetech.com;\n spf=pass smtp.mailfrom=starfivetech.com;\n arc=fail smtp.client-ip=139.219.17.110", "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=starfivetech.com; dmarc=pass action=none\n header.from=starfivetech.com; dkim=pass header.d=starfivetech.com; arc=none" ], "From": "Changhuang Liang <changhuang.liang@starfivetech.com>", "To": "Linus Walleij <linusw@kernel.org>,\n\tRob Herring <robh@kernel.org>,\n\tKrzysztof Kozlowski <krzk+dt@kernel.org>,\n\tConor Dooley <conor+dt@kernel.org>,\n\tEmil Renner Berthing <kernel@esmil.dk>,\n\tPaul Walmsley <pjw@kernel.org>,\n\tAlbert Ou <aou@eecs.berkeley.edu>,\n\tPalmer Dabbelt <palmer@dabbelt.com>,\n\tAlexandre Ghiti <alex@ghiti.fr>,\n\tPhilipp Zabel <p.zabel@pengutronix.de>,\n\tBartosz Golaszewski <brgl@kernel.org>", "Cc": "linux-gpio@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org,\n\tdevicetree@vger.kernel.org,\n\tlinux-riscv@lists.infradead.org,\n\tLianfeng Ouyang <lianfeng.ouyang@starfivetech.com>,\n\tChanghuang Liang <changhuang.liang@starfivetech.com>", "Subject": "[PATCH v1 02/20] pinctrl: starfive: Add StarFive JHB100 sys0\n controller driver", "Date": "Fri, 24 Apr 2026 04:13:12 -0700", "Message-Id": "<20260424111330.702272-3-changhuang.liang@starfivetech.com>", "X-Mailer": "git-send-email 2.25.1", "In-Reply-To": "<20260424111330.702272-1-changhuang.liang@starfivetech.com>", "References": "<20260424111330.702272-1-changhuang.liang@starfivetech.com>", "Content-Transfer-Encoding": "8bit", "Content-Type": "text/plain", "X-ClientProxiedBy": "SHXPR01CA0025.CHNPR01.prod.partner.outlook.cn\n (2406:e500:c311:1b::34) To ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn\n (2406:e500:c550:17::6)", "Precedence": "bulk", "X-Mailing-List": "linux-gpio@vger.kernel.org", "List-Id": "<linux-gpio.vger.kernel.org>", "List-Subscribe": "<mailto:linux-gpio+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-gpio+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "X-MS-PublicTrafficType": "Email", "X-MS-TrafficTypeDiagnostic": "ZQ4PR01MB1202:EE_|ZQ4PR01MB1299:EE_", "X-MS-Office365-Filtering-Correlation-Id": "57a923eb-93af-4751-7f85-08dea1f28a56", "X-MS-Exchange-SenderADCheck": "1", "X-Microsoft-Antispam": "\n\tBCL:0;ARA:13230040|1800799024|366016|52116014|7416014|376014|921020|38350700014|56012099003|22082099003|18002099003;", "X-Microsoft-Antispam-Message-Info": "\n\tei4u1OstfNR2GNijHscpijiSsdcUMQN3h7UMfYy8dAtvRRb8heXrG8aWKe0SzNh14mtAahNfWAYA4CjvswkwoG3r+SMR0K9lOk16oDykjctut5V0n5EahUlzR25Y+B5Qm+LBdbJkP6fRbNZo1dMUT5KlwJGf0RbUQm1Gtc4VC82SYzruCDAo7MQV3835PaGCv/MSbhKEumsNKbNCrj5EDm308L/NOw0tgDilsJFqzpWtbTFFOdOrzX0tx2VLBWFJMu6yUO5PSzsGi0T5tHpsFUebFBOnltD0M9WtgzoRJG1mm8mKdrxzIubGqHRSKkrAfNy2dQ7Y18gORN69my0cDnZ+0vlau6J+u1k7EG3BdC4u4ByoMzFbVoPheNrnD4cDvkVaL+G9EiM95gVIRDja+YLdOcO7o7SkMbjaT1LJdJgw0BC5cuxlJ0sJ9vC4uk2t9JVWzPJag5xItJG2sgKvAS14uRlbIBxyX3PYvaQUYAyVEkWxfwFQtzFZXUlHnuP7PXB+gPWoby2DeozgQdEzB0qpT4yoqtyvykCDoD3SH9qmYBmOmFmXMLsN4QilbwbwIoSk0KU9r4zEKG9B0B85Q72ZzgAKNqqtXVeNJD3MRHQ=", "X-Forefront-Antispam-Report": "\n\tCIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(366016)(52116014)(7416014)(376014)(921020)(38350700014)(56012099003)(22082099003)(18002099003);DIR:OUT;SFP:1102;", "X-MS-Exchange-AntiSpam-MessageData-ChunkCount": "1", "X-MS-Exchange-AntiSpam-MessageData-0": "\n C8NMNxiOpWJ/gQJkzFR4taPaQjDoped7r9PxzfkWeTJ0K+obfMw0V23Jfy9pPlWUHRntbk2QIop5JOBurKlUi70Qvv5+AnVpCgJ223IADpQJyQs1A1vzAH1RNpJfp9evvpzQNmZ7gjYgJcQPYG7ZzQKCynDkjX6uNeck2vI4ONIuQJyQaRi40Anzaj7PSZEisoTIduQGUlDTbu7nhte1NQYOO/+7yMPEYzHuSdlFRUVPPK6B5QHmKYtx1whTT4gFTkU/WJlrdweqYWbl4RFOSvMthcVSl6orbU18OzJDZWyMHdjpLC90NGK6oExn+aiazSfhKkuA1oesHr5P9uKdlBfIk0yhC7L07Z4gKIHjX30Xk4nt+MhK89nmhW4ku4Rec+YBOSe12CBc7e95EFqIeBEzaFjYn4Pom3gzyWo/seLaNGAHQPqYzMRDCTYBUfXgUjnK0eWNhwyl+9WPZ2PSugzosA5qgyxTfa45QjKSp0fG2o1Jm/M482yIjJP9GAGh212u0HQNAMHxbyXfg9lc7qyRo9wqPOoJNs0aibxjFtzxGdT7DReexEldK41ze+oMgmn/qqEX3xvIyYaL409mXx14NaJH+ta7ed3pHOdBS1mB5qx9mIVinOp0lBRITsW+gtyat5rIY7kpPLAYJXkM8CJ6q9e+PJb/8Nn9Moc2hNrOT55GGfBgKsLijzlWmM5o1zs2615tHYfW4OsXZVhU6wX5l51N40nMIjLj8JAz1KnYMN5O0CdzP2GdvgpQM3i8TDkY+XkrjAKqz3oo52jJceaDfeFuOGHQ44Yehizpryfe5G7Cfyl8Xa1p16/YuFi34FoqmKBafhzZyAKx+2kRHKuVl4ndirAM3GlaamTjwh7IJt8K7vFGqGFwRSqgTNYhnBjh+RkO+DGGEimYr/3H2279UquCUJ1CHByxhJEEcFJqq4DTF3Cv9z6vZCEogHqcihnl3UEt8Mw7e6WY1ZfJVl+RxK1bKCKAwrwf/qg5pAdpOm0u8kc/6oG0UnKlqYqwsQ13d/TvXQAr6woDCNQhythU5nm7h/lLuRZQ+SIjE2OO0Bhje0AaLh7I7bnWfAF1JIMrI7Y1VzZhhA40hhN6bJSkguuOQbbTcBdY+AGx0hPXWksHDuzbAS8BocvyBc2X1kAr5ioByK8QR4ElAOHHqOfxdlHlmgB3GhtF7zRL3JORG1nOVHhH9FxBZMRLMkRIS42llHd2kZzj+q74kp841LECBCd73ezdg1sW0IJ86lKU0KFBjtBPX644wbjJ6OluIXsEckTptiB9EXuk147Nx2a/5jfdt/EPaKey+0j9Re234bzPzNNVq+qPV3sAiruL0F3K2EaPmo+KvGk4zs3BLh25jH0+Fr6eP8SVIyYxAjXmvalbNJAYU7TSmlgyhLaSghObGmJfjGLgEGrfqYCGnUzw3f0Sv1XbhWaJeVmkBh/OaIGVdlnw9o/4i25xFEjQlLC7McydKrLHqQ+G5sYdl6CF8/2Ey1TLcn61QePiCf7HSbRXIYIwZRSosxzDRfh+jsG/JSrt0n4+YcMUJBhWhnfyTIZDFVFkBfb/nDy6UiEDoQVuYwhLATLXZUws6i1hU0ri1AGTcU7j75oY8pxjt7i/gzI+qRkF3F4yiC4Efi3MY0B0crKr9aT62TUBcd8832OKCxhA0OYKGUN0DbI+2Ie975kRBMD/fC/vtDahn+vi4pVh4eYNQqNCdWX/E6v4Q0QVEmc5nBCL9OkD/uoeg8eWbP6JdQNYzsuQu34/QpWm2c1tWfyTGkpwPGP3xHA3", "X-OriginatorOrg": "starfivetech.com", "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 57a923eb-93af-4751-7f85-08dea1f28a56", "X-MS-Exchange-CrossTenant-AuthSource": "\n ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn", "X-MS-Exchange-CrossTenant-AuthAs": "Internal", "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "24 Apr 2026 11:13:41.0756\n (UTC)", "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted", "X-MS-Exchange-CrossTenant-Id": "06fe3fa3-1221-43d3-861b-5a4ee687a85c", "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED", "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n 4VtEf9pK3F5/qP/jXF9ojP904TUu9DnqKKquGPMMaMSYUeDFOhRsdcjTBMe1oRQM0i1mApF40RFQbWET16FbJjCRxGSLs+oUxiXGuauBQ7jCyo4CBKPZxXWOH9DM4Fwz", "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "ZQ4PR01MB1299" }, "content": "Add pinctrl driver for StarFive JHB100 SoC System-0(sys0) pinctrl\ncontroller.\n\nSigned-off-by: Lianfeng Ouyang <lianfeng.ouyang@starfivetech.com>\nSigned-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>\n---\n MAINTAINERS | 8 +\n drivers/pinctrl/starfive/Kconfig | 21 +\n drivers/pinctrl/starfive/Makefile | 3 +\n .../starfive/pinctrl-starfive-jhb100-sys0.c | 111 +\n .../starfive/pinctrl-starfive-jhb100.c | 1821 +++++++++++++++++\n .../starfive/pinctrl-starfive-jhb100.h | 191 ++\n 6 files changed, 2155 insertions(+)\n create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c\n create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c\n create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 4ddf8ba2e60d..b3ad0dee7307 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -25319,6 +25319,14 @@ L:\tlinux-riscv@lists.infradead.org\n S:\tMaintained\n F:\tarch/riscv/boot/dts/starfive/jhb100*\n \n+STARFIVE JHB100 PINCTRL DRIVERS\n+M:\tChanghuang Liang <changhuang.liang@starfivetech.com>\n+M:\tLianfeng Ouyang <lianfeng.ouyang@starfivetech.com>\n+L:\tlinux-gpio@vger.kernel.org\n+S:\tMaintained\n+F:\tDocumentation/devicetree/bindings/pinctrl/starfive,jhb1*.yaml\n+F:\tdrivers/pinctrl/starfive/pinctrl-starfive-jhb1*\n+\n STARFIVE JHB100 RESET CONTROLLER DRIVERS\n M:\tChanghuang Liang <changhuang.liang@starfivetech.com>\n S:\tMaintained\ndiff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig\nindex 8192ac2087fc..dc53070ee2c8 100644\n--- a/drivers/pinctrl/starfive/Kconfig\n+++ b/drivers/pinctrl/starfive/Kconfig\n@@ -49,3 +49,24 @@ config PINCTRL_STARFIVE_JH7110_AON\n \t This also provides an interface to the GPIO pins not used by other\n \t peripherals supporting inputs, outputs, configuring pull-up/pull-down\n \t and interrupts on input changes.\n+\n+config PINCTRL_STARFIVE_JHB100\n+\tbool\n+\tselect GENERIC_PINCONF\n+\tselect GENERIC_PINCTRL_GROUPS\n+\tselect GENERIC_PINMUX_FUNCTIONS\n+\tselect GPIOLIB\n+\tselect GPIOLIB_IRQCHIP\n+\tselect OF_GPIO\n+\n+config PINCTRL_STARFIVE_JHB100_SYS0\n+\ttristate \"StarFive JHB100 SoC System-0 pinctrl and GPIO driver\"\n+\tdepends on ARCH_STARFIVE || COMPILE_TEST\n+\tdepends on OF\n+\tselect PINCTRL_STARFIVE_JHB100\n+\tdefault ARCH_STARFIVE\n+\thelp\n+\t Say yes here to support system-0 pin control on the StarFive JHB100 SoC.\n+\t This also provides an interface to the GPIO pins not used by other\n+\t peripherals supporting inputs, outputs, configuring pull-up/pull-down\n+\t and interrupts on input changes.\ndiff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile\nindex ee0d32d085cb..c0d368f413bc 100644\n--- a/drivers/pinctrl/starfive/Makefile\n+++ b/drivers/pinctrl/starfive/Makefile\n@@ -5,3 +5,6 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7100)\t+= pinctrl-starfive-jh7100.o\n obj-$(CONFIG_PINCTRL_STARFIVE_JH7110)\t\t+= pinctrl-starfive-jh7110.o\n obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_SYS)\t+= pinctrl-starfive-jh7110-sys.o\n obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON)\t+= pinctrl-starfive-jh7110-aon.o\n+\n+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)\t\t+= pinctrl-starfive-jhb100.o\n+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)\t+= pinctrl-starfive-jhb100-sys0.o\ndiff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c\nnew file mode 100644\nindex 000000000000..1ee3e9a617da\n--- /dev/null\n+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c\n@@ -0,0 +1,111 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Pinctrl / GPIO driver for StarFive JHB100 SoC System-0 domain\n+ *\n+ * Copyright (C) 2024 StarFive Technology Co., Ltd.\n+ * Author: Alex Soo <yuklin.soo@starfivetech.com>\n+ *\n+ */\n+\n+#include <linux/mod_devicetable.h>\n+#include <linux/platform_device.h>\n+\n+#include \"pinctrl-starfive-jhb100.h\"\n+\n+static const struct jhb100_pin_layout_desc jhb100_sys0_pl_desc[] = {\n+\t{ .pin_start = 0, .pin_cnt = 3, .name = \"gpio\", .gpio_func_sel = 0, },\n+\t{ .pin_start = 3, .pin_cnt = 1, .name = \"bmcpcierp_pe2rst_out\", .gpio_func_sel = 1, },\n+\t{ .pin_start = 4, .pin_cnt = 1, .name = \"testen\", .gpio_func_sel = -1, },\n+\t{ .pin_start = 5, .pin_cnt = 1, .name = \"syspok_in\", .gpio_func_sel = -1, },\n+\t{ .pin_start = 6, .pin_cnt = 1, .name = \"sysrstn_in\", .gpio_func_sel = -1, },\n+\t{ .pin_start = 7, .pin_cnt = 1, .name = \"perstn0_in\", .gpio_func_sel = -1, },\n+\t{ .pin_start = 8, .pin_cnt = 1, .name = \"perstn1_in\", .gpio_func_sel = -1, },\n+\t{ .pin_start = 9, .pin_cnt = 1, .name = \"aprstn_out\", .gpio_func_sel = -1, },\n+\t{ .pin_start = 10, .pin_cnt = 1, .name = \"pcierp_wake\", .gpio_func_sel = -1, },\n+\t{ 0xff },\n+};\n+\n+static struct config_reg_layout_desc jhb100_sys0_pinctrl_crl_desc[] = {\n+\t{\n+\t\t.pin_start\t\t\t= 0,\n+\t\t.pin_cnt\t\t\t= 4,\n+\t\t.drive_strength_2bit\t\t= { .shift = 0, .width = 2 },\n+\t\t.input_enable\t\t\t= { .shift = 2, .width = 1 },\n+\t\t.pull_down\t\t\t= { .shift = 3, .width = 1 },\n+\t\t.pull_up\t\t\t= { .shift = 4, .width = 1 },\n+\t\t.slew_rate\t\t\t= { .shift = 5, .width = 1 },\n+\t\t.schmitt_trigger_select\t\t= { .shift = 6, .width = 1 },\n+\t\t.reserved\t\t\t= { .shift = 7, .width = 8 },\n+\t\t.debounce_width\t\t\t= { .shift = 15, .width = 17 },\n+\t},\n+\t{\n+\t\t.pin_start\t\t\t= 4,\n+\t\t.pin_cnt\t\t\t= 5,\n+\t\t.schmitt_trigger_select\t\t= { .shift = 0, .width = 1 },\n+\t\t.reserved\t\t\t= { .shift = 1, .width = 31 },\n+\t},\n+\t{\n+\t\t.pin_start\t\t\t= 9,\n+\t\t.pin_cnt\t\t\t= 1,\n+\t\t.drive_strength_2bit\t\t= { .shift = 0, .width = 2 },\n+\t\t.slew_rate\t\t\t= { .shift = 2, .width = 1 },\n+\t\t.reserved\t\t\t= { .shift = 3, .width = 29 },\n+\t},\n+\t{\n+\t\t.pin_start\t\t\t= 10,\n+\t\t.pin_cnt\t\t\t= 1,\n+\t\t.drive_strength_2bit\t\t= { .shift = 0, .width = 2 },\n+\t\t.input_enable\t\t\t= { .shift = 2, .width = 1 },\n+\t\t.pull_down\t\t\t= { .shift = 3, .width = 1 },\n+\t\t.pull_up\t\t\t= { .shift = 4, .width = 1 },\n+\t\t.slew_rate\t\t\t= { .shift = 5, .width = 1 },\n+\t\t.schmitt_trigger_select\t\t= { .shift = 6, .width = 1 },\n+\t\t.reserved\t\t\t= { .shift = 7, .width = 25 },\n+\t},\n+\t{ 0xff },\n+};\n+\n+struct starfive_pinctrl_regs jhb100_sys0_pinctrl_regs = {\n+\t.config\t\t\t= { .reg = 0x0c, .width_per_pin = 1 },\n+\t.output\t\t\t= { .reg = 0x38, .width_per_pin = 1 },\n+\t.output_en\t\t= { .reg = 0x3c, .width_per_pin = 1 },\n+\t.gpio_status\t\t= { .reg = 0x40, .width_per_pin = 1 },\n+\t.func_sel\t\t= { .reg = 0x44, .width_per_pin = 2 },\n+\t.irq_en\t\t\t= { .reg = 0x48, .width_per_pin = 1 },\n+\t.irq_status\t\t= { .reg = 0x4c, .width_per_pin = 1 },\n+\t.irq_clr\t\t= { .reg = 0x50, .width_per_pin = 1 },\n+\t.irq_trigger\t\t= { .reg = 0x54, .width_per_pin = 1 },\n+\t.irq_level\t\t= { .reg = 0x58, .width_per_pin = 1 },\n+\t.irq_both_edge\t\t= { .reg = 0x5c, .width_per_pin = 1 },\n+\t.irq_edge\t\t= { .reg = 0x60, .width_per_pin = 1 },\n+};\n+\n+static const struct jhb100_pinctrl_domain_info jhb100_sys0_pinctrl_info = {\n+\t.name\t\t\t= \"jhb100-sys0\",\n+\t.gc_base\t\t= -1,\n+\t.pl_desc\t\t= jhb100_sys0_pl_desc,\n+\t.crl_desc\t\t= jhb100_sys0_pinctrl_crl_desc,\n+\t.regs\t\t\t= &jhb100_sys0_pinctrl_regs,\n+};\n+\n+static const struct of_device_id jhb100_sys0_pinctrl_of_match[] = {\n+\t{\n+\t\t.compatible = \"starfive,jhb100-sys0-pinctrl\",\n+\t\t.data = &jhb100_sys0_pinctrl_info,\n+\t},\n+\t{ /* sentinel */ }\n+};\n+MODULE_DEVICE_TABLE(of, jhb100_sys0_pinctrl_of_match);\n+\n+static struct platform_driver jhb100_sys0_pinctrl_driver = {\n+\t.probe = jhb100_pinctrl_probe,\n+\t.driver = {\n+\t\t.name = \"starfive-jhb100-sys0-pinctrl\",\n+\t\t.of_match_table = jhb100_sys0_pinctrl_of_match,\n+\t},\n+};\n+module_platform_driver(jhb100_sys0_pinctrl_driver);\n+\n+MODULE_DESCRIPTION(\"Pinctrl driver for StarFive JHB100 SoC System-0 domain\");\n+MODULE_AUTHOR(\"Alex Soo <yuklin.soo@starfivetech.com>\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c\nnew file mode 100644\nindex 000000000000..3e4c60d17bb8\n--- /dev/null\n+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c\n@@ -0,0 +1,1821 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Pinctrl / GPIO driver for StarFive JHB100 SoC\n+ *\n+ * Copyright (C) 2024 StarFive Technology Co., Ltd.\n+ * Author: Alex Soo <yuklin.soo@starfivetech.com>\n+ *\n+ */\n+\n+#include <linux/bitfield.h>\n+#include <linux/bits.h>\n+#include <linux/clk.h>\n+#include <linux/gpio/driver.h>\n+#include <linux/io.h>\n+#include <linux/irq.h>\n+#include <linux/minmax.h>\n+#include <linux/mod_devicetable.h>\n+#include <linux/module.h>\n+#include <linux/mutex.h>\n+#include <linux/of.h>\n+#include <linux/platform_device.h>\n+#include <linux/reset.h>\n+#include <linux/seq_file.h>\n+#include <linux/spinlock.h>\n+#include <linux/string.h>\n+#include <linux/sort.h>\n+\n+#include <linux/pinctrl/consumer.h>\n+#include <linux/pinctrl/pinconf.h>\n+#include <linux/pinctrl/pinctrl.h>\n+#include <linux/pinctrl/pinmux.h>\n+\n+#include \"pinctrl-starfive-jhb100.h\"\n+\n+#define GPOUT_LOW\t\t\t0\n+#define GPOUT_HIGH\t\t\t1\n+\n+#define GPOEN_ENABLE\t\t\t0\n+#define GPOEN_DISABLE\t\t\t1\n+\n+#define MAX_DEBOUNCE_WIDTH_STAGES\t0x1FFFF\n+\n+/* Custom pinconf parameters */\n+#define STARFIVE_PIN_CONFIG_GMAC_VSEL\t\t(PIN_CONFIG_END + 1)\n+#define STARFIVE_PIN_CONFIG_DEBOUNCE_WIDTH\t(PIN_CONFIG_END + 2)\n+#define STARFIVE_PIN_DRIVE_I2C_FAST_MODE\t(PIN_CONFIG_END + 3)\n+#define STARFIVE_PIN_DRIVE_I2C_FAST_MODE_PLUS\t(PIN_CONFIG_END + 4)\n+#define STARFIVE_PIN_OPEN_DRAIN_PULLUP_SELECT\t(PIN_CONFIG_END + 5)\n+#define STARFIVE_PIN_VGA_RTE_SELECT\t\t(PIN_CONFIG_END + 6)\n+\n+struct field_info {\n+\tconst char *name;\n+\tunsigned int shift;\n+\tunsigned int width;\n+\tunsigned int end;\n+};\n+\n+static const struct pinconf_generic_params jhb100_custom_bindings[] = {\n+\t{ \"starfive,gmac-vsel\", STARFIVE_PIN_CONFIG_GMAC_VSEL, 0 },\n+\t{ \"starfive,debounce-width\", STARFIVE_PIN_CONFIG_DEBOUNCE_WIDTH, 0 },\n+\t{ \"starfive,drive-i2c-fast-mode\", STARFIVE_PIN_DRIVE_I2C_FAST_MODE, 0 },\n+\t{ \"starfive,drive-i2c-fast-mode-plus\", STARFIVE_PIN_DRIVE_I2C_FAST_MODE_PLUS, 0 },\n+\t{ \"starfive,i2c-open-drain-pull-up-ohm\", STARFIVE_PIN_OPEN_DRAIN_PULLUP_SELECT, 0 },\n+\t{ \"starfive,vga-rte\", STARFIVE_PIN_VGA_RTE_SELECT, 0 },\n+};\n+\n+static unsigned int jhb100_pinmux_pin(u32 v)\n+{\n+\treturn FIELD_GET(GENMASK(7, 0), v);\n+}\n+\n+static u32 jhb100_pinmux_function(u32 v)\n+{\n+\treturn FIELD_GET(GENMASK(9, 8), v);\n+}\n+\n+static u32 jhb100_get_func_sel(struct jhb100_pinctrl *sfp, unsigned int pin)\n+{\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tunsigned int offset = 4 * (pin / 16);\n+\tunsigned int shift = pinctrl_regs->func_sel.width_per_pin * (pin % 16);\n+\tu32 func_sel_mask;\n+\tu32 func_sel;\n+\tvoid __iomem *reg_gpio_func_sel;\n+\tunsigned long flags;\n+\n+\treg_gpio_func_sel = sfp->base + pinctrl_regs->func_sel.reg + offset;\n+\tfunc_sel_mask = GENMASK(pinctrl_regs->func_sel.width_per_pin - 1, 0) << shift;\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tfunc_sel = readl_relaxed(reg_gpio_func_sel);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+\n+\treturn (func_sel & func_sel_mask) >> shift;\n+}\n+\n+static struct config_reg_layout_desc *get_crl_desc_by_pin(struct jhb100_pinctrl *sfp,\n+\t\t\t\t\t\t\t unsigned int pin)\n+{\n+\tstruct config_reg_layout_desc *crl_desc = sfp->info->crl_desc;\n+\tunsigned int i = 0;\n+\n+\tdo {\n+\t\tif (pin >= crl_desc[i].pin_start &&\n+\t\t pin < crl_desc[i].pin_start + crl_desc[i].pin_cnt)\n+\t\t\treturn &crl_desc[i];\n+\t} while (crl_desc[i++].pin_start != 0xff);\n+\n+\treturn NULL;\n+}\n+\n+static struct jhb100_pinctrl *jhb100_from_irq_data(struct irq_data *d)\n+{\n+\tstruct gpio_chip *gc = irq_data_get_irq_chip_data(d);\n+\n+\treturn container_of(gc, struct jhb100_pinctrl, gc);\n+}\n+\n+static struct jhb100_pinctrl *jhb100_from_irq_desc(struct irq_desc *desc)\n+{\n+\tstruct gpio_chip *gc = irq_desc_get_handler_data(desc);\n+\n+\treturn container_of(gc, struct jhb100_pinctrl, gc);\n+}\n+\n+static int jhb100_dt_node_to_map(struct pinctrl_dev *pctldev,\n+\t\t\t\t struct device_node *np,\n+\t\t\t\t struct pinctrl_map **maps,\n+\t\t\t\t unsigned int *num_maps)\n+{\n+\tstruct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);\n+\tunsigned int old_num_funs, new_num_funs;\n+\tstruct device *dev = sfp->gc.parent;\n+\tstruct device_node *child;\n+\tstruct pinctrl_map *map;\n+\tstruct property *pinmux_p;\n+\tconst char **pgnames;\n+\tconst char *mux_grpname = NULL;\n+\tconst char *grpname = NULL;\n+\tint ngroups;\n+\tint nmaps;\n+\tint ret;\n+\n+\tngroups = 0;\n+\tfor_each_child_of_node(np, child)\n+\t\tngroups += 1;\n+\tnmaps = 2 * ngroups;\n+\n+\tpgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL);\n+\tif (!pgnames)\n+\t\treturn -ENOMEM;\n+\n+\tmap = kcalloc(nmaps, sizeof(*map), GFP_KERNEL);\n+\tif (!map)\n+\t\treturn -ENOMEM;\n+\n+\tnmaps = 0;\n+\tngroups = 0;\n+\tmutex_lock(&sfp->mutex);\n+\tfor_each_child_of_node(np, child) {\n+\t\tunsigned int old_num_groups, new_num_groups;\n+\t\tconst char *pin_grpname;\n+\t\tint nmux;\n+\t\tint *mpins;\n+\t\tu32 *pinmux;\n+\t\tint i;\n+\n+\t\tpinmux_p = of_find_property(child, \"pinmux\", NULL);\n+\t\tif (!pinmux_p) {\n+\t\t\tdev_err(dev,\n+\t\t\t\t\"%pOFn.%pOFn: no muxing or pin config is specified\\n\",\n+\t\t\t\tnp, child);\n+\t\t\tret = -EINVAL;\n+\t\t\tgoto put_child;\n+\t\t} else {\n+\t\t\tnmux = of_property_count_u32_elems(child, \"pinmux\");\n+\t\t\tif (nmux < 1) {\n+\t\t\t\tdev_err(dev,\n+\t\t\t\t\t\"invalid pinctrl group %pOFn.%pOFn: no pinmux is set\\n\",\n+\t\t\t\t\tnp, child);\n+\t\t\t\tret = -EINVAL;\n+\t\t\t\tgoto put_child;\n+\t\t\t}\n+\t\t}\n+\n+\t\tgrpname = kasprintf(GFP_KERNEL, \"%pOFn.%pOFn\", np, child);\n+\t\tif (!grpname) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto put_child;\n+\t\t}\n+\n+\t\tpgnames[ngroups] = devm_kstrdup(dev, grpname, GFP_KERNEL);\n+\t\tif (!pgnames[ngroups]) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto free_grpname;\n+\t\t}\n+\t\tngroups++;\n+\n+\t\tpin_grpname = devm_kstrdup(dev, grpname, GFP_KERNEL);\n+\t\tif (!pin_grpname) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto free_grpname;\n+\t\t}\n+\n+\t\tmux_grpname = kstrdup(grpname, GFP_KERNEL);\n+\t\tif (!mux_grpname) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto free_grpname;\n+\t\t}\n+\n+\t\tmpins = devm_kcalloc(dev, nmux, sizeof(*mpins), GFP_KERNEL);\n+\t\tif (!mpins) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto free_mux_grpname;\n+\t\t}\n+\n+\t\tpinmux = devm_kcalloc(dev, nmux, sizeof(*pinmux), GFP_KERNEL);\n+\t\tif (!pinmux) {\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto free_mux_grpname;\n+\t\t}\n+\n+\t\tret = of_property_read_u32_array(child, \"pinmux\", pinmux, nmux);\n+\t\tif (ret)\n+\t\t\tgoto free_mux_grpname;\n+\n+\t\tfor (i = 0; i < nmux; i++)\n+\t\t\tmpins[i] = jhb100_pinmux_pin(pinmux[i]);\n+\n+\t\tmap[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;\n+\t\tmap[nmaps].data.mux.function = np->name;\n+\t\tmap[nmaps].data.mux.group = mux_grpname;\n+\t\tnmaps += 1;\n+\n+\t\told_num_groups = pctldev->num_groups;\n+\n+\t\tret = pinctrl_generic_add_group(pctldev, pin_grpname,\n+\t\t\t\t\t\tmpins, nmux, pinmux);\n+\t\tif (ret < 0) {\n+\t\t\tdev_err(dev, \"error adding group %s: %d\\n\", pin_grpname, ret);\n+\t\t\tgoto free_mux_grpname;\n+\t\t}\n+\n+\t\tnew_num_groups = pctldev->num_groups;\n+\t\tif (new_num_groups == old_num_groups) {\n+\t\t\tdevm_kfree(dev, mpins);\n+\t\t\tdevm_kfree(dev, pinmux);\n+\t\t\tdevm_kfree(dev, pin_grpname);\n+\t\t}\n+\n+\t\tret = pinconf_generic_parse_dt_config(child, pctldev,\n+\t\t\t\t\t\t &map[nmaps].data.configs.configs,\n+\t\t\t\t\t\t &map[nmaps].data.configs.num_configs);\n+\t\tif (ret) {\n+\t\t\tdev_err(dev, \"error parsing pin config of group %s: %d\\n\",\n+\t\t\t\tgrpname, ret);\n+\t\t\tgoto free_mux_grpname;\n+\t\t}\n+\n+\t\t/* don't create a map if there are no pinconf settings */\n+\t\tif (map[nmaps].data.configs.num_configs == 0) {\n+\t\t\tkfree(grpname);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tmap[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;\n+\t\tmap[nmaps].data.configs.group_or_pin = grpname;\n+\t\tnmaps += 1;\n+\t}\n+\n+\told_num_funs = pctldev->num_functions;\n+\tret = pinmux_generic_add_function(pctldev, np->name,\n+\t\t\t\t\t pgnames, ngroups, NULL);\n+\tif (ret < 0) {\n+\t\tdev_err(dev, \"error adding function %s: %d\\n\", np->name, ret);\n+\t\tgoto free_mux_grpname;\n+\t}\n+\n+\tnew_num_funs = pctldev->num_functions;\n+\tif (new_num_funs == old_num_funs) {\n+\t\tint i;\n+\n+\t\tfor (i = 0; i < ngroups; i++)\n+\t\t\tdevm_kfree(dev, pgnames[i]);\n+\n+\t\tdevm_kfree(dev, pgnames);\n+\t}\n+\n+\tmutex_unlock(&sfp->mutex);\n+\n+\t*maps = map;\n+\t*num_maps = nmaps;\n+\treturn 0;\n+\n+free_mux_grpname:\n+\tkfree(mux_grpname);\n+\n+free_grpname:\n+\tkfree(grpname);\n+\n+put_child:\n+\tof_node_put(child);\n+\tmutex_unlock(&sfp->mutex);\n+\tkfree(map);\n+\treturn ret;\n+}\n+\n+static void jhb100_dt_free_map(struct pinctrl_dev *pctldev, struct pinctrl_map *map,\n+\t\t\t unsigned int num_maps)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < num_maps; i++) {\n+\t\tswitch (map[i].type) {\n+\t\tcase PIN_MAP_TYPE_MUX_GROUP:\n+\t\t\tkfree(map[i].data.mux.group);\n+\t\t\tbreak;\n+\t\tcase PIN_MAP_TYPE_CONFIGS_GROUP:\n+\t\t\tkfree(map[i].data.configs.group_or_pin);\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tpinctrl_utils_free_map(pctldev, map, num_maps);\n+}\n+\n+static const struct pinctrl_ops jhb100_pinctrl_ops = {\n+\t.get_groups_count = pinctrl_generic_get_group_count,\n+\t.get_group_name\t = pinctrl_generic_get_group_name,\n+\t.get_group_pins = pinctrl_generic_get_group_pins,\n+\t.dt_node_to_map\t = jhb100_dt_node_to_map,\n+\t.dt_free_map\t = jhb100_dt_free_map,\n+};\n+\n+static void jhb100_set_gpioval(struct jhb100_pinctrl *sfp, unsigned int pin,\n+\t\t\t unsigned int val)\n+{\n+\tconst struct jhb100_pinctrl_domain_info *info = sfp->info;\n+\tunsigned int offset = 4 * (pin / 32);\n+\tunsigned int shift = 1 * (pin % 32);\n+\tunsigned int fs_offset = 4 * (pin / 16);\n+\tunsigned int fs_shift = 2 * (pin % 16);\n+\tu32 gpio_o_mask;\n+\tu32 gpio_oen_mask;\n+\tu32 func_sel_mask;\n+\tu32 dout, doen, fs;\n+\tvoid __iomem *reg_gpio_o;\n+\tvoid __iomem *reg_gpio_oen;\n+\tvoid __iomem *reg_gpio_func_sel;\n+\tunsigned long flags;\n+\n+\treg_gpio_o = sfp->base + info->regs->output.reg + offset;\n+\treg_gpio_oen = sfp->base + info->regs->output_en.reg + offset;\n+\treg_gpio_func_sel = sfp->base + info->regs->func_sel.reg + fs_offset;\n+\n+\tgpio_o_mask = GENMASK(info->regs->output.width_per_pin - 1, 0) << shift;\n+\tgpio_oen_mask = GENMASK(info->regs->output_en.width_per_pin - 1, 0) << shift;\n+\tfunc_sel_mask = GENMASK(info->regs->func_sel.width_per_pin - 1, 0) << fs_shift;\n+\tdout = val << shift;\n+\tdoen = 0;\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tfs = readl_relaxed(reg_gpio_func_sel);\n+\tif (fs & func_sel_mask) {\n+\t\tfs &= ~func_sel_mask;\n+\t\twritel_relaxed(fs, reg_gpio_func_sel);\n+\t}\n+\tdout |= readl_relaxed(reg_gpio_o) & ~gpio_o_mask;\n+\twritel_relaxed(dout, reg_gpio_o);\n+\tdoen |= readl_relaxed(reg_gpio_oen) & ~gpio_oen_mask;\n+\twritel_relaxed(doen, reg_gpio_oen);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+}\n+\n+static void jhb100_set_function(struct jhb100_pinctrl *sfp,\n+\t\t\t\tunsigned int pin, u32 func)\n+{\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tvoid __iomem *func_sel_reg;\n+\tunsigned long flags;\n+\tu32 func_sel_mask;\n+\tu32 func_sel_val;\n+\tunsigned int offset = 4 * (pin / (32 / pinctrl_regs->func_sel.width_per_pin));\n+\tunsigned int shift = pinctrl_regs->func_sel.width_per_pin *\n+\t\t\t (pin % (32 / pinctrl_regs->func_sel.width_per_pin));\n+\n+\tif (!pinctrl_regs->func_sel.reg || !pinctrl_regs->func_sel.width_per_pin)\n+\t\treturn;\n+\n+\tfunc_sel_reg = sfp->base + pinctrl_regs->func_sel.reg + offset;\n+\tfunc_sel_mask = GENMASK(pinctrl_regs->func_sel.width_per_pin - 1, 0) << shift;\n+\tfunc_sel_val = func << shift;\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tfunc_sel_val |= readl_relaxed(func_sel_reg) & ~func_sel_mask;\n+\twritel_relaxed(func_sel_val, func_sel_reg);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+}\n+\n+static int jhb100_set_one_pin_mux(struct jhb100_pinctrl *sfp,\n+\t\t\t\t unsigned int pin,\n+\t\t\t\t u32 func,\n+\t\t\t\t int val)\n+{\n+\tconst struct pinctrl_pin_desc *desc = &sfp->pins[pin];\n+\tstruct device *dev = sfp->gc.parent;\n+\tint gpio_func_sel = sfp->gpio_func_sel_arr[pin];\n+\n+\tjhb100_set_function(sfp, pin, func);\n+\n+\tif (pin < sfp->gc.ngpio && (val == 0 || val == 1)) {\n+\t\tif (func == gpio_func_sel)\n+\t\t\tjhb100_set_gpioval(sfp, pin, val);\n+\t\telse\n+\t\t\tdev_err(dev, \"pin (%s) is not a GPIO. func=%d/%d\\n\",\n+\t\t\t\tdesc->name, func, gpio_func_sel);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int jhb100_set_mux(struct pinctrl_dev *pctldev,\n+\t\t\t unsigned int fsel, unsigned int gsel)\n+{\n+\tstruct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);\n+\tconst struct group_desc *group;\n+\tconst u32 *pinmux;\n+\tunsigned int i;\n+\n+\tgroup = pinctrl_generic_get_group(pctldev, gsel);\n+\tif (!group)\n+\t\treturn -EINVAL;\n+\n+\tpinmux = group->data;\n+\n+\tfor (i = 0; i < group->grp.npins; i++) {\n+\t\tu32 v = pinmux[i];\n+\n+\t\tjhb100_set_one_pin_mux(sfp,\n+\t\t\t\t jhb100_pinmux_pin(v),\n+\t\t\t\t jhb100_pinmux_function(v),\n+\t\t\t\t -1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static const struct pinmux_ops jhb100_pinmux_ops = {\n+\t.get_functions_count = pinmux_generic_get_function_count,\n+\t.get_function_name = pinmux_generic_get_function_name,\n+\t.get_function_groups = pinmux_generic_get_function_groups,\n+\t.set_mux = jhb100_set_mux,\n+};\n+\n+static const u8 jhb100_drive_strength_ma[4] = { 2, 4, 8, 12 };\n+\n+static const u8 jhb100_drive_strength_ma_3bit[8] = { 2, 5, 8, 10, 14, 16, 18, 20 };\n+\n+static u32 jhb100_padcfg_ds_to_mA(u32 padcfg)\n+{\n+\treturn jhb100_drive_strength_ma[padcfg];\n+}\n+\n+static u32 jhb100_padcfg_ds_to_mA_3bit(u32 padcfg)\n+{\n+\treturn jhb100_drive_strength_ma_3bit[padcfg];\n+}\n+\n+static u32 jhb100_padcfg_ds_to_uA(u32 padcfg)\n+{\n+\treturn (jhb100_drive_strength_ma[padcfg] * 1000);\n+}\n+\n+static u32 jhb100_padcfg_ds_to_uA_3bit(u32 padcfg)\n+{\n+\treturn (jhb100_drive_strength_ma_3bit[padcfg] * 1000);\n+}\n+\n+static u32 jhb100_padcfg_ds_from_mA(u32 v)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(jhb100_drive_strength_ma); i++) {\n+\t\tif (v <= jhb100_drive_strength_ma[i])\n+\t\t\tbreak;\n+\t}\n+\treturn i;\n+}\n+\n+static u32 jhb100_padcfg_ds_from_mA_3bit(u32 v)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(jhb100_drive_strength_ma_3bit); i++) {\n+\t\tif (v <= jhb100_drive_strength_ma_3bit[i])\n+\t\t\tbreak;\n+\t}\n+\treturn i;\n+}\n+\n+static u32 jhb100_padcfg_ds_from_uA(u32 v)\n+{\n+\t/* Convert from uA to mA */\n+\tv /= 1000;\n+\n+\treturn jhb100_padcfg_ds_from_mA(v);\n+}\n+\n+static u32 jhb100_padcfg_ds_from_uA_3bit(u32 v)\n+{\n+\t/* Convert from uA to mA */\n+\tv /= 1000;\n+\n+\treturn jhb100_padcfg_ds_from_mA_3bit(v);\n+}\n+\n+static void jhb100_padcfg_rmw(struct jhb100_pinctrl *sfp,\n+\t\t\t unsigned int pin, u32 mask, u32 value)\n+{\n+\tvoid __iomem *reg;\n+\tunsigned int offset;\n+\tunsigned long flags;\n+\tint padcfg_base;\n+\n+\tpadcfg_base = sfp->info->regs->config.reg;\n+\n+\toffset = 4 * pin;\n+\n+\treg = sfp->base + padcfg_base + offset;\n+\n+\tvalue &= mask;\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tvalue |= readl_relaxed(reg) & ~mask;\n+\twritel_relaxed(value, reg);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+}\n+\n+static int jhb100_pinconf_get(struct pinctrl_dev *pctldev,\n+\t\t\t unsigned int pin, unsigned long *config)\n+{\n+\tstruct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);\n+\tint param = pinconf_to_config_param(*config);\n+\tstruct device *dev = sfp->gc.parent;\n+\tstruct config_reg_layout_desc *crl_desc;\n+\tunsigned int offset;\n+\tu32 padcfg, arg;\n+\tbool enabled;\n+\tint padcfg_base;\n+\n+\tpadcfg_base = sfp->info->regs->config.reg;\n+\n+\toffset = 4 * pin;\n+\n+\tif (pin <= sfp->npins)\n+\t\tpadcfg = readl_relaxed(sfp->base + padcfg_base + offset);\n+\telse\n+\t\treturn -EINVAL;\n+\n+\tcrl_desc = get_crl_desc_by_pin(sfp, pin);\n+\tif (!crl_desc) {\n+\t\tdev_err(dev, \"pin %d can't not found reg layout descriptor\\n\", pin);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tswitch (param) {\n+\tcase PIN_CONFIG_BIAS_DISABLE:\n+\t\targ = 0;\n+\n+\t\tif (!RL_DESC_SUPPORTED(crl_desc, pull_down) ||\n+\t\t !RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\treturn -EOPNOTSUPP;\n+\n+\t\tenabled = !(padcfg & (RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t\t RL_DESC_GENMASK(crl_desc, pull_up)));\n+\t\tbreak;\n+\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\t\targ = 1;\n+\n+\t\tif (!RL_DESC_SUPPORTED(crl_desc, pull_down))\n+\t\t\treturn -EOPNOTSUPP;\n+\n+\t\tenabled = (padcfg & RL_DESC_GENMASK(crl_desc, pull_down))\n+\t\t\t >> RL_DESC_SHIFT(crl_desc, pull_down);\n+\t\tbreak;\n+\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\targ = 1;\n+\n+\t\tif (!RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\treturn -EOPNOTSUPP;\n+\n+\t\tenabled = (padcfg & RL_DESC_GENMASK(crl_desc, pull_up))\n+\t\t\t >> RL_DESC_SHIFT(crl_desc, pull_up);\n+\t\tbreak;\n+\tcase PIN_CONFIG_DRIVE_STRENGTH:\n+\t\tenabled = true;\n+\n+\t\tif (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit))\n+\t\t\targ = jhb100_padcfg_ds_to_mA(padcfg <<\n+\t\t\t\t\t\t RL_DESC_SHIFT(crl_desc,\n+\t\t\t\t\t\t\t\t drive_strength_2bit));\n+\t\telse if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit))\n+\t\t\targ = jhb100_padcfg_ds_to_mA_3bit(padcfg <<\n+\t\t\t\t\t\t\t RL_DESC_SHIFT(crl_desc,\n+\t\t\t\t\t\t\t\t\tdrive_strength_3bit));\n+\t\telse\n+\t\t\treturn -EOPNOTSUPP;\n+\t\tbreak;\n+\tcase PIN_CONFIG_DRIVE_STRENGTH_UA:\n+\t\tenabled = true;\n+\n+\t\tif (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit))\n+\t\t\targ = jhb100_padcfg_ds_to_uA(padcfg\n+\t\t\t\t<< RL_DESC_SHIFT(crl_desc, drive_strength_2bit));\n+\t\telse if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit))\n+\t\t\targ = jhb100_padcfg_ds_to_uA_3bit(padcfg\n+\t\t\t\t<< RL_DESC_SHIFT(crl_desc, drive_strength_3bit));\n+\t\telse\n+\t\t\treturn -EOPNOTSUPP;\n+\t\tbreak;\n+\tcase PIN_CONFIG_INPUT_ENABLE:\n+\t\tif (!RL_DESC_SUPPORTED(crl_desc, input_enable))\n+\t\t\treturn -EOPNOTSUPP;\n+\n+\t\tenabled = (padcfg & RL_DESC_GENMASK(crl_desc, input_enable))\n+\t\t\t >> RL_DESC_SHIFT(crl_desc, input_enable);\n+\t\targ = enabled;\n+\t\tbreak;\n+\tcase PIN_CONFIG_INPUT_SCHMITT_ENABLE:\n+\t\tif (!RL_DESC_SUPPORTED(crl_desc, schmitt_trigger_select))\n+\t\t\treturn -EOPNOTSUPP;\n+\n+\t\tenabled = (padcfg & RL_DESC_GENMASK(crl_desc, schmitt_trigger_select))\n+\t\t\t >> RL_DESC_SHIFT(crl_desc, schmitt_trigger_select);\n+\t\targ = enabled;\n+\t\tbreak;\n+\tcase PIN_CONFIG_SLEW_RATE:\n+\t\tenabled = true;\n+\n+\t\tif (!RL_DESC_SUPPORTED(crl_desc, slew_rate))\n+\t\t\treturn -EOPNOTSUPP;\n+\n+\t\targ = (padcfg & RL_DESC_GENMASK(crl_desc, slew_rate))\n+\t\t >> RL_DESC_SHIFT(crl_desc, slew_rate);\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -ENOTSUPP;\n+\t}\n+\n+\t*config = pinconf_to_config_packed(param, arg);\n+\treturn enabled ? 0 : -EINVAL;\n+}\n+\n+static int jhb100_pinconf_set(struct pinctrl_dev *pctldev,\n+\t\t\t unsigned int gpio, unsigned long *config,\n+\t\t\t unsigned int num_configs)\n+{\n+\tstruct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);\n+\tstruct device *dev = sfp->gc.parent;\n+\tstruct config_reg_layout_desc *crl_desc;\n+\tu32 param;\n+\tu32 arg;\n+\tu32 value;\n+\tu32 mask;\n+\tint i;\n+\n+\tcrl_desc = get_crl_desc_by_pin(sfp, gpio);\n+\tif (!crl_desc) {\n+\t\tdev_err(dev, \"pin %d can't not found reg layout descriptor\\n\", gpio);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfor (i = 0; i < num_configs; i++) {\n+\t\tparam = pinconf_to_config_param(config[i]);\n+\t\targ = pinconf_to_config_argument(config[i]);\n+\t\tswitch (param) {\n+\t\tcase PIN_CONFIG_BIAS_DISABLE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, pull_down) ||\n+\t\t\t !RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tvalue = 0;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, pull_down) ||\n+\t\t\t !RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tvalue = RL_DESC_GENMASK(crl_desc, pull_down);\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, pull_down) ||\n+\t\t\t !RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tvalue = RL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_PUSH_PULL:\n+\t\t\treturn 0;\n+\t\tcase PIN_CONFIG_INPUT_ENABLE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, input_enable))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, input_enable);\n+\t\t\tvalue = arg ? RL_DESC_GENMASK(crl_desc, input_enable) : 0;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_INPUT_SCHMITT_ENABLE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, schmitt_trigger_select))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, schmitt_trigger_select);\n+\t\t\tvalue = arg ? RL_DESC_GENMASK(crl_desc, schmitt_trigger_select) : 0;\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_CONFIG_DEBOUNCE_WIDTH:\n+\t\t\tif (arg > MAX_DEBOUNCE_WIDTH_STAGES)\n+\t\t\t\targ = MAX_DEBOUNCE_WIDTH_STAGES;\n+\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, debounce_width))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, debounce_width);\n+\t\t\tvalue = arg ? (arg << RL_DESC_SHIFT(crl_desc, debounce_width)) : 0;\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_CONFIG_GMAC_VSEL:\n+\t\t\tif (!RL_DESC_SUPPORTED_FUNC(crl_desc, vsel,\n+\t\t\t\t\t\t BIT(jhb100_get_func_sel(sfp, gpio))))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, vsel);\n+\t\t\tvalue = arg ? arg << RL_DESC_SHIFT(crl_desc, vsel) : 0;\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_VGA_RTE_SELECT:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, retention_signal_bus))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask = RL_DESC_GENMASK(crl_desc, retention_signal_bus);\n+\t\t\tvalue = arg ? RL_DESC_GENMASK(crl_desc, retention_signal_bus) : 0;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -ENOTSUPP;\n+\t\t}\n+\n+\t\tjhb100_padcfg_rmw(sfp, gpio, mask, value);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int jhb100_pinconf_group_get(struct pinctrl_dev *pctldev,\n+\t\t\t\t unsigned int gsel,\n+\t\t\t\t unsigned long *config)\n+{\n+\tconst struct group_desc *group;\n+\n+\tgroup = pinctrl_generic_get_group(pctldev, gsel);\n+\tif (!group)\n+\t\treturn -EINVAL;\n+\n+\treturn jhb100_pinconf_get(pctldev, group->grp.pins[0], config);\n+}\n+\n+static int jhb100_pinconf_group_set(struct pinctrl_dev *pctldev,\n+\t\t\t\t unsigned int gsel,\n+\t\t\t\t unsigned long *configs,\n+\t\t\t\t unsigned int num_configs)\n+{\n+\tstruct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);\n+\tstruct device *dev = sfp->gc.parent;\n+\tstruct config_reg_layout_desc *crl_desc;\n+\tconst struct group_desc *group;\n+\tu32 mask, value;\n+\tint i;\n+\n+\tgroup = pinctrl_generic_get_group(pctldev, gsel);\n+\tif (!group)\n+\t\treturn -EINVAL;\n+\n+\tmask = 0;\n+\tvalue = 0;\n+\tfor (i = 0; i < num_configs; i++) {\n+\t\tint param = pinconf_to_config_param(configs[i]);\n+\t\tu32 arg = pinconf_to_config_argument(configs[i]);\n+\n+\t\tcrl_desc = get_crl_desc_by_pin(sfp, group->grp.pins[0]);\n+\t\tif (!crl_desc) {\n+\t\t\tdev_err(dev, \"pin %d can't not found reg layout descriptor\\n\",\n+\t\t\t\tgroup->grp.pins[i]);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tswitch (param) {\n+\t\tcase PIN_CONFIG_BIAS_DISABLE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, pull_down) ||\n+\t\t\t !RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t\tRL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tvalue &= ~(RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t\t RL_DESC_GENMASK(crl_desc, pull_up));\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_BIAS_PULL_DOWN:\n+\t\t\tif (!arg || !RL_DESC_SUPPORTED(crl_desc, pull_down) ||\n+\t\t\t !RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t\tRL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tvalue &= ~(RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t\t RL_DESC_GENMASK(crl_desc, pull_up));\n+\t\t\tvalue |= RL_DESC_GENMASK(crl_desc, pull_down);\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_BIAS_PULL_UP:\n+\t\t\tif (!arg || !RL_DESC_SUPPORTED(crl_desc, pull_down) ||\n+\t\t\t !RL_DESC_SUPPORTED(crl_desc, pull_up))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t\tRL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tvalue &= ~(RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t\t RL_DESC_GENMASK(crl_desc, pull_up));\n+\t\t\tvalue |= RL_DESC_GENMASK(crl_desc, pull_up);\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_STRENGTH:\n+\t\t\tif (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit)) {\n+\t\t\t\tmask |= RL_DESC_GENMASK(crl_desc, drive_strength_2bit);\n+\t\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, drive_strength_2bit);\n+\t\t\t\tvalue |= jhb100_padcfg_ds_from_mA(arg) <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, drive_strength_2bit);\n+\t\t\t} else if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit)) {\n+\t\t\t\tmask |= RL_DESC_GENMASK(crl_desc, drive_strength_3bit);\n+\t\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, drive_strength_3bit);\n+\t\t\t\tvalue |= jhb100_padcfg_ds_from_mA_3bit(arg) <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, drive_strength_3bit);\n+\t\t\t} else {\n+\t\t\t\treturn -EOPNOTSUPP;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_STRENGTH_UA:\n+\t\t\tif (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit)) {\n+\t\t\t\tmask |= RL_DESC_GENMASK(crl_desc, drive_strength_2bit);\n+\t\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, drive_strength_2bit);\n+\t\t\t\tvalue |= jhb100_padcfg_ds_from_uA(arg) <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, drive_strength_2bit);\n+\t\t\t} else if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit)) {\n+\t\t\t\tmask |= RL_DESC_GENMASK(crl_desc, drive_strength_3bit);\n+\t\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, drive_strength_3bit);\n+\t\t\t\tvalue |= jhb100_padcfg_ds_from_uA_3bit(arg) <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, drive_strength_3bit);\n+\t\t\t} else {\n+\t\t\t\treturn -EOPNOTSUPP;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_INPUT_ENABLE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, input_enable))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, input_enable);\n+\t\t\tvalue = arg ? (value | RL_DESC_GENMASK(crl_desc, input_enable))\n+\t\t\t\t: value;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_INPUT_SCHMITT_ENABLE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, schmitt_trigger_select))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, schmitt_trigger_select);\n+\t\t\tvalue = arg\n+\t\t\t\t? (value | RL_DESC_GENMASK(crl_desc, schmitt_trigger_select))\n+\t\t\t\t: value;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_SLEW_RATE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, slew_rate))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, slew_rate);\n+\t\t\tvalue = arg ? (value | RL_DESC_GENMASK(crl_desc, slew_rate)) : value;\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_PUSH_PULL:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, mode_select))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue |= JHB100_PUSH_PULL <<\n+\t\t\t\t RL_DESC_SHIFT(crl_desc, mode_select);\n+\t\t\tbreak;\n+\t\tcase PIN_CONFIG_DRIVE_OPEN_DRAIN:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, mode_select))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue |= JHB100_OPEN_DRAIN <<\n+\t\t\t\t RL_DESC_SHIFT(crl_desc, mode_select);\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_DRIVE_I2C_FAST_MODE:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, mode_select))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue |= JHB100_LEGACY_FAST_MODE <<\n+\t\t\t\t RL_DESC_SHIFT(crl_desc, mode_select);\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_DRIVE_I2C_FAST_MODE_PLUS:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, mode_select))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, mode_select);\n+\t\t\tvalue |= JHB100_LEGACY_FAST_MODE_PLUS <<\n+\t\t\t\t RL_DESC_SHIFT(crl_desc, mode_select);\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_OPEN_DRAIN_PULLUP_SELECT:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, open_drain_pull_up_sel))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, open_drain_pull_up_sel);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, open_drain_pull_up_sel);\n+\t\t\tswitch (arg) {\n+\t\t\tcase 600:\n+\t\t\t\tvalue |= JHB100_I2C_OPEN_DRAIN_PU_600_OHMS <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);\n+\t\t\t\tbreak;\n+\t\t\tcase 900:\n+\t\t\t\tvalue |= JHB100_I2C_OPEN_DRAIN_PU_900_OHMS <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);\n+\t\t\t\tbreak;\n+\t\t\tcase 1200:\n+\t\t\t\tvalue |= JHB100_I2C_OPEN_DRAIN_PU_1200_OHMS <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);\n+\t\t\t\tbreak;\n+\t\t\tcase 2000:\n+\t\t\t\tvalue |= JHB100_I2C_OPEN_DRAIN_PU_2000_OHMS <<\n+\t\t\t\t\t RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\treturn -EOPNOTSUPP;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_CONFIG_DEBOUNCE_WIDTH:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, debounce_width))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, debounce_width);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, debounce_width);\n+\t\t\tvalue = arg\n+\t\t\t\t? (value | (arg << RL_DESC_SHIFT(crl_desc, debounce_width)))\n+\t\t\t\t: value;\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_CONFIG_GMAC_VSEL:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, vsel))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, vsel);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, vsel);\n+\t\t\tvalue = arg\n+\t\t\t\t? (value | (arg << RL_DESC_SHIFT(crl_desc, vsel)))\n+\t\t\t\t: value;\n+\t\t\tbreak;\n+\t\tcase STARFIVE_PIN_VGA_RTE_SELECT:\n+\t\t\tif (!RL_DESC_SUPPORTED(crl_desc, retention_signal_bus))\n+\t\t\t\treturn -EOPNOTSUPP;\n+\n+\t\t\tmask |= RL_DESC_GENMASK(crl_desc, retention_signal_bus);\n+\t\t\tvalue &= ~RL_DESC_GENMASK(crl_desc, retention_signal_bus);\n+\t\t\tvalue = arg\n+\t\t\t\t? (value | (arg << RL_DESC_SHIFT(crl_desc, retention_signal_bus)))\n+\t\t\t\t: value;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\treturn -ENOTSUPP;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < group->grp.npins; i++)\n+\t\tjhb100_padcfg_rmw(sfp, group->grp.pins[i], mask, value);\n+\n+\treturn 0;\n+}\n+\n+static const struct pinconf_ops jhb100_pinconf_ops = {\n+\t.pin_config_get\t\t= jhb100_pinconf_get,\n+\t.pin_config_set\t\t= jhb100_pinconf_set,\n+\t.pin_config_group_get\t= jhb100_pinconf_group_get,\n+\t.pin_config_group_set\t= jhb100_pinconf_group_set,\n+\t.is_generic\t\t= true,\n+};\n+\n+static int jhb100_gpio_get_direction(struct gpio_chip *gc,\n+\t\t\t\t unsigned int gpio)\n+{\n+\tstruct jhb100_pinctrl *sfp = container_of(gc, struct jhb100_pinctrl, gc);\n+\tconst struct jhb100_pinctrl_domain_info *info = sfp->info;\n+\tunsigned int offset = 4 * (gpio / 32);\n+\tunsigned int shift = 1 * (gpio % 32);\n+\tu32 gpio_oen_mask;\n+\tu32 doen;\n+\tvoid __iomem *reg_gpio_oen;\n+\n+\treg_gpio_oen = sfp->base + info->regs->output_en.reg + offset;\n+\tgpio_oen_mask = GENMASK(info->regs->output_en.width_per_pin - 1, 0) << shift;\n+\n+\tdoen = (readl_relaxed(reg_gpio_oen) & gpio_oen_mask) >> shift;\n+\n+\treturn doen == GPOEN_ENABLE ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;\n+}\n+\n+static int jhb100_gpio_direction_input(struct gpio_chip *gc,\n+\t\t\t\t unsigned int gpio)\n+{\n+\tstruct jhb100_pinctrl *sfp = container_of(gc, struct jhb100_pinctrl, gc);\n+\tstruct device *dev = sfp->gc.parent;\n+\tstruct config_reg_layout_desc *crl_desc;\n+\n+\tcrl_desc = get_crl_desc_by_pin(sfp, gpio);\n+\tif (!crl_desc) {\n+\t\tdev_err(dev, \"pin %d can't not found reg layout descriptor\\n\",\n+\t\t\tgpio);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tjhb100_padcfg_rmw(sfp, gpio,\n+\t\t\t RL_DESC_GENMASK(crl_desc, input_enable) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, schmitt_trigger_select),\n+\t\t\t RL_DESC_GENMASK(crl_desc, input_enable) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, schmitt_trigger_select));\n+\n+\tjhb100_set_one_pin_mux(sfp, gpio, 0, -1);\n+\n+\treturn 0;\n+}\n+\n+static int jhb100_gpio_direction_output(struct gpio_chip *gc,\n+\t\t\t\t\tunsigned int gpio, int value)\n+{\n+\tstruct jhb100_pinctrl *sfp = container_of(gc, struct jhb100_pinctrl, gc);\n+\tstruct device *dev = sfp->gc.parent;\n+\tstruct config_reg_layout_desc *crl_desc;\n+\n+\tjhb100_set_one_pin_mux(sfp, gpio, 0,\n+\t\t\t value ? GPOUT_HIGH : GPOUT_LOW);\n+\n+\tcrl_desc = get_crl_desc_by_pin(sfp, gpio);\n+\tif (!crl_desc) {\n+\t\tdev_err(dev, \"pin %d can't not found reg layout descriptor\\n\",\n+\t\t\tgpio);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tjhb100_padcfg_rmw(sfp, gpio,\n+\t\t\t RL_DESC_GENMASK(crl_desc, input_enable) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, schmitt_trigger_select) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, pull_down) |\n+\t\t\t RL_DESC_GENMASK(crl_desc, pull_up),\n+\t\t\t 0);\n+\n+\treturn 0;\n+}\n+\n+static int jhb100_gpio_get(struct gpio_chip *gc, unsigned int gpio)\n+{\n+\tstruct jhb100_pinctrl *sfp = container_of(gc, struct jhb100_pinctrl, gc);\n+\tconst struct jhb100_pinctrl_domain_info *info = sfp->info;\n+\tunsigned int offset = 4 * (gpio / 32);\n+\tunsigned int shift = 1 * (gpio % 32);\n+\tu32 gpio_oen_mask = GENMASK(info->regs->output_en.width_per_pin - 1, 0) << shift;\n+\tu32 doen = 0;\n+\tvoid __iomem *reg_gpio_oen;\n+\tvoid __iomem *reg;\n+\tunsigned long flags;\n+\n+\treg_gpio_oen = sfp->base + info->regs->output_en.reg + offset;\n+\treg = sfp->base + info->regs->gpio_status.reg + offset;\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tdoen = readl_relaxed(reg_gpio_oen) | gpio_oen_mask;\n+\twritel_relaxed(doen, reg_gpio_oen);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+\n+\treturn !!(readl_relaxed(reg) & BIT(gpio % 32));\n+}\n+\n+static int jhb100_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)\n+{\n+\tstruct jhb100_pinctrl *sfp = container_of(gc, struct jhb100_pinctrl, gc);\n+\tconst struct jhb100_pinctrl_domain_info *info = sfp->info;\n+\tunsigned int offset = 4 * (gpio / 32);\n+\tunsigned int shift = 1 * (gpio % 32);\n+\tvoid __iomem *reg_dout;\n+\tu32 dout;\n+\tu32 mask;\n+\tunsigned long flags;\n+\n+\treg_dout = sfp->base + info->regs->output.reg + offset;\n+\tdout = (value ? GPOUT_HIGH : GPOUT_LOW) << shift;\n+\tmask = GENMASK(info->regs->output.width_per_pin - 1, 0) << shift;\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tdout |= readl_relaxed(reg_dout) & ~mask;\n+\twritel_relaxed(dout, reg_dout);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+\n+\treturn 0;\n+}\n+\n+static void jhb100_irq_ack(struct irq_data *d)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_data(d);\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tirq_hw_number_t gpio = irqd_to_hwirq(d);\n+\tvoid __iomem *ic;\n+\tu32 mask;\n+\tunsigned long flags;\n+\tu32 value;\n+\n+\tic = sfp->base + pinctrl_regs->irq_clr.reg + 4 * (gpio / 32);\n+\tmask = BIT(gpio % 32);\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tvalue = readl_relaxed(ic) & ~mask;\n+\twritel_relaxed(value | mask, ic);\n+\tvalue = readl_relaxed(ic) & ~mask;\n+\twritel_relaxed(value, ic);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+}\n+\n+static void jhb100_irq_mask(struct irq_data *d)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_data(d);\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tirq_hw_number_t gpio = irqd_to_hwirq(d);\n+\tvoid __iomem *ien;\n+\tu32 mask;\n+\tunsigned long flags;\n+\tu32 value;\n+\n+\tien = sfp->base + pinctrl_regs->irq_en.reg + 4 * (gpio / 32);\n+\tmask = BIT(gpio % 32);\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tvalue = readl_relaxed(ien) & ~mask;\n+\twritel_relaxed(value, ien);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+\n+\tgpiochip_disable_irq(&sfp->gc, d->hwirq);\n+}\n+\n+static void jhb100_irq_mask_ack(struct irq_data *d)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_data(d);\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tirq_hw_number_t gpio = irqd_to_hwirq(d);\n+\tvoid __iomem *ien;\n+\tvoid __iomem *ic;\n+\tu32 mask = BIT(gpio % 32);\n+\tunsigned long flags;\n+\tu32 value;\n+\n+\tien = sfp->base + pinctrl_regs->irq_en.reg + 4 * (gpio / 32);\n+\tic = sfp->base + pinctrl_regs->irq_clr.reg + 4 * (gpio / 32);\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tvalue = readl_relaxed(ien) & ~mask;\n+\twritel_relaxed(value, ien);\n+\n+\tvalue = readl_relaxed(ic) & ~mask;\n+\twritel_relaxed(value | mask, ic);\n+\tvalue = readl_relaxed(ic) & ~mask;\n+\twritel_relaxed(value, ic);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+}\n+\n+static void jhb100_irq_unmask(struct irq_data *d)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_data(d);\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tirq_hw_number_t gpio = irqd_to_hwirq(d);\n+\tvoid __iomem *ien;\n+\tu32 mask;\n+\tunsigned long flags;\n+\tu32 value;\n+\n+\tien = sfp->base + pinctrl_regs->irq_en.reg + 4 * (gpio / 32);\n+\tmask = BIT(gpio % 32);\n+\n+\tgpiochip_enable_irq(&sfp->gc, d->hwirq);\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tvalue = readl_relaxed(ien) | mask;\n+\twritel_relaxed(value, ien);\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+}\n+\n+static int jhb100_irq_set_type(struct irq_data *d, unsigned int trigger)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_data(d);\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tirq_hw_number_t gpio = irqd_to_hwirq(d);\n+\tvoid __iomem *base;\n+\tu32 mask;\n+\tu32 irq_type, edge_both, polarity;\n+\tunsigned long flags;\n+\n+\tbase = sfp->base + 4 * (gpio / 32);\n+\tmask = BIT(gpio % 32);\n+\n+\tswitch (trigger) {\n+\tcase IRQ_TYPE_EDGE_RISING:\n+\t\tirq_type = mask; /* 1: edge triggered */\n+\t\tedge_both = 0; /* 0: single edge */\n+\t\tpolarity = mask; /* 1: rising edge */\n+\t\tbreak;\n+\tcase IRQ_TYPE_EDGE_FALLING:\n+\t\tirq_type = mask; /* 1: edge triggered */\n+\t\tedge_both = 0; /* 0: single edge */\n+\t\tpolarity = 0; /* 0: falling edge */\n+\t\tbreak;\n+\tcase IRQ_TYPE_EDGE_BOTH:\n+\t\tirq_type = mask; /* 1: edge triggered */\n+\t\tedge_both = mask; /* 1: both edges */\n+\t\tpolarity = 0; /* 0: ignored */\n+\t\tbreak;\n+\tcase IRQ_TYPE_LEVEL_HIGH:\n+\t\tirq_type = 0; /* 0: level triggered */\n+\t\tedge_both = 0; /* 0: ignored */\n+\t\tpolarity = mask; /* 1: high level */\n+\t\tbreak;\n+\tcase IRQ_TYPE_LEVEL_LOW:\n+\t\tirq_type = 0; /* 0: level triggered */\n+\t\tedge_both = 0; /* 0: ignored */\n+\t\tpolarity = 0; /* 0: low level */\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (trigger & IRQ_TYPE_EDGE_BOTH)\n+\t\tirq_set_handler_locked(d, handle_edge_irq);\n+\telse\n+\t\tirq_set_handler_locked(d, handle_level_irq);\n+\n+\traw_spin_lock_irqsave(&sfp->lock, flags);\n+\tirq_type |= readl_relaxed(base + pinctrl_regs->irq_trigger.reg) & ~mask;\n+\twritel_relaxed(irq_type, base + pinctrl_regs->irq_trigger.reg);\n+\n+\tedge_both |= readl_relaxed(base + pinctrl_regs->irq_both_edge.reg) & ~mask;\n+\twritel_relaxed(edge_both, base + pinctrl_regs->irq_both_edge.reg);\n+\n+\tif (irq_type & mask) { /* edge polarity */\n+\t\tpolarity |= readl_relaxed(base + pinctrl_regs->irq_edge.reg) & ~mask;\n+\t\twritel_relaxed(polarity, base + pinctrl_regs->irq_edge.reg);\n+\t} else if (irq_type == 0) { /* level polarity */\n+\t\tpolarity |= readl_relaxed(base + pinctrl_regs->irq_level.reg) & ~mask;\n+\t\twritel_relaxed(polarity, base + pinctrl_regs->irq_level.reg);\n+\t}\n+\traw_spin_unlock_irqrestore(&sfp->lock, flags);\n+\treturn 0;\n+}\n+\n+static int jhb100_irq_set_wake(struct irq_data *d, unsigned int enable)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_data(d);\n+\tint ret = 0;\n+\n+\tif (enable)\n+\t\tret = enable_irq_wake(sfp->wakeup_irq);\n+\telse\n+\t\tret = disable_irq_wake(sfp->wakeup_irq);\n+\tif (ret)\n+\t\tdev_err(sfp->dev, \"failed to %s wake-up interrupt\\n\",\n+\t\t\tenable ? \"enable\" : \"disable\");\n+\n+\treturn ret;\n+}\n+\n+static void jhb100_irq_print_chip(struct irq_data *d, struct seq_file *p)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_data(d);\n+\n+\tseq_printf(p, sfp->gc.label);\n+}\n+\n+static const struct irq_chip jhb100_irq_chip = {\n+\t.irq_ack = jhb100_irq_ack,\n+\t.irq_mask = jhb100_irq_mask,\n+\t.irq_mask_ack = jhb100_irq_mask_ack,\n+\t.irq_unmask = jhb100_irq_unmask,\n+\t.irq_set_type = jhb100_irq_set_type,\n+\t.irq_set_wake = jhb100_irq_set_wake,\n+\t.irq_print_chip = jhb100_irq_print_chip,\n+\t.flags = IRQCHIP_SET_TYPE_MASKED |\n+\t\t\t IRQCHIP_IMMUTABLE |\n+\t\t\t IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND |\n+\t\t\t IRQCHIP_MASK_ON_SUSPEND |\n+\t\t\t IRQCHIP_SKIP_SET_WAKE,\n+\tGPIOCHIP_IRQ_RESOURCE_HELPERS,\n+};\n+\n+static void jhb100_gpio_irq_handler(struct irq_desc *desc)\n+{\n+\tstruct jhb100_pinctrl *sfp = jhb100_from_irq_desc(desc);\n+\tstruct irq_chip *chip = irq_desc_get_chip(desc);\n+\tstruct gpio_irq_chip *girq = &sfp->gc.irq;\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tunsigned long is;\n+\tunsigned int pin;\n+\tunsigned int total, size, remain = sfp->npins;\n+\n+\tchained_irq_enter(chip, desc);\n+\n+\tfor (total = 0, size = 0; total < sfp->npins; total += 32, remain -= size) {\n+\t\tis = readl_relaxed(sfp->base + pinctrl_regs->irq_status.reg +\n+\t\t\t\t (total >> 3));\n+\t\tsize = umin(remain, 32);\n+\n+\t\tfor_each_set_bit(pin, &is, size) {\n+\t\t\tif (sfp->gpio_func_sel_arr[pin] >= 0)\n+\t\t\t\tgeneric_handle_domain_irq(girq->domain, pin);\n+\t\t}\n+\t}\n+\n+\tchained_irq_exit(chip, desc);\n+}\n+\n+static int jhb100_gpio_init_hw(struct gpio_chip *gc)\n+{\n+\tstruct jhb100_pinctrl *sfp = container_of(gc, struct jhb100_pinctrl, gc);\n+\tstruct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < sfp->npins; i += 32) {\n+\t\t/* mask all GPIO interrupts */\n+\t\twritel_relaxed(0U, sfp->base + pinctrl_regs->irq_en.reg + (i >> 3));\n+\t\t/* clear all interrupts */\n+\t\twritel_relaxed(~0U, sfp->base + pinctrl_regs->irq_clr.reg + (i >> 3));\n+\t\twritel_relaxed(0U, sfp->base + pinctrl_regs->irq_clr.reg + (i >> 3));\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int field_compare(const void *a, const void *b)\n+{\n+\tconst struct field_info *fa = (const struct field_info *)a;\n+\tconst struct field_info *fb = (const struct field_info *)b;\n+\n+\tif (fa->shift < fb->shift)\n+\t\treturn -1;\n+\n+\tif (fa->shift > fb->shift)\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+static int check_crl_desc(struct jhb100_pinctrl *sfp, unsigned int index,\n+\t\t\t const struct config_reg_layout_desc *desc)\n+{\n+\tstruct device *dev = sfp->gc.parent;\n+\tstruct field_info *fields;\n+\tint field_cnt = 0;\n+\tint num, i;\n+\n+\tnum = sizeof(struct config_reg_layout_desc) / sizeof(struct reg_layout_field);\n+\n+\tfields = kcalloc(num, sizeof(struct field_info), GFP_KERNEL);\n+\tif (!fields)\n+\t\treturn -ENOMEM;\n+\n+\t#define COLLECT_FIELD(field) \\\n+\t\tdo { \\\n+\t\t\tif (desc->field.width > 0) { \\\n+\t\t\t\tfields[field_cnt].name = #field; \\\n+\t\t\t\tfields[field_cnt].shift = desc->field.shift; \\\n+\t\t\t\tfields[field_cnt].width = desc->field.width; \\\n+\t\t\t\tfields[field_cnt].end = desc->field.shift + desc->field.width; \\\n+\t\t\t\tfield_cnt++; \\\n+\t\t\t} \\\n+\t\t} while (0)\n+\n+\t/* same as struct config_reg_layout_desc filed except for pin_start and pin_cnt */\n+\tCOLLECT_FIELD(debounce_width);\n+\tCOLLECT_FIELD(drive_strength_2bit);\n+\tCOLLECT_FIELD(drive_strength_3bit);\n+\tCOLLECT_FIELD(function);\n+\tCOLLECT_FIELD(input_enable);\n+\tCOLLECT_FIELD(vsel);\n+\tCOLLECT_FIELD(mode_select);\n+\tCOLLECT_FIELD(open_drain_pull_up_sel);\n+\tCOLLECT_FIELD(pull_down);\n+\tCOLLECT_FIELD(pull_up);\n+\tCOLLECT_FIELD(reserved);\n+\tCOLLECT_FIELD(retention_signal_bus);\n+\tCOLLECT_FIELD(schmitt_trigger_select);\n+\tCOLLECT_FIELD(slew_rate);\n+\n+\t#undef COLLECT_FIELD\n+\n+\tsort(fields, field_cnt, sizeof(struct field_info), field_compare, NULL);\n+\n+\tfor (i = 0; i < field_cnt; i++) {\n+\t\tif (fields[i].end > 32) {\n+\t\t\tdev_err(dev,\n+\t\t\t\t\"layout %d: field %s exceeds 32bit [shift=%u, width=%u, end=%u]\\n\",\n+\t\t\t\tindex, fields[i].name,\n+\t\t\t\tfields[i].shift, fields[i].width, fields[i].end);\n+\t\t\tgoto failed;\n+\t\t}\n+\n+\t\tif (i < field_cnt - 1) {\n+\t\t\tif (fields[i].end > fields[i + 1].shift) {\n+\t\t\t\tdev_err(dev,\n+\t\t\t\t\t\"layout %d: field overlap: %s[%u:%u] with %s[%u:%u]\\n\",\n+\t\t\t\t\tindex, fields[i].name, fields[i].end - 1,\n+\t\t\t\t\tfields[i].shift, fields[i + 1].name,\n+\t\t\t\t\tfields[i + 1].end - 1, fields[i + 1].shift);\n+\t\t\t\tgoto failed;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (desc->reserved.width > 0) {\n+\t\tunsigned int used_mask = 0;\n+\t\tunsigned int reserved_mask = 0;\n+\n+\t\tfor (i = 0; i < field_cnt; i++) {\n+\t\t\tif (strcmp(fields[i].name, \"reserved\"))\n+\t\t\t\tused_mask |= GENMASK(fields[i].end - 1, fields[i].shift);\n+\t\t\telse\n+\t\t\t\treserved_mask |= GENMASK(fields[i].end - 1, fields[i].shift);\n+\t\t}\n+\n+\t\tif ((used_mask | reserved_mask) != 0xFFFFFFFF) {\n+\t\t\tdev_err(dev,\n+\t\t\t\t\"layout %d: reserved field not cover all unused bits\\n\",\n+\t\t\t\tindex);\n+\t\t\tdev_err(dev,\n+\t\t\t\t\"used mask: 0x%08X, reserved mask: 0x%08X, combined: 0x%08X\\n\",\n+\t\t\t\tused_mask, reserved_mask, used_mask | reserved_mask);\n+\t\t}\n+\t}\n+\n+\tkfree(fields);\n+\treturn 0;\n+\n+failed:\n+\tkfree(fields);\n+\treturn -EINVAL;\n+}\n+\n+static int check_layout_pin_range(struct jhb100_pinctrl *sfp,\n+\t\t\t\t const struct config_reg_layout_desc *descs,\n+\t\t\t\t unsigned int num_desc)\n+{\n+\tstruct device *dev = sfp->gc.parent;\n+\n+\tif (descs[num_desc - 1].pin_start + descs[num_desc - 1].pin_cnt > sfp->npins) {\n+\t\tdev_err(dev, \"layout %u pin_start[%u] + pin_cnt[%u] exceeds pin number[%u]\\n\",\n+\t\t\tnum_desc - 1, descs[num_desc - 1].pin_start,\n+\t\t\tdescs[num_desc - 1].pin_cnt, sfp->npins);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tfor (int i = 0; i < num_desc; i++) {\n+\t\tif (descs[i].pin_start == 0xff)\n+\t\t\tbreak;\n+\n+\t\tif (i < num_desc - 1) {\n+\t\t\tif (descs[i].pin_start + descs[i].pin_cnt > descs[i + 1].pin_start) {\n+\t\t\t\tdev_err(dev, \"pin range: [%u-%u] overlaps with [%u-%u]\\n\",\n+\t\t\t\t\tdescs[i].pin_start, descs[i].pin_cnt,\n+\t\t\t\t\tdescs[i + 1].pin_start, descs[i + 1].pin_cnt);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\n+\t\t\tif (descs[i].pin_start + descs[i].pin_cnt < descs[i + 1].pin_start) {\n+\t\t\t\tdev_err(dev, \"pin range: [%u-%u] -> [%u-%u] has gap\\n\",\n+\t\t\t\t\tdescs[i].pin_start, descs[i].pin_cnt,\n+\t\t\t\t\tdescs[i + 1].pin_start, descs[i + 1].pin_cnt);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int check_pinctrl_layouts(struct jhb100_pinctrl *sfp,\n+\t\t\t\t const struct config_reg_layout_desc *layouts)\n+{\n+\tstruct device *dev = sfp->gc.parent;\n+\tint i = 0, err_cnt = 0, ret;\n+\n+\tif (!layouts) {\n+\t\tdev_err(dev, \"layout pointer is NULL\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\twhile (layouts[i].pin_start != 0xff) {\n+\t\tret = check_crl_desc(sfp, i, &layouts[i]);\n+\t\tif (ret) {\n+\t\t\tdev_err(dev, \"layout %d check failed\\n\", i);\n+\t\t\terr_cnt++;\n+\t\t}\n+\n+\t\tif (++i > 100) {\n+\t\t\tdev_err(dev, \"too many layouts or missing 0xff for end\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\tif (!err_cnt) {\n+\t\tret = check_layout_pin_range(sfp, layouts, i);\n+\t\tif (ret)\n+\t\t\terr_cnt++;\n+\t}\n+\n+\tif (err_cnt) {\n+\t\tdev_err(dev, \"pinctrl layout check finish with %d error(s)\\n\", err_cnt);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tdev_info(dev, \"pinctrl layout check completed!\\n\");\n+\treturn 0;\n+}\n+\n+static\n+struct pinctrl_pin_desc *devm_create_pins_from_pld(struct device *dev,\n+\t\t\t\t\t\t const struct jhb100_pin_layout_desc *desc,\n+\t\t\t\t\t\t const char *prefix,\n+\t\t\t\t\t\t unsigned int *total_pins,\n+\t\t\t\t\t\t unsigned int *total_gpios,\n+\t\t\t\t\t\t int **gpio_func_sel_arr)\n+{\n+\tstruct pinctrl_pin_desc *pins = NULL;\n+\tunsigned int i, j, ngpios = 0, npins = 0, pin_index = 0;\n+\tunsigned int same_name_found = 0;\n+\tint *arr;\n+\n+\tif (!dev || !desc || !prefix) {\n+\t\tdev_err(dev, \"Invalid parameters: desc=%p, prefix=%s\\n\",\n+\t\t\tdesc, prefix);\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\n+\tfor (i = 0; desc[i].pin_start != 0xff; i++) {\n+\t\tif (!desc[i].pin_cnt) {\n+\t\t\tdev_err(dev, \"Invalid pin cnt\\n\");\n+\t\t\treturn ERR_PTR(-EINVAL);\n+\t\t}\n+\n+\t\tnpins += desc[i].pin_cnt;\n+\t}\n+\n+\tif (npins == 0) {\n+\t\tdev_err(dev, \"No pins defined\\n\");\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\n+\tdev_dbg(dev, \"Total pins to create: %d\\n\", npins);\n+\n+\tpins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);\n+\tif (!pins)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tarr = devm_kzalloc(dev, npins, GFP_KERNEL);\n+\tif (!arr)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tfor (i = 0; desc[i].pin_start != 0xff; i++) {\n+\t\tsame_name_found = 0;\n+\n+\t\tfor (j = 0; j < i; j++) {\n+\t\t\tif (!strcmp(desc[j].name, desc[i].name)) {\n+\t\t\t\tsame_name_found = 1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tfor (j = 0; j < desc[i].pin_cnt; j++) {\n+\t\t\tchar *name = NULL;\n+\t\t\tint pin_num = desc[i].pin_start + j;\n+\n+\t\t\tpins[pin_index].number = pin_num;\n+\t\t\tif (same_name_found) {\n+\t\t\t\tname = devm_kasprintf(dev, GFP_KERNEL, \"%s_%s_%d\",\n+\t\t\t\t\t\t prefix, desc[i].name,\n+\t\t\t\t\t\t desc[i].pin_start + j);\n+\t\t\t} else {\n+\t\t\t\tif (desc[i].pin_cnt > 1)\n+\t\t\t\t\tname = devm_kasprintf(dev, GFP_KERNEL, \"%s_%s_%d\",\n+\t\t\t\t\t\t\t prefix, desc[i].name, j);\n+\t\t\t\telse\n+\t\t\t\t\tname = devm_kasprintf(dev, GFP_KERNEL, \"%s_%s\",\n+\t\t\t\t\t\t\t prefix, desc[i].name);\n+\t\t\t}\n+\n+\t\t\tif (!name) {\n+\t\t\t\tdev_err(dev, \"Failed to allocate pin name for pin %d\\n\",\n+\t\t\t\t\tpin_num);\n+\t\t\t\treturn ERR_PTR(-ENOMEM);\n+\t\t\t}\n+\n+\t\t\tif (!strcmp(desc[i].name, \"gpio\") || desc[i].gpio_func_sel != -1)\n+\t\t\t\tngpios++;\n+\n+\t\t\tpins[pin_index].name = name;\n+\t\t\tarr[pin_index] = desc[i].gpio_func_sel;\n+\t\t\tpin_index++;\n+\t\t}\n+\t}\n+\n+\t*total_pins = npins;\n+\t*total_gpios = ngpios;\n+\t*gpio_func_sel_arr = arr;\n+\n+\treturn pins;\n+}\n+\n+static int of_pinvref_get(struct device *dev, const struct pinvref_desc *pv_desc, u32 *val)\n+{\n+\tchar prop_name[32];\n+\tstruct device_node *np = dev->of_node;\n+\tint ret;\n+\n+\tsnprintf(prop_name, sizeof(prop_name), \"%s-vref\", pv_desc->name);\n+\tdev_dbg(dev, \"Looking up %s from node %pOF\\n\", prop_name, np);\n+\n+\tret = of_property_read_u32(np, prop_name, val);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Looking up %s in node %pOF failed: %d\\n\", prop_name, np, ret);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int starfive_pinvref_set(struct device *dev, void __iomem *reg,\n+\t\t\t\tunsigned int val, const struct pinvref_desc *pv_desc)\n+{\n+\tif (!pv_desc->range)\n+\t\treturn 0;\n+\n+\tif (pv_desc->range & BIT(val)) {\n+\t\twritel(val, reg);\n+\t} else {\n+\t\tdev_err(dev, \"pin vref range is unsupported(%lx/%x)\\n\", BIT(val), pv_desc->range);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int starfive_pinvref_init(struct device *dev, void __iomem *base,\n+\t\t\t\t struct starfive_pinctrl_regs *pinctrl_regs)\n+{\n+\tint ret = 0;\n+\tunsigned int val, i = 0;\n+\tstruct pinvref_reg *vref;\n+\n+\tvref = &pinctrl_regs->vref;\n+\tif (!vref->pv_desc)\n+\t\treturn ret;\n+\n+\twhile (vref->pv_desc[i].name) {\n+\t\tret = of_pinvref_get(dev, &vref->pv_desc[i], &val);\n+\t\tif (!ret)\n+\t\t\tret = starfive_pinvref_set(dev, base + vref->reg + i * 4,\n+\t\t\t\t\t\t val, &vref->pv_desc[i]);\n+\t\ti++;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int jhb100_pinctrl_probe(struct platform_device *pdev)\n+{\n+\tstruct device *dev = &pdev->dev;\n+\tstruct gpio_irq_chip *girq;\n+\tconst struct jhb100_pinctrl_domain_info *info;\n+\tstruct jhb100_pinctrl *sfp;\n+\tstruct pinctrl_desc *jhb100_pinctrl_desc;\n+\tstruct reset_control *rst;\n+\tstruct clk *clk;\n+\tint ret;\n+\n+\tinfo = of_device_get_match_data(&pdev->dev);\n+\tif (!info)\n+\t\treturn -ENODEV;\n+\n+\tsfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL);\n+\tif (!sfp)\n+\t\treturn -ENOMEM;\n+\n+\tsfp->base = devm_platform_ioremap_resource(pdev, 0);\n+\tif (IS_ERR(sfp->base))\n+\t\treturn PTR_ERR(sfp->base);\n+\n+\tclk = devm_clk_get_optional_enabled(dev, NULL);\n+\tif (IS_ERR(clk))\n+\t\treturn dev_err_probe(dev, PTR_ERR(clk), \"could not get & enable clock\\n\");\n+\n+\trst = devm_reset_control_array_get_optional_shared(dev);\n+\tif (IS_ERR(rst))\n+\t\treturn dev_err_probe(dev, PTR_ERR(rst), \"could not get reset control\\n\");\n+\n+\t/*\n+\t * we don't want to assert reset and risk undoing pin muxing for the\n+\t * early boot serial console, but let's make sure the reset line is\n+\t * deasserted in case someone runs a really minimal bootloader.\n+\t */\n+\tret = reset_control_deassert(rst);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret, \"could not deassert reset\\n\");\n+\n+\tsfp->pins = devm_create_pins_from_pld(dev, info->pl_desc, info->name,\n+\t\t\t\t\t &sfp->npins, &sfp->ngpios,\n+\t\t\t\t\t &sfp->gpio_func_sel_arr);\n+\tif (IS_ERR(sfp->pins))\n+\t\treturn PTR_ERR(sfp->pins);\n+\n+\tjhb100_pinctrl_desc = devm_kzalloc(&pdev->dev,\n+\t\t\t\t\t sizeof(*jhb100_pinctrl_desc),\n+\t\t\t\t\t GFP_KERNEL);\n+\tif (!jhb100_pinctrl_desc)\n+\t\treturn -ENOMEM;\n+\n+\tjhb100_pinctrl_desc->name = dev_name(dev);\n+\tjhb100_pinctrl_desc->num_custom_params = ARRAY_SIZE(jhb100_custom_bindings);\n+\tjhb100_pinctrl_desc->custom_params = jhb100_custom_bindings;\n+\tjhb100_pinctrl_desc->pctlops = &jhb100_pinctrl_ops;\n+\tjhb100_pinctrl_desc->pmxops = &jhb100_pinmux_ops;\n+\tjhb100_pinctrl_desc->confops = &jhb100_pinconf_ops;\n+\tjhb100_pinctrl_desc->owner = THIS_MODULE;\n+\tjhb100_pinctrl_desc->pins = sfp->pins;\n+\tjhb100_pinctrl_desc->npins = sfp->npins;\n+\n+\tsfp->info = info;\n+\tsfp->dev = dev;\n+\tplatform_set_drvdata(pdev, sfp);\n+\tsfp->gc.parent = dev;\n+\traw_spin_lock_init(&sfp->lock);\n+\tmutex_init(&sfp->mutex);\n+\n+\tret = devm_pinctrl_register_and_init(dev, jhb100_pinctrl_desc,\n+\t\t\t\t\t sfp, &sfp->pctl);\n+\tif (ret)\n+\t\treturn dev_err_probe(dev, ret,\n+\t\t\t\t \"could not register pinctrl driver\\n\");\n+\n+\tsfp->gc.label = dev_name(dev);\n+\tsfp->gc.owner = THIS_MODULE;\n+\tsfp->gc.request = pinctrl_gpio_request;\n+\tsfp->gc.free = pinctrl_gpio_free;\n+\tsfp->gc.get_direction = jhb100_gpio_get_direction;\n+\tsfp->gc.direction_input = jhb100_gpio_direction_input;\n+\tsfp->gc.direction_output = jhb100_gpio_direction_output;\n+\tsfp->gc.get = jhb100_gpio_get;\n+\tsfp->gc.set = jhb100_gpio_set;\n+\tsfp->gc.set_config = gpiochip_generic_config;\n+\tsfp->gc.base = info->gc_base;\n+\tsfp->gc.ngpio = sfp->ngpios;\n+\n+\tgirq = &sfp->gc.irq;\n+\n+\tif (info->regs->irq_edge.reg) {\n+\t\tgpio_irq_chip_set_chip(girq, &jhb100_irq_chip);\n+\t\tgirq->parent_handler = jhb100_gpio_irq_handler;\n+\t\tgirq->num_parents = 1;\n+\t\tgirq->parents = devm_kcalloc(dev, girq->num_parents,\n+\t\t\t\t\t sizeof(*girq->parents),\n+\t\t\t\t\t GFP_KERNEL);\n+\t\tif (!girq->parents)\n+\t\t\treturn -ENOMEM;\n+\n+\t\tgirq->default_type = IRQ_TYPE_NONE;\n+\t\tgirq->handler = handle_bad_irq;\n+\t\tgirq->init_hw = jhb100_gpio_init_hw;\n+\n+\t\tret = platform_get_irq(pdev, 0);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\tgirq->parents[0] = ret;\n+\t}\n+\n+\tret = pinctrl_enable(sfp->pctl);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (sfp->gc.ngpio > 0) {\n+\t\tret = devm_gpiochip_add_data(dev, &sfp->gc, sfp);\n+\t\tif (ret)\n+\t\t\treturn dev_err_probe(dev, ret, \"could not register gpiochip\\n\");\n+\n+\t\tdev_info(dev, \"StarFive JHB100 GPIO chip registered %d GPIOs\\n\",\n+\t\t\t sfp->gc.ngpio);\n+\t}\n+\n+\tret = check_pinctrl_layouts(sfp, info->crl_desc);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = starfive_pinvref_init(dev, sfp->base, info->regs);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(jhb100_pinctrl_probe);\n+\n+MODULE_DESCRIPTION(\"Pinctrl driver for the StarFive JHB100 SoC\");\n+MODULE_AUTHOR(\"Alex Soo <yuklin.soo@starfivetech.com>\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h\nnew file mode 100644\nindex 000000000000..a5e7c788ba13\n--- /dev/null\n+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h\n@@ -0,0 +1,191 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Pinctrl / GPIO driver for StarFive JHB100 SoC\n+ *\n+ * Copyright (C) 2024 StarFive Technology Co., Ltd.\n+ * Author: Alex Soo <yuklin.soo@starfivetech.com>\n+ *\n+ */\n+\n+#ifndef __PINCTRL_STARFIVE_JHB100_H__\n+#define __PINCTRL_STARFIVE_JHB100_H__\n+\n+#include <linux/gpio/driver.h>\n+#include <linux/pinctrl/pinconf-generic.h>\n+#include <linux/pinctrl/pinmux.h>\n+\n+#include \"../core.h\"\n+\n+#define PER2_GMAC_RGMII_FUNC\t\t\t1\n+#define PER2_GMAC_RMII_FUNC\t\t\t2\n+#define PER3_GMAC_RMII_FUNC\t\t\t1\n+\n+/* mode select */\n+#define JHB100_PUSH_PULL\t\t\t0\n+#define JHB100_OPEN_DRAIN\t\t\t1\n+#define JHB100_LEGACY_FAST_MODE_PLUS\t\t2\n+#define JHB100_LEGACY_FAST_MODE\t\t\t3\n+\n+/* i2c open-drain pull-up select */\n+#define JHB100_I2C_OPEN_DRAIN_PU_600_OHMS\t0\n+#define JHB100_I2C_OPEN_DRAIN_PU_900_OHMS\t1\n+#define JHB100_I2C_OPEN_DRAIN_PU_1200_OHMS\t2\n+#define JHB100_I2C_OPEN_DRAIN_PU_2000_OHMS\t3\n+\n+struct jhb100_pin_layout_desc {\n+\tunsigned int pin_start;\n+\tunsigned int pin_cnt;\n+\tconst char *name;\n+\tint gpio_func_sel;\n+};\n+\n+struct jhb100_pinctrl {\n+\tstruct device *dev;\n+\tstruct gpio_chip gc;\n+\tstruct pinctrl_gpio_range gpios;\n+\traw_spinlock_t lock;\n+\tconst char *iodomain_name;\n+\tvoid __iomem *base;\n+\tstruct pinctrl_dev *pctl;\n+\t/* register read/write mutex */\n+\tstruct mutex mutex;\n+\tconst struct jhb100_pinctrl_domain_info *info;\n+\t/* wakeup */\n+\tint wakeup_gpio;\n+\tint wakeup_irq;\n+\tstruct irq_domain *irq_domain;\n+\tconst struct pinctrl_pin_desc *pins;\n+\tunsigned int npins;\n+\tunsigned int ngpios;\n+\tint *gpio_func_sel_arr;\n+};\n+\n+/* pinref voltage range */\n+#define JHB100_PINVREF_3_3V\t0\n+#define JHB100_PINVREF_2_5V\t1\n+#define JHB100_PINVREF_1_8V\t2\n+\n+struct pinvref_desc {\n+\tconst char *name;\n+\tunsigned int range;\n+};\n+\n+struct pinvref_reg {\n+\tunsigned int reg;\n+\tconst struct pinvref_desc *pv_desc;\n+};\n+\n+struct gpio_irq_reg {\n+\tunsigned int reg;\n+\tunsigned int width_per_pin;\n+};\n+\n+struct starfive_pinctrl_regs {\n+\tstruct pinvref_reg vref;\n+\tstruct gpio_irq_reg config;\n+\tstruct gpio_irq_reg output;\n+\tstruct gpio_irq_reg output_en;\n+\tstruct gpio_irq_reg func_sel;\n+\tstruct gpio_irq_reg gpio_status;\n+\tstruct gpio_irq_reg irq_en;\n+\tstruct gpio_irq_reg irq_status;\n+\tstruct gpio_irq_reg irq_clr;\n+\tstruct gpio_irq_reg irq_trigger;\n+\tstruct gpio_irq_reg irq_level;\n+\tstruct gpio_irq_reg irq_both_edge;\n+\tstruct gpio_irq_reg irq_edge;\n+};\n+\n+struct reg_layout_field {\n+\tunsigned char shift;\n+\tunsigned char width;\n+\tunsigned int func;\n+};\n+\n+#define RL_DESC_SUPPORTED(crl_desc, field) ({ \\\n+\ttypeof(crl_desc) _desc = (crl_desc); \\\n+\t(_desc && _desc->field.width > 0); \\\n+})\n+\n+#define RL_DESC_SHIFT(crl_desc, field) ({ \\\n+\ttypeof(crl_desc) __desc = (crl_desc); \\\n+\t__desc->field.shift; \\\n+})\n+\n+#define RL_DESC_GENMASK(crl_desc, field) ({ \\\n+\ttypeof(crl_desc) __desc = (crl_desc); \\\n+\tRL_DESC_SUPPORTED(__desc, field) ? \\\n+\tGENMASK(__desc->field.shift + __desc->field.width - 1, __desc->field.shift) : 0; \\\n+})\n+\n+#define RL_DESC_SUPPORTED_FUNC(crl_desc, field, pinfunc) ({ \\\n+\ttypeof(crl_desc) _desc = (crl_desc); \\\n+\t(_desc && _desc->field.width > 0 && \\\n+\t\t(!_desc->field.func || (_desc->field.func & pinfunc))); \\\n+})\n+\n+struct config_reg_layout_desc {\n+\tunsigned int pin_start;\n+\tunsigned int pin_cnt;\n+\n+\tstruct reg_layout_field debounce_width;\n+\tstruct reg_layout_field drive_strength_2bit;\n+\tstruct reg_layout_field drive_strength_3bit;\n+\tstruct reg_layout_field function;\n+\tstruct reg_layout_field input_enable;\n+\tstruct reg_layout_field vsel;\n+\tstruct reg_layout_field mode_select;\n+\tstruct reg_layout_field open_drain_pull_up_sel;\n+\tstruct reg_layout_field pull_down;\n+\tstruct reg_layout_field pull_up;\n+\tstruct reg_layout_field reserved;\n+\tstruct reg_layout_field retention_signal_bus;\n+\tstruct reg_layout_field schmitt_trigger_select;\n+\tstruct reg_layout_field slew_rate;\n+};\n+\n+struct funcsel_reg_layout_desc {\n+\tunsigned int pin_start;\n+\tunsigned int pin_cnt;\n+\tunsigned int width;\n+};\n+\n+struct jhb100_pinctrl_domain_info {\n+\tconst char *name;\n+\tunsigned int gc_base;\n+\tconst struct pinctrl_pin_desc *pins;\n+\tconst struct jhb100_pin_layout_desc *pl_desc;\n+\tstruct config_reg_layout_desc *crl_desc;\n+\tstruct starfive_pinctrl_regs *regs;\n+};\n+\n+static inline irq_hw_number_t pin_to_hwirq(struct jhb100_pinctrl *sfp)\n+{\n+\treturn sfp->wakeup_gpio - sfp->info->gc_base;\n+}\n+\n+int jhb100_pinctrl_probe(struct platform_device *pdev);\n+\n+void pinctrl_utils_free_map(struct pinctrl_dev *pctldev,\n+\t\t\t struct pinctrl_map *map, unsigned int num_maps);\n+int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev);\n+const char *pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,\n+\t\t\t\t\t unsigned int selector);\n+int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,\n+\t\t\t\t unsigned int selector,\n+\t\t\t\t const char * const **groups,\n+\t\t\t\t unsigned int * const num_groups);\n+int pinmux_generic_add_function(struct pinctrl_dev *pctldev,\n+\t\t\t\tconst char *name,\n+\t\t\t\tconst char * const *groups,\n+\t\t\t\tunsigned int const num_groups,\n+\t\t\t\tvoid *data);\n+\n+#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)\n+int pinconf_generic_parse_dt_config(struct device_node *np,\n+\t\t\t\t struct pinctrl_dev *pctldev,\n+\t\t\t\t unsigned long **configs,\n+\t\t\t\t unsigned int *nconfigs);\n+#endif\n+\n+#endif /* __PINCTRL_STARFIVE_JHB100_H__ */\n", "prefixes": [ "v1", "02/20" ] }