From patchwork Tue Jul 16 19:28:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Li X-Patchwork-Id: 812906 Received: from AS8PR04CU009.outbound.protection.outlook.com (mail-westeuropeazon11011003.outbound.protection.outlook.com [52.101.70.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48BE91A072C; Tue, 16 Jul 2024 19:29:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.70.3 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721158154; cv=fail; b=K/CidBTBH/qjofIdWdU3GfaHhOBLErgk21cnwsxUekTK7Zkoc61Lwh2gsqyi8CqlC/mFYLjxNjywnR33qRUsypqIb3MkHCKBP7B73WsHBVbjUrHcjgwye/vurrmimedtwUpKQK1clb80p8LENKWCk5hYfLqPm1IDhE6Wz8wwB2Y= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721158154; c=relaxed/simple; bh=po8Ool7o3UM4Uh/jsHpDjST0Gs9nOujmSWm9VP/qA9k=; h=From:Date:Subject:Content-Type:Message-Id:References:In-Reply-To: To:Cc:MIME-Version; b=kY2321HXdRb3cSbBYxGk/cYN3FUG+rYfdeI5JSYMDdFxmLYrbEHxUvnpQfUnXAJq2umAQbnjVBvqN09/VQ0A0oetz4IwBfSvcxyFUqN8yKfpB1C0dJeZWSCx4WB1V1ZfrogcfL1uPeAK6lHZF4S9oyCjuDiWBkqENwwNp0q/80M= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com; spf=pass smtp.mailfrom=nxp.com; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b=fzfDjYz8; arc=fail smtp.client-ip=52.101.70.3 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=nxp.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nxp.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=nxp.com header.i=@nxp.com header.b="fzfDjYz8" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=FVtZrR+PtCHAK8iSlGrAk3C6ma7EMDbHpJDHcHzoJOiF/s2p9bCFjDk3bfJX2WEo5T9HJF18+oojjn7uO9LlEwnecbnmMUzMn0G90kE6PkyJPWFN0dLKkXMGrjozU/aRRrxWHS1Sxcae8zoZSPBtEHo2bhYFWHyXcBA2KdTWKIjMixC9LYzqRtl1DCY58DegTB6OHaKFBKWO7diDC/TxanJZgmqcPy4iHOJ+dpL2ts9q/5Oh8/ykA/ZgGSsSCa+mb3+as3jFJ6LkTE0I90gh606QwROALQbYH7pIv9hFcYb2IITNMRLFfoMIRMMjTprKOOkPO75WvLSDkLPFfMrRjA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=audpQSg28RPcK+jB538LSGRNrGBU1eaNPR6AG8d/TA8=; b=oaJ/hECclSPN9PIh8ByyHgP1YfgfsNkhGQyLjwY8ZDfQGGzkZhgHmsBqKkuushUYpE5eFmFWCQNfqcrqy0oObQRLQqCuBJlfIe86ygrwJ+GoCW0hKm8v4A08I+4zmTRJj0okliJcs/0ZBXY6WRj15mPHsiO1JqDRWwpj2/fJtOwpL2717vCI4qyQf0gxjimrANYzBonE0y9OgW6RxHlYq34otdXiJ4Sp5O4P5eehB4YeLjh3SiCNm/jKXgnmsRxjRWgcPoBgDeluR4jpIdLl9nRuEPJ0MieCDgUpPlpXSbuBV8sSw7j3ud58YhPc0hRd0KIPnGPMhL63xf5nRpAVFQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nxp.com; dmarc=pass action=none header.from=nxp.com; dkim=pass header.d=nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=audpQSg28RPcK+jB538LSGRNrGBU1eaNPR6AG8d/TA8=; b=fzfDjYz8QjQSlIdLTuAuRhJj/5OacXaZiBjbsSDM8U+MMrBtkZ7e32wp2mxuLDN9OlN8f3y4AONHK3mTlUY1dfXOo87fziHtZlqyUI1rB/cJlBprQGKjBqI95P+MXHAC5hziEMuZd+OTqhlimR4z2nfINUCxM4p/kwSGDnmcSI0= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nxp.com; Received: from PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) by VE1PR04MB7325.eurprd04.prod.outlook.com (2603:10a6:800:1af::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7784.14; Tue, 16 Jul 2024 19:29:09 +0000 Received: from PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::9126:a61e:341d:4b06]) by PAXPR04MB9642.eurprd04.prod.outlook.com ([fe80::9126:a61e:341d:4b06%4]) with mapi id 15.20.7762.027; Tue, 16 Jul 2024 19:29:09 +0000 From: Frank Li Date: Tue, 16 Jul 2024 15:28:27 -0400 Subject: [PATCH 4/6] pwm: adp5585: add adp5585 PWM support Message-Id: <20240716-adi-v1-4-79c0122986e7@nxp.com> References: <20240716-adi-v1-0-79c0122986e7@nxp.com> In-Reply-To: <20240716-adi-v1-0-79c0122986e7@nxp.com> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , Bartosz Golaszewski , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Shawn Guo , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, Frank Li , Clark Wang , Haibo Chen , Jindong Yue X-Mailer: b4 0.13-dev-e586c X-Developer-Signature: v=1; a=ed25519-sha256; t=1721158123; l=8057; i=Frank.Li@nxp.com; s=20240130; h=from:subject:message-id; bh=EiVtoqMy75CK5ERMMGoJ/yXXvz/dg9oechvT32M0l38=; b=1VYa+Ewde+HKap6V5bmlRBVVooCEKmoZmOOrKajOsUzO6feYCNXSKQz9yq/kEfIlGTuEeQl/Y wtJgQJ0SDynAYynpwWRoamyZh3jVn3RV9yo7YAfMank6hHzR5GwrzgF X-Developer-Key: i=Frank.Li@nxp.com; a=ed25519; pk=I0L1sDUfPxpAkRvPKy7MdauTuSENRq+DnA+G4qcS94Q= X-ClientProxiedBy: SJ0PR03CA0148.namprd03.prod.outlook.com (2603:10b6:a03:33c::33) To PAXPR04MB9642.eurprd04.prod.outlook.com (2603:10a6:102:240::14) Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: PAXPR04MB9642:EE_|VE1PR04MB7325:EE_ X-MS-Office365-Filtering-Correlation-Id: 64b77f8a-08f5-496b-2a73-08dca5cd9096 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|1800799024|366016|376014|52116014|7416014|921020|38350700014; X-Microsoft-Antispam-Message-Info: =?utf-8?q?8oniFZyOgOgbfilU1+hUGHyrSyASH4C?= =?utf-8?q?l6gqRCSdaBVy4fOBmGQCB4AQRim3GKw0Kzp7YAadAqEIvEE+9ge8NaH3EeNSld+kg?= =?utf-8?q?epUvI8ed5T28buB0gwWirKtXUm82sIatcfD8yBLX5yNUsLrbf0tB5FnXeGfiBW11i?= =?utf-8?q?5dJTV2rdn39YcpwcZfOYQKwnpBfQsk7pFO9m3tw25Jz8wd53GR7y4nO1S5ZPFlsfJ?= =?utf-8?q?AlJbXbjgTSbBqZWrva09XEuFnJNoC5VCBtL+zOmZpUV8/yHMj8OmI9xGp6NHeSeiN?= =?utf-8?q?Uza4FPv1L1NMwcjNql7j4MutxfrrQauMUvETZ5FOEuriHETPGaIFfwbCUY1CrziNg?= =?utf-8?q?miCUfk/O0bwhOG5XNq4FwV77rkIqBOmgTNZAAmzKs8zTdLZvnEItT4g09pdMo1bX3?= =?utf-8?q?RWEyA3jGLt4rkGvWTAit1lXGPIaGdWzc5FWbotCV9r4TEi9YATDYGGYi2DIq7zCEq?= =?utf-8?q?GqODNEjQHp1V3uJQGaRVtl0xYBXuSs6zU2WXLOC1SCgpticol/i4NKikRjJ+q4bQH?= =?utf-8?q?sqqWfruorDIdEWPVhyrwPptoCS7ETeAMsexC1RjogYjxy1W9DaIyLSWRcVcS8nsMC?= =?utf-8?q?6RFeICHa2FOk5US/o1JHO5+4P65Ra7eLdqFlphWXeCYrWEmbSmU7QMVfjH2dnaQpt?= =?utf-8?q?WX0rYRW8g9dPxUKZ+2RII+JT+9/lUSxvV5pAUUsQPtWSEQDo2oExImaca/m5/d4/7?= =?utf-8?q?FdsPlWDheF6R2mmJAG4ahikYHvshnARJ36/frT+VND8UCRzpZOEakWGREDnE2j86i?= =?utf-8?q?FidKJsQ+6SoRJoKFs3PBGa/EPD5SiK5VeBmGmb/EqlhnisCp9J6It1CarUK0gCgSd?= =?utf-8?q?wjCadZLqYhKETjxEqrCXICkd4RvNBFtZvJuPPfWTvfzk4Hm2Qn90tYxOEjQPW8iNG?= =?utf-8?q?+zL0BOSHK/PlCFUi+U6/FzM43IEYFIvIjOyRIi7mKKT51ontyBupRQkXfnZ/He2Zo?= =?utf-8?q?XQL4rENE8xvyoZ6q0BNfPilYPRbaZySas0fv1x/73kaM3RzTqZlChDyUn+y5nqef/?= =?utf-8?q?PpczhCqUOEHdFkqzsI9hQETgEGBW5TMn2EiPtiElFEarB+aUfUmHIGjHAU6puA8HJ?= =?utf-8?q?FGC7s467lnVRYEgJ74iBeks4vUeTTgEl1jdMv+JJTjFNIKgm55TW5DHdjL8TBf2l5?= =?utf-8?q?s0bQhMZH7X1pS9AO4cXXnAAl38tSQJN1eiUo1EPemtK7Kz9Y/A1Z8/vPVfMXW2aRv?= =?utf-8?q?CkRLlmZCIEtgWHgmYH+aBkB4Y3l417cYB/TYZz1fwpK+Yqr7juxEuutVks20WbB/i?= =?utf-8?q?7FXSW7lD2eq6jg3itkJTDcqL6ElLVGJevnvqF7aHpxft9jkA1u/U806XpiiQvEBEu?= =?utf-8?q?0V4GDXc5C5H8uXElb/flWDyTBVG8nTNrLuLp6pdYhTPS16gaOi9Opno=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:PAXPR04MB9642.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(1800799024)(366016)(376014)(52116014)(7416014)(921020)(38350700014); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?q?gqvbE+e7OXvk6AFNyY7kuU5EJo2y?= =?utf-8?q?U85ytTMmn2WE/soczaPKjKCev4GBYi8hlhDF3gTmbczfmarArxgKpcXFzF2FAwbIK?= =?utf-8?q?zp1IyUdPMnVqOpS2Me+4ZkuoNlY3NzPek5SudC3QA5gMqmqnPNA3cEwOluQVtpjSC?= =?utf-8?q?tNtcFZsgkQ99P/tsf85GjNmwF3E0ihhv6ZPe3tiEdkzKT3VA/mH9cMzQrgai+rKRw?= =?utf-8?q?dUiCf/+6u6VVsmS6S7ye4VpZZTzMx++BckYvKuQQpvylLBsiQn1722YPALzLf3mn3?= =?utf-8?q?alhfkJjm9FHvRstBomV3up3qsKt7W4FNWoiJdT8ZJWguVYJXkiojfVCt+R8yZ4H/t?= =?utf-8?q?o6IRsG2002g10rH/mddcgguljhKNFksvYQqd5xF6nhZrjqcT1xZvcILa+SU7emqe3?= =?utf-8?q?ZS0IMcB8s7EfEY9lNaVA2GSiU6e7tWRUTaUZLwWLe3sBc+ZxxAWU7wqWi+ywoGxcP?= =?utf-8?q?bsUmhx8jtSHh2eU9ub0sQ3RbJG0TprzMsWA+RPHnUH/9WrD4Bzf4frA+tmRAoWh5m?= =?utf-8?q?9V1CZiUQCndhYft0qq4LrsSC5F6+uLIDadMV1fGr+Tcwb00eca0zo9ki0vFLvVvJI?= =?utf-8?q?1ZXvmybKPU8HyFOUezI9QPcz6dGNs0I9cPy7WwpZXXa9ohpSLKa67CnxM7sNfeTrS?= =?utf-8?q?0oYpz+SthfvRFp/MurVRWGFDpaosd5pLXC8TaLinelHbSIA7V0c10mmLrhBI0vW7T?= =?utf-8?q?fw97KVqzmECPmECMFUmBcOD2E1mI9LAMGe0FEj6pK22hiVgXbQytGbsaaWJvjKi/F?= =?utf-8?q?F0GbeKc9APwywrbqSs6u8gBUVZHClOmkdDbhfU7HQ4AwDq6AszMMW/c1U7M/G4gA/?= =?utf-8?q?1BKl1hWQlDCaqqiWEmGFo1FrrqYp/WayeEiDYEG4Tcaoy9EdSdPkM0IU8xNliWtFL?= =?utf-8?q?7JvnCvgATvUAvERTZVmeUhBXkLPpd+unCHtEPnZ6stT+f08DbKvY1ewvnl/IbEvFZ?= =?utf-8?q?ZO43RTSbU5wFpHCXoUUFs9tsvJ9hiCgu22oVMx8iUlY8zgNlbDxS96mfwBUYVbKPu?= =?utf-8?q?Xq9z6U8AqNDDd72LSvpJrIuSefytAM0qi3jf0zag1a+iZjh3S9zBiGBAjKZ49OqEz?= =?utf-8?q?qhufSLBOEbV5KsorxGX2VGRwuMyAgHP1BhuBtHxuXnQpRII8JnpJaO3677hsdkTT3?= =?utf-8?q?JeyYpr+dBtUpf6lDfxJrEsO4MtmkShM6BhKTcOlWyfZQh7gsPe5KHm6kGaBTehZWV?= =?utf-8?q?30FBT6bfprIudpWHDEz2aqbehAIuqb9pSrqdcdp3sWkzsQKkZ61OpfF02ANo1rF3s?= =?utf-8?q?3QsJYFbLeWb801ha9cXpbfgWz9hFaLd0Q4dfgMj/o7PI40I3U1R16m3uMT29iWJDT?= =?utf-8?q?0tMrsNtKasq/CGKNyAHFgV7pVbHx7EuY+O7NvkJYxMrdZXM83sxT56Nfj1uoaqoDM?= =?utf-8?q?rlFtC/i4o0m/TqLII8c20FARdspG54IzqaB+0DAPueDtsZIcFGu5nJnAovF5oYhf1?= =?utf-8?q?+NcZkgObWNlm9E4leErsOM/0T8op1zon3dyu/kk3akwMq0O98R5sovYU=3D?= X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 64b77f8a-08f5-496b-2a73-08dca5cd9096 X-MS-Exchange-CrossTenant-AuthSource: PAXPR04MB9642.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Jul 2024 19:29:09.3616 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: ok7AGpBEwoU+aoFzu/jU65joWEhCwqV1NwzGcCao5HQU9jMWavrp7SxyXISHRQFnmeBybzD05Kbs80QJosC2EA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: VE1PR04MB7325 From: Clark Wang Add PWM function support for MFD adp5585. Reviewed-by: Haibo Chen Signed-off-by: Clark Wang Signed-off-by: Jindong Yue Signed-off-by: Frank Li --- drivers/pwm/Kconfig | 8 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-adp5585.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 3e53838990f5b..baaadf877b9c6 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -38,6 +38,14 @@ config PWM_DEBUG It is expected to introduce some runtime overhead and diagnostic output to the kernel log, so only enable while working on a driver. +config PWM_ADP5585 + tristate "ADP5585 PWM support" + depends on MFD_ADP5585 + help + This option enables support for on-chip PWM found + on Analog Devices ADP5585. + + config PWM_AB8500 tristate "AB8500 PWM support" depends on AB8500_CORE && ARCH_U8500 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 0be4f3e6dd432..161131a261e94 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o obj-$(CONFIG_PWM_APPLE) += pwm-apple.o +obj-$(CONFIG_PWM_ADP5585) += pwm-adp5585.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o diff --git a/drivers/pwm/pwm-adp5585.c b/drivers/pwm/pwm-adp5585.c new file mode 100644 index 0000000000000..f578d24df5c74 --- /dev/null +++ b/drivers/pwm/pwm-adp5585.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * PWM driver for Analog Devices ADP5585 MFD + * + * Copyright 2024 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADP5585_PWM_CHAN_NUM 1 +#define ADP5585_PWM_FASTEST_PERIOD_NS 2000 +#define ADP5585_PWM_SLOWEST_PERIOD_NS 131070000 + +struct adp5585_pwm_chip { + struct device *parent; + struct mutex lock; + u8 pin_config_val; +}; + +static inline struct adp5585_pwm_chip * +to_adp5585_pwm_chip(struct pwm_chip *chip) +{ + return pwmchip_get_drvdata(chip); +} + +static int adp5585_pwm_reg_read(struct adp5585_pwm_chip *adp5585_pwm, u8 reg, u8 *val) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(adp5585_pwm->parent); + + return adp5585->read_reg(adp5585, reg, val); +} + +static int adp5585_pwm_reg_write(struct adp5585_pwm_chip *adp5585_pwm, u8 reg, u8 val) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(adp5585_pwm->parent); + + return adp5585->write_reg(adp5585, reg, val); +} + +static int pwm_adp5585_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct adp5585_pwm_chip *adp5585_pwm = to_adp5585_pwm_chip(chip); + u32 on, off; + u8 temp; + + /* get period */ + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PWM_OFFT_LOW, &temp); + off = temp; + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PWM_OFFT_HIGH, &temp); + off |= temp << 8; + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PWM_ONT_LOW, &temp); + on = temp; + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PWM_ONT_HIGH, &temp); + on |= temp << 8; + state->period = (on + off) * NSEC_PER_USEC; + + state->duty_cycle = on; + state->polarity = PWM_POLARITY_NORMAL; + + /* get channel status */ + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PWM_CFG, &temp); + state->enabled = temp & ADP5585_PWM_CFG_EN; + + return 0; +} + +static int pwm_adp5585_apply(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct adp5585_pwm_chip *adp5585_pwm = to_adp5585_pwm_chip(chip); + u32 on, off; + u8 enabled; + int ret; + + if (state->period > ADP5585_PWM_SLOWEST_PERIOD_NS || + state->period < ADP5585_PWM_FASTEST_PERIOD_NS) + return -EINVAL; + + guard(mutex)(&adp5585_pwm->lock); + + /* set on/off cycle*/ + on = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, NSEC_PER_USEC); + off = DIV_ROUND_CLOSEST_ULL((state->period - state->duty_cycle), NSEC_PER_USEC); + + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PWM_OFFT_LOW, off & ADP5585_REG_MASK); + if (ret) + return ret; + + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PWM_OFFT_HIGH, + (off >> 8) & ADP5585_REG_MASK); + if (ret) + return ret; + + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PWM_ONT_LOW, on & ADP5585_REG_MASK); + if (ret) + return ret; + + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PWM_ONT_HIGH, + (on >> 8) & ADP5585_REG_MASK); + if (ret) + return ret; + + /* enable PWM and set to continuous PWM mode*/ + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PWM_CFG, &enabled); + if (state->enabled) + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PWM_CFG, ADP5585_PWM_CFG_EN); + else + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PWM_CFG, 0); + + return ret; +} + +static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct adp5585_pwm_chip *adp5585_pwm = to_adp5585_pwm_chip(chip); + u8 reg_cfg; + int ret; + + guard(mutex)(&adp5585_pwm->lock); + + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PIN_CONFIG_C, &adp5585_pwm->pin_config_val); + reg_cfg = adp5585_pwm->pin_config_val & ~ADP5585_PIN_CONFIG_R3_MASK; + reg_cfg |= ADP5585_PIN_CONFIG_R3_PWM; + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PIN_CONFIG_C, reg_cfg); + + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_GENERAL_CFG, &adp5585_pwm->pin_config_val); + reg_cfg |= ADP5585_GENERAL_CFG_OSC_EN; + ret = adp5585_pwm_reg_write(adp5585_pwm, ADP5585_GENERAL_CFG, reg_cfg); + + return ret; +} + +static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct adp5585_pwm_chip *adp5585_pwm = to_adp5585_pwm_chip(chip); + u8 reg_cfg; + + guard(mutex)(&adp5585_pwm->lock); + + adp5585_pwm_reg_read(adp5585_pwm, ADP5585_PIN_CONFIG_C, ®_cfg); + reg_cfg &= ~ADP5585_PIN_CONFIG_R3_MASK; + reg_cfg |= adp5585_pwm->pin_config_val & ADP5585_PIN_CONFIG_R3_MASK; + adp5585_pwm_reg_write(adp5585_pwm, ADP5585_PIN_CONFIG_C, reg_cfg); +} + +static const struct pwm_ops adp5585_pwm_ops = { + .request = pwm_adp5585_request, + .free = pwm_adp5585_free, + .get_state = pwm_adp5585_get_state, + .apply = pwm_adp5585_apply, +}; + +static int adp5585_pwm_probe(struct platform_device *pdev) +{ + struct adp5585_pwm_chip *adp5585_pwm; + struct pwm_chip *chip; + unsigned int npwm = ADP5585_PWM_CHAN_NUM; + int ret; + + chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*adp5585_pwm)); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + adp5585_pwm = to_adp5585_pwm_chip(chip); + adp5585_pwm->parent = pdev->dev.parent; + + platform_set_drvdata(pdev, adp5585_pwm); + + chip->ops = &adp5585_pwm_ops; + mutex_init(&adp5585_pwm->lock); + + ret = devm_pwmchip_add(&pdev->dev, chip); + if (ret) + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); + + return ret; +} + +static void adp5585_pwm_remove(struct platform_device *pdev) +{ + struct pwm_chip *chip = platform_get_drvdata(pdev); + + pwmchip_remove(chip); +} + +static const struct of_device_id adp5585_pwm_of_match[] = { + {.compatible = "adp5585-pwm", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, adp5585_pwm_of_match); + +static struct platform_driver adp5585_pwm_driver = { + .driver = { + .name = "adp5585-pwm", + .of_match_table = adp5585_pwm_of_match, + }, + .probe = adp5585_pwm_probe, + .remove = adp5585_pwm_remove, +}; +module_platform_driver(adp5585_pwm_driver); + +MODULE_AUTHOR("Xiaoning Wang "); +MODULE_DESCRIPTION("ADP5585 PWM Driver"); +MODULE_LICENSE("GPL");