From patchwork Mon May 20 19:59:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 797917 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 93ACE13665A; Mon, 20 May 2024 19:59:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235195; cv=none; b=ixNA2jlm8iDki0+sT7aJfw6mk/9Wn9/aG72pCUlIkf5YcpnSAvU8R/CiVJ6EbR3TEUR+bt/F/0IM/Axy/i8Z69M2sTVr8YKKBmX0CbwCVA3nUhtOtAZY7dfL7UWFxgiemhoKBo6BMmODK6lNE367eYRWNDaClfRi4PcmYg0kK4s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235195; c=relaxed/simple; bh=pwfh1HNB6ejIfQ8JrKO9PRDbCXrx5uV4yhJeYYaiDvo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tMCEhfEQ+wxb3ZMcYmwzxuvy1KnQKhTf43+4eqrYXXhEAxF3eQPyvw1HRqG86q5UUi1kDJtfrD4UT50aVkzeoFK45RK4IGPGFve/MVOBduJa0dDOGNZt/lffxfEjlChU6lQ0StVXWlmdEDiaH2qqD9hB1Sjt4hqBNvhv49BHPZw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=U3DoIdXM; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="U3DoIdXM" Received: from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi [81.175.209.231]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 99EF7EBB; Mon, 20 May 2024 21:59:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716235180; bh=pwfh1HNB6ejIfQ8JrKO9PRDbCXrx5uV4yhJeYYaiDvo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=U3DoIdXMI/EIM1O756bGUJlOIRbTUzw3se0GaiKuScuEfmjpPu8/hReq4Z+vzCFq6 s1HxhEHuOjXi26iHmaVkmVX3dUh0uZWOevR7HEKJ/vkvWTHGB1VS/mGJV1lmGLLoCq qaL1cUl3hKwu8U0eZNjSlH8ahsVgxybx+h6tnw+s= From: Laurent Pinchart To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org Cc: Alexandru Ardelean , Bartosz Golaszewski , Conor Dooley , Krzysztof Kozlowski , Lee Jones , Linus Walleij , Rob Herring , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= Subject: [PATCH 1/5] dt-bindings: trivial-devices: Drop adi,adp5585 and adi,adp5585-02 Date: Mon, 20 May 2024 22:59:37 +0300 Message-ID: <20240520195942.11582-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.44.1 In-Reply-To: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> References: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The Analog Devices ADP5585 is a multi-function device that requires non-trivial DT bindings. To prepare for proper support of the device, drop the related compatible strings from trivial-devices.yaml. They were added by mistake, without any user in the mainline kernel, neither in device tree sources nor in drivers. Fixes: e5dddbedfe09 ("dt-bindings: add ADP5585/ADP5589 entries to trivial-devices") Signed-off-by: Laurent Pinchart --- Documentation/devicetree/bindings/trivial-devices.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index e07be7bf8395..59102d46b98e 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -39,10 +39,6 @@ properties: # AD5110 - Nonvolatile Digital Potentiometer - adi,ad5110 # Analog Devices ADP5585 Keypad Decoder and I/O Expansion - - adi,adp5585 - # Analog Devices ADP5585 Keypad Decoder and I/O Expansion with support for Row5 - - adi,adp5585-02 - # Analog Devices ADP5589 Keypad Decoder and I/O Expansion - adi,adp5589 # Analog Devices LT7182S Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher - adi,lt7182s From patchwork Mon May 20 19:59:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 798049 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 51B1313958B; Mon, 20 May 2024 19:59:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235197; cv=none; b=ayWImph2yJnn8UcifSxCNpi7NOGWAjih45jXKEdj/pFMmrdFpJU3pE6Tm90ccj0OXrQdFVGlW3AVmQd8BHcaNtmmE5GW7Swi84T+4+qpU6VDIR426Vf1bG/831xFHfg9/J0aXPLdfqB1j1Z1S+RIda7tqH8skK6qPbeB5VxEUH8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235197; c=relaxed/simple; bh=bvqH2VGBWZ/am0ARAWuB70w1rkZaIjolzu7wdeNlU+g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fMD5Rq6wIF2H8cx0KMXoa3EwaGGzRbHRqlSvZ/If48+kcsI8dC6QlU8ze3bHOH4jpbhqX7eP5EauRusmX+nJ3Fh0GsZTrL0beyW0dtVjpVCSR1kbuZlJmBC6N87VTbJeBuk8UqlyFgfW4NDrGGSsadkqb+Ca3NwwX2zUIXWEfzg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=RlALjiGU; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RlALjiGU" Received: from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi [81.175.209.231]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 02320FD6; Mon, 20 May 2024 21:59:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716235182; bh=bvqH2VGBWZ/am0ARAWuB70w1rkZaIjolzu7wdeNlU+g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RlALjiGUW2i9f4kOygS6wA7SF/zkUtTOxtGbYR7aP+5NQY7cpihYSQfnNQhxDnt2i KgT9X2SKjtRHlEu1J3MTRC+nSaSKTbBjA29ROPfzDxT+ngqpsbPGZrCsLQCf2iPOEq SFBJMvbW85pgfCj5s4MT6D19Gvofk5vyzo9q9xDU= From: Laurent Pinchart To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org Cc: Alexandru Ardelean , Bartosz Golaszewski , Conor Dooley , Krzysztof Kozlowski , Lee Jones , Linus Walleij , Rob Herring , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= Subject: [PATCH 2/5] dt-bindings: Add bindings for the Analog Devices ADP5585 Date: Mon, 20 May 2024 22:59:38 +0300 Message-ID: <20240520195942.11582-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.44.1 In-Reply-To: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> References: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The ADP5585 is a 10/11 input/output port expander with a built in keypad matrix decoder, programmable logic, reset generator, and PWM generator. These bindings model the device as an MFD, and support the GPIO expander and PWM functions. These bindings support the GPIO and PWM functions. Signed-off-by: Laurent Pinchart --- I've limited the bindings to GPIO and PWM as I lack hardware to design, implement and test the rest of the features the chip supports. --- .../bindings/gpio/adi,adp5585-gpio.yaml | 36 ++++++ .../devicetree/bindings/mfd/adi,adp5585.yaml | 117 ++++++++++++++++++ .../bindings/pwm/adi,adp5585-pwm.yaml | 35 ++++++ MAINTAINERS | 7 ++ 4 files changed, 195 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/adi,adp5585-gpio.yaml create mode 100644 Documentation/devicetree/bindings/mfd/adi,adp5585.yaml create mode 100644 Documentation/devicetree/bindings/pwm/adi,adp5585-pwm.yaml diff --git a/Documentation/devicetree/bindings/gpio/adi,adp5585-gpio.yaml b/Documentation/devicetree/bindings/gpio/adi,adp5585-gpio.yaml new file mode 100644 index 000000000000..210e4d53e764 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/adi,adp5585-gpio.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/adi,adp5585-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADP5585 GPIO Expander + +maintainers: + - Laurent Pinchart + +description: | + The Analog Devices ADP5585 has up to 11 GPIOs represented by a "gpio" child + node of the parent MFD device. See + Documentation/devicetree/bindings/mfd/adi,adp5585.yaml for further details as + well as an example. + +properties: + compatible: + const: adi,adp5585-gpio + + gpio-controller: true + + '#gpio-cells': + const: 2 + + gpio-reserved-ranges: true + +required: + - compatible + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +... diff --git a/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml b/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml new file mode 100644 index 000000000000..217c038b2842 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/adi,adp5585.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/adi,adp5585.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADP5585 Keypad Decoder and I/O Expansion + +maintainers: + - Laurent Pinchart + +description: | + The ADP5585 is a 10/11 input/output port expander with a built in keypad + matrix decoder, programmable logic, reset generator, and PWM generator. + +properties: + compatible: + items: + - enum: + - adi,adp5585-00 # Default + - adi,adp5585-01 # 11 GPIOs + - adi,adp5585-02 # No pull-up resistors by default on special pins + - adi,adp5585-03 # Alternate I2C address + - adi,adp5585-04 # Pull-down resistors on all pins by default + - const: adi,adp5585 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + vdd-supply: true + + gpio: + $ref: /schemas/gpio/adi,adp5585-gpio.yaml + + pwm: + $ref: /schemas/pwm/adi,adp5585-pwm.yaml + +required: + - compatible + - reg + - gpio + - pwm + +allOf: + - if: + properties: + compatible: + contains: + const: adi,adp5585-01 + then: + properties: + gpio: + properties: + gpio-reserved-ranges: false + else: + properties: + gpio: + properties: + gpio-reserved-ranges: + items: + - const: 5 + - const: 1 + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + mfd@34 { + compatible = "adi,adp5585-00", "adi,adp5585"; + reg = <0x34>; + + gpio { + compatible = "adi,adp5585-gpio"; + gpio-controller; + #gpio-cells = <2>; + gpio-reserved-ranges = <5 1>; + }; + + pwm { + compatible = "adi,adp5585-pwm"; + #pwm-cells = <3>; + }; + }; + }; + + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + mfd@34 { + compatible = "adi,adp5585-01", "adi,adp5585"; + reg = <0x34>; + + vdd-supply = <®_3v3>; + + gpio { + compatible = "adi,adp5585-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + pwm { + compatible = "adi,adp5585-pwm"; + #pwm-cells = <3>; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/pwm/adi,adp5585-pwm.yaml b/Documentation/devicetree/bindings/pwm/adi,adp5585-pwm.yaml new file mode 100644 index 000000000000..351a9d5da566 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/adi,adp5585-pwm.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/adi,adp5585-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADP5585 PWM Generator + +maintainers: + - Laurent Pinchart + +description: | + The Analog Devices ADP5585 generates a PWM output with configurable frequency + and duty cycle represented by a "pwm" child node of the parent MFD device. + See Documentation/devicetree/bindings/mfd/adi,adp5585.yaml for further + details as well as an example. + +allOf: + - $ref: /schemas/pwm/pwm.yaml# + +properties: + compatible: + enum: + - adi,adp5585-pwm + + "#pwm-cells": + const: 3 + +required: + - compatible + - "#pwm-cells" + +additionalProperties: false + +... diff --git a/MAINTAINERS b/MAINTAINERS index 28e20975c26f..afecdb82e783 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -497,6 +497,13 @@ F: drivers/leds/leds-adp5520.c F: drivers/mfd/adp5520.c F: drivers/video/backlight/adp5520_bl.c +ADP5585 GPIO EXPANDER, PWM AND KEYPAD CONTROLLER DRIVER +M: Laurent Pinchart +L: linux-gpio@vger.kernel.org +L: linux-pwm@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml + ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587) M: Michael Hennerich S: Supported From patchwork Mon May 20 19:59:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 797916 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 6C5BF13958E; Mon, 20 May 2024 19:59:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235198; cv=none; b=I4ksI6bh2zmYylLiicNDRtUlgUkQ49d0BhqRHadR+6a7G2QM3zg91TfR1VIcFZ0zEUpIvh5gt0wk8ZQ++cUYjSL8krmhY7WkEeZY0Yr6jTDxT9GG5aaKVKGDVQAKbImNqtw1Woc3i5h8fy+RCRk2NvXmrBjH1FRII9LaqCSlJ6w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235198; c=relaxed/simple; bh=QUKwoWTCAuCdzuYMVxMp/t5dZbwNUOmSsqnqRz50L74=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lwTKc+Ff6taHM7d00wooIsrmfYikS98VUkAQfcka/aCkcguNUMlq1KnIIHa1QELyPX+5OWtSBq4r6ScX+XhgG2VMuB7zTOZSf0EWk5+u9Dvot4SQnF0FU8fKg9pvjEDVl10GAp2AVmkEnGdHwt7Ff8biFSdmkURhaismu/4OmR0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=LQTgoTWh; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="LQTgoTWh" Received: from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi [81.175.209.231]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 51168114C; Mon, 20 May 2024 21:59:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716235183; bh=QUKwoWTCAuCdzuYMVxMp/t5dZbwNUOmSsqnqRz50L74=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LQTgoTWhwwfvjcxm4kE1BtahmKFBQz2nzYerO0dN1Y6mwXSdb2a4JYUwO8ndbP+Pb yx+qzUwv/n96hhtPhNxuvlUFeH1GRjjZ9+eYGOi67uBp2Onrr9z9akP17GxgJYZpe1 oQrac7IIndJcSzdeczObtbMLey6U3jEdlklyTXn0= From: Laurent Pinchart To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org Cc: Alexandru Ardelean , Bartosz Golaszewski , Conor Dooley , Krzysztof Kozlowski , Lee Jones , Linus Walleij , Rob Herring , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Haibo Chen Subject: [PATCH 3/5] mfd: adp5585: Add Analog Devices ADP5585 core support Date: Mon, 20 May 2024 22:59:39 +0300 Message-ID: <20240520195942.11582-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.44.1 In-Reply-To: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> References: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Haibo Chen The ADP5585 is a 10/11 input/output port expander with a built in keypad matrix decoder, programmable logic, reset generator, and PWM generator. This driver supports the chip by modelling it as an MFD device, with two child devices for the GPIO and PWM functions. The driver is derived from an initial implementation from NXP, available in commit 8059835bee19 ("MLK-25917-1 mfd: adp5585: add ADI adp5585 core support") in their BSP kernel tree. It has been extensively rewritten. Signed-off-by: Haibo Chen Signed-off-by: Laurent Pinchart --- Changes compared to the NXP original version: - Add MAINTAINERS entry - Fix compatible strings for child devices - Fix header guards - Use lowercase hex constants - White space fixes - Use module_i2c_driver() - Switch to regmap - Drop I2C device ID table - Drop ADP5585_REG_MASK - Support R5 GPIO pin - Drop dev field from adp5585_dev structure - Check device ID at probe time - Fix register field names - Update copyright - Update license to GPL-2.0-only - Implement suspend/resume --- MAINTAINERS | 2 + drivers/mfd/Kconfig | 11 ++ drivers/mfd/Makefile | 1 + drivers/mfd/adp5585.c | 207 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/adp5585.h | 120 +++++++++++++++++++++ 5 files changed, 341 insertions(+) create mode 100644 drivers/mfd/adp5585.c create mode 100644 include/linux/mfd/adp5585.h diff --git a/MAINTAINERS b/MAINTAINERS index afecdb82e783..7150f091b69b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -503,6 +503,8 @@ L: linux-gpio@vger.kernel.org L: linux-pwm@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml +F: drivers/mfd/adp5585.c +F: include/linux/mfd/adp5585.h ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587) M: Michael Hennerich diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 4b023ee229cf..3423eac0877a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -20,6 +20,17 @@ config MFD_CS5535 This is the core driver for CS5535/CS5536 MFD functions. This is necessary for using the board's GPIO and MFGPT functionality. +config MFD_ADP5585 + tristate "Analog Devices ADP5585 MFD driver" + select MFD_CORE + select REGMAP_I2C + depends on I2C && OF + help + Say yes here to add support for the Analog Devices ADP5585 GPIO + expander, PWM and keypad controller. This includes the I2C driver and + the core APIs _only_, you have to select individual components like + the GPIO and PWM functions under the corresponding menus. + config MFD_ALTERA_A10SR bool "Altera Arria10 DevKit System Resource chip" depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index c66f07edcd0e..37f36a019a68 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -188,6 +188,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o +obj-$(CONFIG_MFD_ADP5585) += adp5585.o obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o obj-$(CONFIG_MFD_INTEL_QUARK_I2C_GPIO) += intel_quark_i2c_gpio.o obj-$(CONFIG_LPC_SCH) += lpc_sch.o diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c new file mode 100644 index 000000000000..75957f9b67c2 --- /dev/null +++ b/drivers/mfd/adp5585.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADP5585 I/O expander, PWM controller and keypad controller + * + * Copyright 2022 NXP + * Copyright 2024 Ideas on Board Oy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell adp5585_devs[] = { + { + .name = "adp5585-gpio", + .of_compatible = "adi,adp5585-gpio", + }, + { + .name = "adp5585-pwm", + .of_compatible = "adi,adp5585-pwm", + }, +}; + +static const struct regmap_range adp5585_volatile_ranges[] = { + regmap_reg_range(ADP5585_ID, ADP5585_GPI_STATUS_B), +}; + +static const struct regmap_access_table adp5585_volatile_regs = { + .yes_ranges = adp5585_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(adp5585_volatile_ranges), +}; + +static const u8 adp5585_regmap_defaults_00[ADP5585_MAX_REG + 1] = { + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 adp5585_regmap_defaults_02[ADP5585_MAX_REG + 1] = { + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, + /* 0x18 */ 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 adp5585_regmap_defaults_04[ADP5585_MAX_REG + 1] = { + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + /* 0x18 */ 0x05, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +enum adp5585_regmap_type { + ADP5585_REGMAP_00, + ADP5585_REGMAP_02, + ADP5585_REGMAP_04, +}; + +static const struct regmap_config adp5585_regmap_configs[] = { + [ADP5585_REGMAP_00] = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADP5585_MAX_REG, + .volatile_table = &adp5585_volatile_regs, + .cache_type = REGCACHE_MAPLE, + .reg_defaults_raw = adp5585_regmap_defaults_00, + .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_00), + }, + [ADP5585_REGMAP_02] = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADP5585_MAX_REG, + .volatile_table = &adp5585_volatile_regs, + .cache_type = REGCACHE_MAPLE, + .reg_defaults_raw = adp5585_regmap_defaults_02, + .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_02), + }, + [ADP5585_REGMAP_04] = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADP5585_MAX_REG, + .volatile_table = &adp5585_volatile_regs, + .cache_type = REGCACHE_MAPLE, + .reg_defaults_raw = adp5585_regmap_defaults_04, + .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_04), + }, +}; + + +static int adp5585_i2c_probe(struct i2c_client *i2c) +{ + const struct regmap_config *regmap_config; + struct adp5585_dev *adp5585; + unsigned int id; + int ret; + + adp5585 = devm_kzalloc(&i2c->dev, sizeof(struct adp5585_dev), + GFP_KERNEL); + if (adp5585 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, adp5585); + + regmap_config = of_device_get_match_data(&i2c->dev); + adp5585->regmap = devm_regmap_init_i2c(i2c, regmap_config); + if (IS_ERR(adp5585->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(adp5585->regmap), + "Failed to initialize register map\n"); + + /* Verify the device ID. */ + ret = regmap_read(adp5585->regmap, ADP5585_ID, &id); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to read device ID\n"); + + if (ADP5585_MAN_ID(id) != ADP5585_MAN_ID_VALUE) + return dev_err_probe(&i2c->dev, -ENODEV, + "Invalid device ID 0x%02x\n", id); + + dev_dbg(&i2c->dev, "device ID 0x%02x\n", id); + + /* Add MFD devices. */ + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, + adp5585_devs, ARRAY_SIZE(adp5585_devs), + NULL, 0, NULL); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to add MFD devices\n"); + + return 0; +} + +static int adp5585_suspend(struct device *dev) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(dev); + + regcache_cache_only(adp5585->regmap, true); + + return 0; +} + +static int adp5585_resume(struct device *dev) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(dev); + + regcache_cache_only(adp5585->regmap, false); + regcache_mark_dirty(adp5585->regmap); + + return regcache_sync(adp5585->regmap); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume); + +static const struct of_device_id adp5585_of_match[] = { + { + .compatible = "adi,adp5585-00", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + }, { + .compatible = "adi,adp5585-01", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + }, { + .compatible = "adi,adp5585-02", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_02], + }, { + .compatible = "adi,adp5585-03", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + }, { + .compatible = "adi,adp5585-04", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_04], + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, adp5585_of_match); + +static struct i2c_driver adp5585_i2c_driver = { + .driver = { + .name = "adp5585", + .of_match_table = of_match_ptr(adp5585_of_match), + .pm = pm_sleep_ptr(&adp5585_pm), + }, + .probe = adp5585_i2c_probe, +}; +module_i2c_driver(adp5585_i2c_driver); + +MODULE_DESCRIPTION("ADP5585 core driver"); +MODULE_AUTHOR("Haibo Chen "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/adp5585.h b/include/linux/mfd/adp5585.h new file mode 100644 index 000000000000..3f178f30fac6 --- /dev/null +++ b/include/linux/mfd/adp5585.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Analog Devices ADP5585 I/O expander, PWM controller and keypad controller + * + * Copyright 2022 NXP + * Copyright 2024 Ideas on Board Oy + */ + +#ifndef __LINUX_MFD_ADP5585_H_ +#define __LINUX_MFD_ADP5585_H_ + +#include + +#define ADP5585_ID 0x00 +#define ADP5585_MAN_ID(v) (((v) & 0xf0) >> 4) +#define ADP5585_MAN_ID_VALUE 0x02 +#define ADP5585_INT_STATUS 0x01 +#define ADP5585_STATUS 0x02 +#define ADP5585_FIFO_1 0x03 +#define ADP5585_FIFO_2 0x04 +#define ADP5585_FIFO_3 0x05 +#define ADP5585_FIFO_4 0x06 +#define ADP5585_FIFO_5 0x07 +#define ADP5585_FIFO_6 0x08 +#define ADP5585_FIFO_7 0x09 +#define ADP5585_FIFO_8 0x0a +#define ADP5585_FIFO_9 0x0b +#define ADP5585_FIFO_10 0x0c +#define ADP5585_FIFO_11 0x0d +#define ADP5585_FIFO_12 0x0e +#define ADP5585_FIFO_13 0x0f +#define ADP5585_FIFO_14 0x10 +#define ADP5585_FIFO_15 0x11 +#define ADP5585_FIFO_16 0x12 +#define ADP5585_GPI_INT_STAT_A 0x13 +#define ADP5585_GPI_INT_STAT_B 0x14 +#define ADP5585_GPI_STATUS_A 0x15 +#define ADP5585_GPI_STATUS_B 0x16 +#define ADP5585_RPULL_CONFIG_A 0x17 +#define ADP5585_RPULL_CONFIG_B 0x18 +#define ADP5585_RPULL_CONFIG_C 0x19 +#define ADP5585_RPULL_CONFIG_D 0x1a +#define ADP5585_Rx_PULL_CFG(n, v) ((v) << ((n) * 2)) +#define ADP5585_Rx_PULL_CFG_PU_300K (0) +#define ADP5585_Rx_PULL_CFG_PD_300K (1) +#define ADP5585_Rx_PULL_CFG_PU_100K (2) +#define ADP5585_Rx_PULL_CFG_DISABLE (3) +#define ADP5585_Rx_PULL_CFG_MASK (3) +#define ADP5585_GPI_INT_LEVEL_A 0x1b +#define ADP5585_GPI_INT_LEVEL_B 0x1c +#define ADP5585_GPI_EVENT_EN_A 0x1d +#define ADP5585_GPI_EVENT_EN_B 0x1e +#define ADP5585_GPI_INTERRUPT_EN_A 0x1f +#define ADP5585_GPI_INTERRUPT_EN_B 0x20 +#define ADP5585_DEBOUNCE_DIS_A 0x21 +#define ADP5585_DEBOUNCE_DIS_B 0x22 +#define ADP5585_GPO_DATA_OUT_A 0x23 +#define ADP5585_GPO_DATA_OUT_B 0x24 +#define ADP5585_GPO_OUT_MODE_A 0x25 +#define ADP5585_GPO_OUT_MODE_B 0x26 +#define ADP5585_GPIO_DIRECTION_A 0x27 +#define ADP5585_GPIO_DIRECTION_B 0x28 +#define ADP5585_RESET1_EVENT_A 0x29 +#define ADP5585_RESET1_EVENT_B 0x2a +#define ADP5585_RESET1_EVENT_C 0x2b +#define ADP5585_RESET2_EVENT_A 0x2c +#define ADP5585_RESET2_EVENT_B 0x2d +#define ADP5585_RESET_CFG 0x2e +#define ADP5585_PWM_OFFT_LOW 0x2f +#define ADP5585_PWM_OFFT_HIGH 0x30 +#define ADP5585_PWM_ONT_LOW 0x31 +#define ADP5585_PWM_ONT_HIGH 0x32 +#define ADP5585_PWM_CFG 0x33 +#define ADP5585_PWM_IN_AND BIT(2) +#define ADP5585_PWM_MODE BIT(1) +#define ADP5585_PWM_EN BIT(0) +#define ADP5585_LOGIC_CFG 0x34 +#define ADP5585_LOGIC_FF_CFG 0x35 +#define ADP5585_LOGIC_INT_EVENT_EN 0x36 +#define ADP5585_POLL_PTIME_CFG 0x37 +#define ADP5585_PIN_CONFIG_A 0x38 +#define ADP5585_PIN_CONFIG_B 0x39 +#define ADP5585_PIN_CONFIG_C 0x3a +#define ADP5585_PULL_SELECT BIT(7) +#define ADP5585_C4_EXTEND_CFG_GPIO11 (0U << 6) +#define ADP5585_C4_EXTEND_CFG_RESET2 (1U << 6) +#define ADP5585_C4_EXTEND_CFG_MASK (1U << 6) +#define ADP5585_R4_EXTEND_CFG_GPIO5 (0U << 5) +#define ADP5585_R4_EXTEND_CFG_RESET1 (1U << 5) +#define ADP5585_R4_EXTEND_CFG_MASK (1U << 5) +#define ADP5585_R3_EXTEND_CFG_GPIO4 (0U << 2) +#define ADP5585_R3_EXTEND_CFG_LC (1U << 2) +#define ADP5585_R3_EXTEND_CFG_PWM_OUT (2U << 2) +#define ADP5585_R3_EXTEND_CFG_MASK (3U << 2) +#define ADP5585_R0_EXTEND_CFG_GPIO1 (0U << 0) +#define ADP5585_R0_EXTEND_CFG_LY (1U << 0) +#define ADP5585_R0_EXTEND_CFG_MASK (1U << 0) +#define ADP5585_GENERAL_CFG 0x3b +#define ADP5585_OSC_EN BIT(7) +#define ADP5585_OSC_FREQ_50KHZ (0U << 5) +#define ADP5585_OSC_FREQ_100KHZ (1U << 5) +#define ADP5585_OSC_FREQ_200KHZ (2U << 5) +#define ADP5585_OSC_FREQ_500KHZ (3U << 5) +#define ADP5585_OSC_FREQ_MASK (3U << 5) +#define ADP5585_INT_CFG BIT(1) +#define ADP5585_RST_CFG BIT(0) +#define ADP5585_INT_EN 0x3c + +#define ADP5585_MAX_REG ADP5585_INT_EN + +#define ADP5585_BANK(n) ((n) >= 6 ? 1 : 0) +#define ADP5585_BIT(n) ((n) >= 6 ? BIT((n) - 6) : BIT(n)) + +struct regmap; + +struct adp5585_dev { + struct regmap *regmap; +}; + +#endif From patchwork Mon May 20 19:59:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 797915 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 CE836139D1D; Mon, 20 May 2024 19:59:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235201; cv=none; b=IqA0L6NicolH3VurXGGXVpxUi5CRJNS7L6TuLAUyThckvDZwXxZb2aU7awfzJn6uuTckZbfl7bttywqnlwwam+5d/Gu1ITzxYfu2XQTr504tNmCJ6e8hkfvekNGiMHHwH+cmYvlMZwGfP0QJsJdDeAMlVaM5XYkpecKAQXFEDXs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235201; c=relaxed/simple; bh=82jsgl19cMYoCxoET5IPGfygxkn3NkEukJF9ABMZrPA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QkvsV084LW4WMrebYWRQ2394HHccLVUr4QlD+6VUp6hpxRb9IEiUjFoL73nBPRvufpJNnb1wuYNDrqKi0c7fpHcfoVmQcQxo5ZaI2Dl25lO14NQfowk5yK1mX5KdJabjRu9wVhpOEKiBf2mb0mZtv6XlrE4+90MsWTFGzi9j7ck= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=Zl3xKYZ7; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Zl3xKYZ7" Received: from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi [81.175.209.231]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9A363D49; Mon, 20 May 2024 21:59:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716235184; bh=82jsgl19cMYoCxoET5IPGfygxkn3NkEukJF9ABMZrPA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Zl3xKYZ7UdntKDMBpE3gCa8eVOczo5FVCpRMBTD97s80qyuOoVuJ4nwa0vfUONnFl BikhoiW3qk2LlUghBwLrT7FIIBp2JzUopGWZUm9tc3Jpy/gIy1kGvBll16p7DD5R+h M8WXiJ86ik+5LMYAa+0s4v2y2PFH/4b0bhkHXdCY= From: Laurent Pinchart To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org Cc: Alexandru Ardelean , Bartosz Golaszewski , Conor Dooley , Krzysztof Kozlowski , Lee Jones , Linus Walleij , Rob Herring , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Haibo Chen Subject: [PATCH 4/5] gpio: adp5585: Add Analog Devices ADP5585 support Date: Mon, 20 May 2024 22:59:40 +0300 Message-ID: <20240520195942.11582-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.44.1 In-Reply-To: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> References: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Haibo Chen The ADP5585 is a 10/11 input/output port expander with a built in keypad matrix decoder, programmable logic, reset generator, and PWM generator. This driver supports the GPIO function using the platform device registered by the core MFD driver. The driver is derived from an initial implementation from NXP, available in commit 451f61b46b76 ("MLK-25917-2 gpio: adp5585-gpio: add adp5585-gpio support") in their BSP kernel tree. It has been extensively rewritten. Signed-off-by: Haibo Chen Signed-off-by: Laurent Pinchart Reviewed-by: Linus Walleij --- Changes compared to the NXP original version - Add MAINTAINERS entry - Add prefix to compatible string - Switch to regmap - White space fixes - Use sizeof(*variable) - Initialize variables at declaration time - Use mutex scope guards - Cleanup header includes - Support R5 GPIO pin - Reorder functions - Add bias support - Return real pin value from .get() - Add debounce support - Add drive mode support - Destroy mutex on remove - Update copyright - Update license to GPL-2.0-only --- MAINTAINERS | 1 + drivers/gpio/Kconfig | 7 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-adp5585.c | 232 ++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 drivers/gpio/gpio-adp5585.c diff --git a/MAINTAINERS b/MAINTAINERS index 7150f091b69b..5689fec270ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -503,6 +503,7 @@ L: linux-gpio@vger.kernel.org L: linux-pwm@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml +F: drivers/gpio/gpio-adp5585.c F: drivers/mfd/adp5585.c F: include/linux/mfd/adp5585.h diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b50d0b470849..79d004e31a47 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1206,6 +1206,13 @@ config GPIO_ADP5520 This option enables support for on-chip GPIO found on Analog Devices ADP5520 PMICs. +config GPIO_ADP5585 + tristate "GPIO Support for ADP5585" + depends on MFD_ADP5585 + help + This option enables support for the GPIO function found in the Analog + Devices ADP5585. + config GPIO_ALTERA_A10SR tristate "Altera Arria10 System Resource GPIO" depends on MFD_ALTERA_A10SR diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fdd28c58d890..b44b6bc3a74f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o +obj-$(CONFIG_GPIO_ADP5585) += gpio-adp5585.o obj-$(CONFIG_GPIO_AGGREGATOR) += gpio-aggregator.o obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o diff --git a/drivers/gpio/gpio-adp5585.c b/drivers/gpio/gpio-adp5585.c new file mode 100644 index 000000000000..30e538f8d1ac --- /dev/null +++ b/drivers/gpio/gpio-adp5585.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADP5585 GPIO driver + * + * Copyright 2022 NXP + * Copyright 2024 Ideas on Board Oy + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADP5585_GPIO_MAX 11 + +struct adp5585_gpio_dev { + struct gpio_chip gpio_chip; + struct regmap *regmap; + struct mutex lock; +}; + +static int adp5585_gpio_direction_input(struct gpio_chip *chip, unsigned int off) +{ + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); + unsigned int bank = ADP5585_BANK(off); + unsigned int bit = ADP5585_BIT(off); + + guard(mutex)(&adp5585_gpio->lock); + + return regmap_update_bits(adp5585_gpio->regmap, + ADP5585_GPIO_DIRECTION_A + bank, + bit, 0); +} + +static int adp5585_gpio_direction_output(struct gpio_chip *chip, unsigned int off, int val) +{ + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); + unsigned int bank = ADP5585_BANK(off); + unsigned int bit = ADP5585_BIT(off); + int ret; + + guard(mutex)(&adp5585_gpio->lock); + + ret = regmap_update_bits(adp5585_gpio->regmap, + ADP5585_GPO_DATA_OUT_A + bank, bit, + val ? bit : 0); + if (ret) + return ret; + + return regmap_update_bits(adp5585_gpio->regmap, + ADP5585_GPIO_DIRECTION_A + bank, + bit, bit); +} + +static int adp5585_gpio_get_value(struct gpio_chip *chip, unsigned int off) +{ + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); + unsigned int bank = ADP5585_BANK(off); + unsigned int bit = ADP5585_BIT(off); + unsigned int val; + + guard(mutex)(&adp5585_gpio->lock); + + regmap_read(adp5585_gpio->regmap, ADP5585_GPI_STATUS_A + bank, &val); + + return !!(val & bit); +} + +static void adp5585_gpio_set_value(struct gpio_chip *chip, unsigned int off, int val) +{ + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); + unsigned int bank = ADP5585_BANK(off); + unsigned int bit = ADP5585_BIT(off); + + guard(mutex)(&adp5585_gpio->lock); + + regmap_update_bits(adp5585_gpio->regmap, ADP5585_GPO_DATA_OUT_A + bank, + bit, val ? bit : 0); +} + +static int adp5585_gpio_set_bias(struct adp5585_gpio_dev *adp5585_gpio, + unsigned int off, unsigned int bias) +{ + unsigned int bit, reg, mask, val; + + /* + * The bias configuration fields are 2 bits wide and laid down in + * consecutive registers ADP5585_RPULL_CONFIG_*, with a hole of 4 bits + * after R5. + */ + bit = off * 2 + (off > 5 ? 4 : 0); + reg = ADP5585_RPULL_CONFIG_A + bit / 8; + mask = ADP5585_Rx_PULL_CFG(bit % 8, ADP5585_Rx_PULL_CFG_MASK); + val = ADP5585_Rx_PULL_CFG(bit % 8, bias); + + guard(mutex)(&adp5585_gpio->lock); + + return regmap_update_bits(adp5585_gpio->regmap, reg, mask, val); +} + +static int adp5585_gpio_set_drive(struct adp5585_gpio_dev *adp5585_gpio, + unsigned int off, enum pin_config_param drive) +{ + unsigned int bank = ADP5585_BANK(off); + unsigned int bit = ADP5585_BIT(off); + + guard(mutex)(&adp5585_gpio->lock); + + return regmap_update_bits(adp5585_gpio->regmap, + ADP5585_GPO_OUT_MODE_A + bank, bit, + drive == PIN_CONFIG_DRIVE_OPEN_DRAIN ? 1 : 0); +} + +static int adp5585_gpio_set_debounce(struct adp5585_gpio_dev *adp5585_gpio, + unsigned int off, unsigned int debounce) +{ + unsigned int bank = ADP5585_BANK(off); + unsigned int bit = ADP5585_BIT(off); + + guard(mutex)(&adp5585_gpio->lock); + + return regmap_update_bits(adp5585_gpio->regmap, + ADP5585_DEBOUNCE_DIS_A + bank, bit, + debounce ? 0 : 1); +} + +static int adp5585_gpio_set_config(struct gpio_chip *chip, unsigned int off, + unsigned long config) +{ + struct adp5585_gpio_dev *adp5585_gpio = gpiochip_get_data(chip); + enum pin_config_param param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + return adp5585_gpio_set_bias(adp5585_gpio, off, + ADP5585_Rx_PULL_CFG_DISABLE); + + case PIN_CONFIG_BIAS_PULL_DOWN: + return adp5585_gpio_set_bias(adp5585_gpio, off, arg ? + ADP5585_Rx_PULL_CFG_PD_300K : + ADP5585_Rx_PULL_CFG_DISABLE); + + case PIN_CONFIG_BIAS_PULL_UP: + return adp5585_gpio_set_bias(adp5585_gpio, off, arg ? + ADP5585_Rx_PULL_CFG_PU_300K : + ADP5585_Rx_PULL_CFG_DISABLE); + + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + case PIN_CONFIG_DRIVE_PUSH_PULL: + return adp5585_gpio_set_drive(adp5585_gpio, off, param); + + case PIN_CONFIG_INPUT_DEBOUNCE: + return adp5585_gpio_set_debounce(adp5585_gpio, off, arg); + + default: + return -ENOTSUPP; + }; +} + +static int adp5585_gpio_probe(struct platform_device *pdev) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent); + struct adp5585_gpio_dev *adp5585_gpio; + struct device *dev = &pdev->dev; + struct gpio_chip *gc; + int ret; + + adp5585_gpio = devm_kzalloc(&pdev->dev, sizeof(*adp5585_gpio), GFP_KERNEL); + if (!adp5585_gpio) + return -ENOMEM; + + platform_set_drvdata(pdev, adp5585_gpio); + + adp5585_gpio->regmap = adp5585->regmap; + + mutex_init(&adp5585_gpio->lock); + + gc = &adp5585_gpio->gpio_chip; + gc->parent = dev; + gc->direction_input = adp5585_gpio_direction_input; + gc->direction_output = adp5585_gpio_direction_output; + gc->get = adp5585_gpio_get_value; + gc->set = adp5585_gpio_set_value; + gc->set_config = adp5585_gpio_set_config; + gc->can_sleep = true; + + gc->base = -1; + gc->ngpio = ADP5585_GPIO_MAX; + gc->label = pdev->name; + gc->owner = THIS_MODULE; + + ret = devm_gpiochip_add_data(&pdev->dev, &adp5585_gpio->gpio_chip, + adp5585_gpio); + if (ret) { + mutex_destroy(&adp5585_gpio->lock); + return dev_err_probe(&pdev->dev, ret, "failed to add GPIO chip\n"); + } + + return 0; +} + +static void adp5585_gpio_remove(struct platform_device *pdev) +{ + struct adp5585_gpio_dev *adp5585_gpio = platform_get_drvdata(pdev); + + mutex_destroy(&adp5585_gpio->lock); +} + +static const struct of_device_id adp5585_of_match[] = { + { .compatible = "adi,adp5585-gpio" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, adp5585_of_match); + +static struct platform_driver adp5585_gpio_driver = { + .driver = { + .name = "adp5585-gpio", + .of_match_table = adp5585_of_match, + }, + .probe = adp5585_gpio_probe, + .remove_new = adp5585_gpio_remove, +}; +module_platform_driver(adp5585_gpio_driver); + +MODULE_AUTHOR("Haibo Chen "); +MODULE_DESCRIPTION("GPIO ADP5585 Driver"); +MODULE_LICENSE("GPL"); From patchwork Mon May 20 19:59:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 798048 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) (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 C6643139D1C; Mon, 20 May 2024 19:59:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.167.242.64 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235201; cv=none; b=HZ2GubaxFdCD3x08mRecILCHL/UwsgGBPY5YjnseECONFfcWmjABeUdjaHkjOM0t7FiJULIxqVleFIrycBxcBVWBb6TWsvKzN3LSZAOC6yOjzCojVAa0iKpiUJfSntz8ui5d1zKsu8R22sLDbNMBZhk2HusmbWCZM6HHLerkjrU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716235201; c=relaxed/simple; bh=edOZnoLpGGwMfNSHAt6rfmjOeaPRifmFW19KtEa3l2s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SgqjLKDg3Oh33ME2sT8iGjToOvSONf4yQEBkr8nYtoHEbUmhT+iq67dfF4qLO1Kq1AHwWSQpkWaEizZXI721cQ7ZQrICA/exJw0lRi2l+uPW+V+C/bVFp9xKDmG4euB3GPzl9AtCZq65rD5kGXkodD86cWeymx0hOZAqcXPuA44= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com; spf=pass smtp.mailfrom=ideasonboard.com; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b=n6aDhvhl; arc=none smtp.client-ip=213.167.242.64 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ideasonboard.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="n6aDhvhl" Received: from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi [81.175.209.231]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E817DEBB; Mon, 20 May 2024 21:59:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716235186; bh=edOZnoLpGGwMfNSHAt6rfmjOeaPRifmFW19KtEa3l2s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=n6aDhvhlmt7JYn0a9FIj6vD5A7zWGpFD4SWGYLOgRZj9a+Ov8L9ApCHogSNmFfiMq ONF/X+4aUUOcUcx7h56g3kxcrJQX1CoopXWPub5wtHufsDGLZSmeF8caHKs1NbF0zM 0r5XAmfqfKlHd67EC8jL2ds0R4Yq93V5VkJWh44k= From: Laurent Pinchart To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-gpio@vger.kernel.org, linux-pwm@vger.kernel.org Cc: Alexandru Ardelean , Bartosz Golaszewski , Conor Dooley , Krzysztof Kozlowski , Lee Jones , Linus Walleij , Rob Herring , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Clark Wang Subject: [PATCH 5/5] pwm: adp5585: Add Analog Devices ADP5585 support Date: Mon, 20 May 2024 22:59:41 +0300 Message-ID: <20240520195942.11582-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.44.1 In-Reply-To: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> References: <20240520195942.11582-1-laurent.pinchart@ideasonboard.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Clark Wang The ADP5585 is a 10/11 input/output port expander with a built in keypad matrix decoder, programmable logic, reset generator, and PWM generator. This driver supports the PWM function using the platform device registered by the core MFD driver. The driver is derived from an initial implementation from NXP, available in commit 113113742208 ("MLK-25922-1 pwm: adp5585: add adp5585 PWM support") in their BSP kernel tree. It has been extensively rewritten. Signed-off-by: Clark Wang Signed-off-by: Laurent Pinchart --- Changes compared to the NXP original version - Add MAINTAINERS entry - Drop pwm_ops.owner - Fix compilation - Add prefix to compatible string - Switch to regmap - Use devm_pwmchip_add() - Cleanup header includes - White space fixes - Drop ADP5585_REG_MASK - Fix register field names - Use mutex scope guards - Clear OSC_EN when freeing PWM - Reorder functions - Clear PWM_IN_AND and PWM_MODE bits - Support inverted polarity - Clean up on/off computations - Fix duty cycle computation in .get_state() - Destroy mutex on remove - Update copyright - Update license to GPL-2.0-only --- MAINTAINERS | 1 + drivers/pwm/Kconfig | 7 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-adp5585.c | 230 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 239 insertions(+) create mode 100644 drivers/pwm/pwm-adp5585.c diff --git a/MAINTAINERS b/MAINTAINERS index 5689fec270ef..280f97129598 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -505,6 +505,7 @@ S: Maintained F: Documentation/devicetree/bindings/*/adi,adp5585*.yaml F: drivers/gpio/gpio-adp5585.c F: drivers/mfd/adp5585.c +F: drivers/pwm/pwm-adp5585.c F: include/linux/mfd/adp5585.h ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 4b956d661755..2393a50b3781 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -51,6 +51,13 @@ config PWM_AB8500 To compile this driver as a module, choose M here: the module will be called pwm-ab8500. +config PWM_ADP5585 + tristate "ADP5585 PWM support" + depends on MFD_ADP5585 + help + This option enables support for the PWM function found in the Analog + Devices ADP5585. + config PWM_APPLE tristate "Apple SoC PWM support" depends on ARCH_APPLE || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c5ec9e168ee7..100ac66b5f40 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_SYSFS) += sysfs.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o +obj-$(CONFIG_PWM_ADP5585) += pwm-adp5585.o obj-$(CONFIG_PWM_APPLE) += pwm-apple.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o diff --git a/drivers/pwm/pwm-adp5585.c b/drivers/pwm/pwm-adp5585.c new file mode 100644 index 000000000000..709713d8f47a --- /dev/null +++ b/drivers/pwm/pwm-adp5585.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADP5585 PWM driver + * + * Copyright 2022 NXP + * Copyright 2024 Ideas on Board Oy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADP5585_PWM_CHAN_NUM 1 + +#define ADP5585_PWM_OSC_FREQ_HZ 1000000U +#define ADP5585_PWM_MIN_PERIOD_NS (2ULL * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) +#define ADP5585_PWM_MAX_PERIOD_NS (2ULL * 0xffff * NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ) + +struct adp5585_pwm_chip { + struct pwm_chip chip; + struct regmap *regmap; + struct mutex lock; + u8 pin_config_val; +}; + +static inline struct adp5585_pwm_chip * +to_adp5585_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct adp5585_pwm_chip, chip); +} + +static int pwm_adp5585_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct adp5585_pwm_chip *adp5585_pwm = to_adp5585_pwm_chip(chip); + unsigned int val; + int ret; + + guard(mutex)(&adp5585_pwm->lock); + + ret = regmap_read(adp5585_pwm->regmap, ADP5585_PIN_CONFIG_C, &val); + if (ret) + return ret; + + adp5585_pwm->pin_config_val = val; + + ret = regmap_update_bits(adp5585_pwm->regmap, ADP5585_PIN_CONFIG_C, + ADP5585_R3_EXTEND_CFG_MASK, + ADP5585_R3_EXTEND_CFG_PWM_OUT); + if (ret) + return ret; + + ret = regmap_update_bits(adp5585_pwm->regmap, ADP5585_GENERAL_CFG, + ADP5585_OSC_EN, ADP5585_OSC_EN); + if (ret) + return ret; + + return 0; +} + +static void pwm_adp5585_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct adp5585_pwm_chip *adp5585_pwm = to_adp5585_pwm_chip(chip); + + guard(mutex)(&adp5585_pwm->lock); + + regmap_update_bits(adp5585_pwm->regmap, ADP5585_PIN_CONFIG_C, + ADP5585_R3_EXTEND_CFG_MASK, + adp5585_pwm->pin_config_val); + regmap_update_bits(adp5585_pwm->regmap, ADP5585_GENERAL_CFG, + ADP5585_OSC_EN, 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; + int ret; + + if (!state->enabled) { + guard(mutex)(&adp5585_pwm->lock); + + return regmap_update_bits(adp5585_pwm->regmap, ADP5585_PWM_CFG, + ADP5585_PWM_EN, 0); + } + + if (state->period < ADP5585_PWM_MIN_PERIOD_NS || + state->period > ADP5585_PWM_MAX_PERIOD_NS) + return -EINVAL; + + /* + * Compute the on and off time. As the internal oscillator frequency is + * 1MHz, the calculation can be simplified without loss of precision. + */ + on = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, + NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ); + off = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, + NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ); + + if (state->polarity == PWM_POLARITY_INVERSED) + swap(on, off); + + guard(mutex)(&adp5585_pwm->lock); + + ret = regmap_write(adp5585_pwm->regmap, ADP5585_PWM_OFFT_LOW, + off & 0xff); + if (ret) + return ret; + ret = regmap_write(adp5585_pwm->regmap, ADP5585_PWM_OFFT_HIGH, + (off >> 8) & 0xff); + if (ret) + return ret; + ret = regmap_write(adp5585_pwm->regmap, ADP5585_PWM_ONT_LOW, + on & 0xff); + if (ret) + return ret; + ret = regmap_write(adp5585_pwm->regmap, ADP5585_PWM_ONT_HIGH, + (on >> 8) & 0xff); + if (ret) + return ret; + + /* Enable PWM in continuous mode and no external AND'ing. */ + ret = regmap_update_bits(adp5585_pwm->regmap, ADP5585_PWM_CFG, + ADP5585_PWM_IN_AND | ADP5585_PWM_MODE | + ADP5585_PWM_EN, ADP5585_PWM_EN); + if (ret) + return ret; + + return 0; +} + +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); + unsigned int on, off; + unsigned int val; + + regmap_read(adp5585_pwm->regmap, ADP5585_PWM_OFFT_LOW, &off); + regmap_read(adp5585_pwm->regmap, ADP5585_PWM_OFFT_HIGH, &val); + off |= val << 8; + + regmap_read(adp5585_pwm->regmap, ADP5585_PWM_ONT_LOW, &on); + regmap_read(adp5585_pwm->regmap, ADP5585_PWM_ONT_HIGH, &val); + on |= val << 8; + + state->duty_cycle = on * (NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ); + state->period = (on + off) * (NSEC_PER_SEC / ADP5585_PWM_OSC_FREQ_HZ); + + state->polarity = PWM_POLARITY_NORMAL; + + regmap_read(adp5585_pwm->regmap, ADP5585_PWM_CFG, &val); + state->enabled = !!(val & ADP5585_PWM_EN); + + return 0; +} + +static const struct pwm_ops adp5585_pwm_ops = { + .request = pwm_adp5585_request, + .free = pwm_adp5585_free, + .apply = pwm_adp5585_apply, + .get_state = pwm_adp5585_get_state, +}; + +static int adp5585_pwm_probe(struct platform_device *pdev) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent); + struct adp5585_pwm_chip *adp5585_pwm; + int ret; + + adp5585_pwm = devm_kzalloc(&pdev->dev, sizeof(*adp5585_pwm), GFP_KERNEL); + if (!adp5585_pwm) + return -ENOMEM; + + platform_set_drvdata(pdev, adp5585_pwm); + + adp5585_pwm->regmap = adp5585->regmap; + + mutex_init(&adp5585_pwm->lock); + + adp5585_pwm->chip.dev = &pdev->dev; + adp5585_pwm->chip.ops = &adp5585_pwm_ops; + adp5585_pwm->chip.npwm = ADP5585_PWM_CHAN_NUM; + + ret = devm_pwmchip_add(&pdev->dev, &adp5585_pwm->chip); + if (ret) { + mutex_destroy(&adp5585_pwm->lock); + return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n"); + } + + return 0; +} + +static void adp5585_pwm_remove(struct platform_device *pdev) +{ + struct adp5585_pwm_chip *adp5585_pwm = platform_get_drvdata(pdev); + + mutex_destroy(&adp5585_pwm->lock); +} + +static const struct of_device_id adp5585_pwm_of_match[] = { + { .compatible = "adi,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_new = adp5585_pwm_remove, +}; +module_platform_driver(adp5585_pwm_driver); + +MODULE_AUTHOR("Xiaoning Wang "); +MODULE_DESCRIPTION("ADP5585 PWM Driver"); +MODULE_LICENSE("GPL");