From patchwork Tue May 27 22:25:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Kayode via B4 Relay X-Patchwork-Id: 893046 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 38F682147F2; Tue, 27 May 2025 22:26:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; cv=none; b=U2Yd1nP/xjUEA1OIX48Ywi5iUs9bhHywkh9DbWEO4GFWkyluGVReoU5ii6sDIR0WBLKqYHrZrZYubcB7dbdB5TBzVfhxfdcMaezDgGXtgDjdGGv5rmjxhuURxvE7F0wANJMUVsH/VOcsTlwPaYDII+VpUS9I0uwlzuF93fq+y64= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; c=relaxed/simple; bh=suDOGLgCQjgSfySaFDzmylmYIE5Fxa9bYp0izxSUg9I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZDnIEddUmKkZgIC8cPjsNOSI2JZYCt0qgiRG+u/7hFwtxQTspaZs2pS0zfVv0lkqCQIudasK3OrVX1jLzzWPNjLwa7fvcS3Pmd1rAv6p5ZscNJhBf2+sxX4EA2QUcvQUuDDPmooTR5GGApIFyE9NBENT6iMFAH4aWqvdOPVonZc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AEOIg22w; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AEOIg22w" Received: by smtp.kernel.org (Postfix) with ESMTPS id B97ADC4CEED; Tue, 27 May 2025 22:26:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748384784; bh=suDOGLgCQjgSfySaFDzmylmYIE5Fxa9bYp0izxSUg9I=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=AEOIg22wV6ZaA+FG318B18VokFqetzPI1Tqq+l0yJRqT1A6ZjntqY7wwmGnyG3Ie2 bYJEdhJRr2jlsX+KqBz8qSBLlMSEq7f1Aqafx9Z+szd4AxWIRPeTtR085xcczlOSmA dfna7INgUZs7+GO61FvhoSuMDxEY9RQwK3my02N9Py6NA2xmaNfRGVbM01IIM8jqjL Of/Ogytgh7+lWC7rGKouO20ffS9ieUgRfWvuS9f5j2meZw2jYId2EYpGG5RrwN2kyw 54HBPr8BS62r1bcWft4BDZr0gEIWtmdYFBh0b475Ide3E/Fx+FYN9pYT6fGE/14ztF zKOmoo1pj6LqQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A3744C54ED1; Tue, 27 May 2025 22:26:24 +0000 (UTC) From: Samuel Kayode via B4 Relay Date: Tue, 27 May 2025 18:25:33 -0400 Subject: [PATCH v3 1/6] dt-bindings: mfd: add pf1550 Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250527-pf1550-v3-1-45f69453cd51@savoirfairelinux.com> References: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> In-Reply-To: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Dmitry Torokhov , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, linux-pm@vger.kernel.org, Samuel Kayode , eballetbo@gmail.com, abelvesa@linux.com, b38343@freescale.com, yibin.gong@nxp.com, Abel Vesa X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1748384783; l=5295; i=samuel.kayode@savoirfairelinux.com; s=20250527; h=from:subject:message-id; bh=qDwJDqukdPYnizhVluFWp/IpAUKqb922WJOnoe5Cexw=; b=zfPchfRbG+eoztgNTypBqE7grUB69gpefvyKftSxdqq+zyp2eNCrgyp/pCXFsm+bdUXjRM3Ee ihAcFx1XPcIA0zYX9ynWRoTvkaF4RaeHs5bWzeGOBinKUdNQxnf8kk3 X-Developer-Key: i=samuel.kayode@savoirfairelinux.com; a=ed25519; pk=TPSQGQ5kywnnPyGs0EQqLajLFbdDu17ahXz8/gxMfio= X-Endpoint-Received: by B4 Relay for samuel.kayode@savoirfairelinux.com/20250527 with auth_id=412 X-Original-From: Samuel Kayode Reply-To: samuel.kayode@savoirfairelinux.com From: Samuel Kayode Add a DT binding document for pf1550 PMIC. This describes the core mfd device along with its children: regulators, charger and onkey. Signed-off-by: Samuel Kayode --- v3: - Address Krzysztof's feedback: - Fold charger and onkey objects - Drop compatible for sub-devices: onkey, charger and regulator. - Drop constant voltage property already included in monitored-battery - Fix whitespace warnings - Fix license v2: - Add yamls for the PMIC and the sub-devices --- Documentation/devicetree/bindings/mfd/pf1550.yaml | 139 ++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/pf1550.yaml b/Documentation/devicetree/bindings/mfd/pf1550.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7f22cb91eb5542c8aa616525ed1e78efa2a863d3 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/pf1550.yaml @@ -0,0 +1,139 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/pf1550.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PF1550 Power Management IC + +maintainers: + - Samuel Kayode + +description: | + PF1550 PMIC provides battery charging and power supply for low power IoT and + wearable applications. This device consists of an i2c controlled MFD that + includes regulators, battery charging and an onkey/power button. + +$ref: /schemas/power/supply/power-supply.yaml + +properties: + compatible: + const: fsl,pf1550 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + wakeup-source: true + + regulators: + type: object + + patternProperties: + "^(ldo[1-3]|sw[1-3]|vrefddr)$": + type: object + $ref: /schemas/regulator/regulator.yaml + description: + regulator configuration for ldo1-3, buck converters(sw1-3) + and DDR termination reference voltage (vrefddr) + unevaluatedProperties: false + + additionalProperties: false + + monitored-battery: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + A phandle to a monitored battery node that contains a valid value + for: + constant-charge-voltage-max-microvolt. + + fsl,thermal-regulation: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Temperature threshold for thermal regulation of charger in celsius. + enum: [ 60, 75, 90, 105 ] + + fsl,min-system-microvolt: + description: + System specific lower limit voltage. + enum: [ 3500000, 3700000, 4300000 ] + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + battery: battery-cell { + compatible = "simple-battery"; + constant-charge-voltage-max-microvolt = <4400000>; + operating-range-celsius = <0 75>; + }; + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@8 { + compatible = "fsl,pf1550"; + reg = <0x8>; + + interrupt-parent = <&gpio1>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + wakeup-source; + monitored-battery = <&battery>; + fsl,min-system-microvolt = <4300000>; + fsl,thermal-regulation = <75>; + + regulators { + sw1_reg: sw1 { + regulator-name = "sw1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1387500>; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-name = "sw2"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1387500>; + regulator-always-on; + }; + + sw3_reg: sw3 { + regulator-name = "sw3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vldo1_reg: ldo1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vldo2_reg: ldo2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vldo3_reg: ldo3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + }; From patchwork Tue May 27 22:25:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Kayode via B4 Relay X-Patchwork-Id: 892851 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 41477217659; Tue, 27 May 2025 22:26:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; cv=none; b=SZq9S8TwRzpIr1dwOW5GK+azYJKW6rUVTXjz/tG/fP1Fl9vRrN4tKI2pojqPLCizvIoIqG8RGg1OzhWXNcg/MKfeWJOBZdiN5ywxiPPqBwsJrCAT2LTmWAzcai2uOTc9xsvXHQY4690Hu3cfbfppMaUeiqaD/y3urL8eGK4d2zc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; c=relaxed/simple; bh=/s+QbixNc92ZjKCweZkkApeCp7b0Cyl6wFWArJWiwuk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=aJORAL6aVHJ4+Bdw9MVWFjjJzIkUo90fNbYv8GN+xoZ/3ZEo4L9EP8MSm9oG+0ADjmcoOdhwfsi9XFni2UkZd/BWAwdt4g2kzC3/cSzqBURNnc5K/jYep9VihuPSl8JmiVMH91R0MOcFo+14CqJBfHSQ9vCT4/n70DwTXe4nHH0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RGeRczvc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RGeRczvc" Received: by smtp.kernel.org (Postfix) with ESMTPS id CA1AAC4CEEE; Tue, 27 May 2025 22:26:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748384784; bh=/s+QbixNc92ZjKCweZkkApeCp7b0Cyl6wFWArJWiwuk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=RGeRczvcIIjd5qXtDrgKNU90q+5tHPkIQx5Ev6NMtm0AXavEoOzjfztppX591+QWI Ltk7Xlb7XEGwOC656hb3XYb/224+Oju+vDLt4D1BjLvS+FGsrfLhnjV9u2YK7CWSN4 KFSccyeYRgTuaNUoo8b4nCY1N3kBI7sIT6WN8gvB7+oHdwsURE16aIsoWnjLpyg2ML LRAowbshLeAJz63ROTACL0ANHZmTvE+FV45S0Chty+g6TZuiH/5daJaC2ppv336RsA KBwLbljZQHoSgM3t7EwDpEGvDaJQHJHrRM42/FM9iwdcND3Nu692zSPLaQt0b8K4j0 U/iYuAs8LscPg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id B7A14C5B54E; Tue, 27 May 2025 22:26:24 +0000 (UTC) From: Samuel Kayode via B4 Relay Date: Tue, 27 May 2025 18:25:34 -0400 Subject: [PATCH v3 2/6] mfd: pf1550: add core mfd driver Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250527-pf1550-v3-2-45f69453cd51@savoirfairelinux.com> References: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> In-Reply-To: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Dmitry Torokhov , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, linux-pm@vger.kernel.org, Samuel Kayode , eballetbo@gmail.com, abelvesa@linux.com, b38343@freescale.com, yibin.gong@nxp.com, Abel Vesa X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1748384783; l=19024; i=samuel.kayode@savoirfairelinux.com; s=20250527; h=from:subject:message-id; bh=YXKY2FuzZ0SpEiZNrN0xJbTvE6dRwUm5NRk30tearmA=; b=AKuuxqae0JmZ5S/yNVOd6HzzFXvW7rvYJOGx6KdW+df40QT4ld3ofiz4hHQTJqez2cLX0zSo/ mbKRSrCnImxA2F1qxuJeVruFX89GYah/ZmarXnGLDrI3KoCarEYeDA4 X-Developer-Key: i=samuel.kayode@savoirfairelinux.com; a=ed25519; pk=TPSQGQ5kywnnPyGs0EQqLajLFbdDu17ahXz8/gxMfio= X-Endpoint-Received: by B4 Relay for samuel.kayode@savoirfairelinux.com/20250527 with auth_id=412 X-Original-From: Samuel Kayode Reply-To: samuel.kayode@savoirfairelinux.com From: Samuel Kayode Add the core mfd driver for pf1550 PMIC. There are 3 subdevices for which the drivers will be added in subsequent patches. Signed-off-by: Samuel Kayode --- v3: - Address Dmitry's feedback: - Place Table IDs next to each other - Drop of_match_ptr - Replace dev_err with dev_err_probe in probe method - Drop useless log in probe - Map all irqs instead of doing it in the sub-devices as recommended by Dmitry. v2: - Address feedback from Enric Balletbo Serra --- drivers/mfd/Kconfig | 14 +++ drivers/mfd/Makefile | 2 + drivers/mfd/pf1550.c | 277 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/pf1550.h | 241 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 534 insertions(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 22b93631003943c393d9fe704748bc23f1905397..c43bd7d51955e576a9dc948fabb8cf8420a47d8b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -558,6 +558,20 @@ config MFD_MX25_TSADC i.MX25 processors. They consist of a conversion queue for general purpose ADC and a queue for Touchscreens. +config MFD_PF1550 + tristate "Freescale Semiconductor PF1550 PMIC Support" + depends on I2C=y && OF + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + Say yes here to add support for Freescale Semiconductor PF1550. + This is a companion Power Management IC with regulators, onkey, + and charger control on chip. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. + config MFD_HI6421_PMIC tristate "HiSilicon Hi6421 PMU/Codec IC" depends on OF diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 948cbdf42a18b22a826f0b17fb8d5796a7ec8ba6..c4f270c5538ac162e3006c6bec9ab8420ebea7f6 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -120,6 +120,8 @@ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o +obj-$(CONFIG_MFD_PF1550) += pf1550.o + obj-$(CONFIG_MFD_CORE) += mfd-core.o ocelot-soc-objs := ocelot-core.o ocelot-spi.o diff --git a/drivers/mfd/pf1550.c b/drivers/mfd/pf1550.c new file mode 100644 index 0000000000000000000000000000000000000000..7fd5bee7d24e51379562faeba0d3bc255e5f8048 --- /dev/null +++ b/drivers/mfd/pf1550.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pf1550.c - mfd core driver for the PF1550 + * + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Robin Gong + * + * This driver is based on max77693.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell pf1550_devs[] = { + { + .name = "pf1550-regulator", + }, + { + .name = "pf1550-onkey", + }, + { + .name = "pf1550-charger", + }, +}; + +static const struct regmap_config pf1550_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PF1550_PMIC_REG_END, +}; + +static const struct regmap_irq pf1550_regulator_irqs[] = { + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_LS, 0, PMIC_IRQ_SW1_LS), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_LS, 0, PMIC_IRQ_SW2_LS), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_LS, 0, PMIC_IRQ_SW3_LS), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_HS, 3, PMIC_IRQ_SW1_HS), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_HS, 3, PMIC_IRQ_SW2_HS), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_HS, 3, PMIC_IRQ_SW3_HS), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO1_FAULT, 16, PMIC_IRQ_LDO1_FAULT), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO2_FAULT, 16, PMIC_IRQ_LDO2_FAULT), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO3_FAULT, 16, PMIC_IRQ_LDO3_FAULT), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_110, 22, PMIC_IRQ_TEMP_110), + REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_125, 22, PMIC_IRQ_TEMP_125), +}; + +static const struct regmap_irq_chip pf1550_regulator_irq_chip = { + .name = "pf1550-regulator", + .status_base = PF1550_PMIC_REG_SW_INT_STAT0, + .mask_base = PF1550_PMIC_REG_SW_INT_MASK0, + .num_regs = 23, + .irqs = pf1550_regulator_irqs, + .num_irqs = ARRAY_SIZE(pf1550_regulator_irqs), +}; + +static const struct regmap_irq pf1550_onkey_irqs[] = { + REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_PUSHI, 0, ONKEY_IRQ_PUSHI), + REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_1SI, 0, ONKEY_IRQ_1SI), + REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_2SI, 0, ONKEY_IRQ_2SI), + REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_3SI, 0, ONKEY_IRQ_3SI), + REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_4SI, 0, ONKEY_IRQ_4SI), + REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_8SI, 0, ONKEY_IRQ_8SI), +}; + +static const struct regmap_irq_chip pf1550_onkey_irq_chip = { + .name = "pf1550-onkey", + .status_base = PF1550_PMIC_REG_ONKEY_INT_STAT0, + .ack_base = PF1550_PMIC_REG_ONKEY_INT_STAT0, + .mask_base = PF1550_PMIC_REG_ONKEY_INT_MASK0, + .use_ack = 1, + .init_ack_masked = 1, + .num_regs = 1, + .irqs = pf1550_onkey_irqs, + .num_irqs = ARRAY_SIZE(pf1550_onkey_irqs), +}; + +static const struct regmap_irq pf1550_charger_irqs[] = { + REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BAT2SOCI, 0, CHARG_IRQ_BAT2SOCI), + REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BATI, 0, CHARG_IRQ_BATI), + REGMAP_IRQ_REG(PF1550_CHARG_IRQ_CHGI, 0, CHARG_IRQ_CHGI), + REGMAP_IRQ_REG(PF1550_CHARG_IRQ_VBUSI, 0, CHARG_IRQ_VBUSI), + REGMAP_IRQ_REG(PF1550_CHARG_IRQ_THMI, 0, CHARG_IRQ_THMI), +}; + +static const struct regmap_irq_chip pf1550_charger_irq_chip = { + .name = "pf1550-charger", + .status_base = PF1550_CHARG_REG_CHG_INT, + .mask_base = PF1550_CHARG_REG_CHG_INT_MASK, + .num_regs = 1, + .irqs = pf1550_charger_irqs, + .num_irqs = ARRAY_SIZE(pf1550_charger_irqs), +}; + +int pf1550_read_otp(struct pf1550_dev *pf1550, unsigned int index, + unsigned int *val) +{ + int ret = 0; + + ret = regmap_write(pf1550->regmap, PF1550_PMIC_REG_KEY, 0x15); + if (ret) + goto read_err; + ret = regmap_write(pf1550->regmap, PF1550_CHARG_REG_CHGR_KEY2, 0x50); + if (ret) + goto read_err; + ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_KEY3, 0xAB); + if (ret) + goto read_err; + ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_FMRADDR, index); + if (ret) + goto read_err; + ret = regmap_read(pf1550->regmap, PF1550_TEST_REG_FMRDATA, val); + if (ret) + goto read_err; + + return 0; + +read_err: + dev_err(pf1550->dev, "read otp reg %x found!\n", index); + return ret; +} + +static int pf1550_map_chip_irqs(const struct regmap_irq_chip *chip, + struct regmap_irq_chip_data *data) +{ + const int num_irqs = chip->num_irqs; + int i; + + for (i = 0; i < num_irqs; i++) + if (regmap_irq_get_virq(data, i) < 0) + return -EINVAL; + + return 0; +} + +static int pf1550_i2c_probe(struct i2c_client *i2c) +{ + struct pf1550_dev *pf1550; + unsigned int reg_data = 0; + int ret = 0; + + pf1550 = devm_kzalloc(&i2c->dev, sizeof(*pf1550), GFP_KERNEL); + if (!pf1550) + return -ENOMEM; + + i2c_set_clientdata(i2c, pf1550); + pf1550->dev = &i2c->dev; + pf1550->i2c = i2c; + pf1550->irq = i2c->irq; + + pf1550->regmap = devm_regmap_init_i2c(i2c, &pf1550_regmap_config); + if (IS_ERR(pf1550->regmap)) + return dev_err_probe(pf1550->dev, PTR_ERR(pf1550->regmap), + "failed to allocate register map\n"); + + ret = regmap_read(pf1550->regmap, PF1550_PMIC_REG_DEVICE_ID, ®_data); + if (ret < 0 || reg_data != PF1550_DEVICE_ID) + return dev_err_probe(pf1550->dev, ret, "device not found!\n"); + + pf1550->type = PF1550; + + ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, + pf1550->irq, + IRQF_ONESHOT | IRQF_SHARED | + IRQF_TRIGGER_FALLING, 0, + &pf1550_regulator_irq_chip, + &pf1550->irq_data_regulator); + if (ret) + return dev_err_probe(pf1550->dev, ret, + "failed to add regulator irq chip\n"); + + ret = pf1550_map_chip_irqs(&pf1550_regulator_irq_chip, + pf1550->irq_data_regulator); + + if (ret) + return dev_err_probe(pf1550->dev, ret, + "Failed to get parent vIRQ for chip %s\n", + pf1550_regulator_irq_chip.name); + + ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, + pf1550->irq, + IRQF_ONESHOT | IRQF_SHARED | + IRQF_TRIGGER_FALLING, 0, + &pf1550_onkey_irq_chip, + &pf1550->irq_data_onkey); + if (ret) + return dev_err_probe(pf1550->dev, ret, + "failed to add onkey irq chip\n"); + + ret = pf1550_map_chip_irqs(&pf1550_onkey_irq_chip, + pf1550->irq_data_onkey); + + if (ret) + return dev_err_probe(pf1550->dev, ret, + "Failed to get parent vIRQ for chip %s\n", + pf1550_onkey_irq_chip.name); + + ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, + pf1550->irq, + IRQF_ONESHOT | IRQF_SHARED | + IRQF_TRIGGER_FALLING, 0, + &pf1550_charger_irq_chip, + &pf1550->irq_data_charger); + if (ret) + return dev_err_probe(pf1550->dev, ret, + "failed to add charger irq chip\n"); + + ret = pf1550_map_chip_irqs(&pf1550_charger_irq_chip, + pf1550->irq_data_charger); + + if (ret) + return dev_err_probe(pf1550->dev, ret, + "Failed to get parent vIRQ for chip %s\n", + pf1550_charger_irq_chip.name); + + return devm_mfd_add_devices(pf1550->dev, -1, pf1550_devs, + ARRAY_SIZE(pf1550_devs), NULL, 0, NULL); +} + +static int pf1550_suspend(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct pf1550_dev *pf1550 = i2c_get_clientdata(i2c); + + if (device_may_wakeup(dev)) { + enable_irq_wake(pf1550->irq); + disable_irq(pf1550->irq); + } + + return 0; +} + +static int pf1550_resume(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct pf1550_dev *pf1550 = i2c_get_clientdata(i2c); + + if (device_may_wakeup(dev)) { + disable_irq_wake(pf1550->irq); + enable_irq(pf1550->irq); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_pm, pf1550_suspend, pf1550_resume); + +static const struct i2c_device_id pf1550_i2c_id[] = { + { "pf1550", PF1550 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, pf1550_i2c_id); + +static const struct of_device_id pf1550_dt_match[] = { + { .compatible = "fsl,pf1550" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, pf1550_dt_match); + +static struct i2c_driver pf1550_i2c_driver = { + .driver = { + .name = "pf1550", + .pm = pm_sleep_ptr(&pf1550_pm), + .of_match_table = pf1550_dt_match, + }, + .probe = pf1550_i2c_probe, + .id_table = pf1550_i2c_id, +}; +module_i2c_driver(pf1550_i2c_driver); + +MODULE_DESCRIPTION("Freescale PF1550 multi-function core driver"); +MODULE_AUTHOR("Robin Gong "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/pf1550.h b/include/linux/mfd/pf1550.h new file mode 100644 index 0000000000000000000000000000000000000000..915a6dcac52e4c545b56f5ecff8c53176a024f68 --- /dev/null +++ b/include/linux/mfd/pf1550.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * pf1550.h - mfd head file for PF1550 + * + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Robin Gong + */ + +#ifndef __LINUX_MFD_PF1550_H +#define __LINUX_MFD_PF1550_H + +#include +#include + +enum chips { PF1550 = 1, }; + +enum pf1550_pmic_reg { + /* PMIC regulator part */ + PF1550_PMIC_REG_DEVICE_ID = 0x00, + PF1550_PMIC_REG_OTP_FLAVOR = 0x01, + PF1550_PMIC_REG_SILICON_REV = 0x02, + + PF1550_PMIC_REG_INT_CATEGORY = 0x06, + PF1550_PMIC_REG_SW_INT_STAT0 = 0x08, + PF1550_PMIC_REG_SW_INT_MASK0 = 0x09, + PF1550_PMIC_REG_SW_INT_SENSE0 = 0x0A, + PF1550_PMIC_REG_SW_INT_STAT1 = 0x0B, + PF1550_PMIC_REG_SW_INT_MASK1 = 0x0C, + PF1550_PMIC_REG_SW_INT_SENSE1 = 0x0D, + PF1550_PMIC_REG_SW_INT_STAT2 = 0x0E, + PF1550_PMIC_REG_SW_INT_MASK2 = 0x0F, + PF1550_PMIC_REG_SW_INT_SENSE2 = 0x10, + PF1550_PMIC_REG_LDO_INT_STAT0 = 0x18, + PF1550_PMIC_REG_LDO_INT_MASK0 = 0x19, + PF1550_PMIC_REG_LDO_INT_SENSE0 = 0x1A, + PF1550_PMIC_REG_TEMP_INT_STAT0 = 0x20, + PF1550_PMIC_REG_TEMP_INT_MASK0 = 0x21, + PF1550_PMIC_REG_TEMP_INT_SENSE0 = 0x22, + PF1550_PMIC_REG_ONKEY_INT_STAT0 = 0x24, + PF1550_PMIC_REG_ONKEY_INT_MASK0 = 0x25, + PF1550_PMIC_REG_ONKEY_INT_SENSE0 = 0x26, + PF1550_PMIC_REG_MISC_INT_STAT0 = 0x28, + PF1550_PMIC_REG_MISC_INT_MASK0 = 0x29, + PF1550_PMIC_REG_MISC_INT_SENSE0 = 0x2A, + + PF1550_PMIC_REG_COINCELL_CONTROL = 0x30, + + PF1550_PMIC_REG_SW1_VOLT = 0x32, + PF1550_PMIC_REG_SW1_STBY_VOLT = 0x33, + PF1550_PMIC_REG_SW1_SLP_VOLT = 0x34, + PF1550_PMIC_REG_SW1_CTRL = 0x35, + PF1550_PMIC_REG_SW1_CTRL1 = 0x36, + PF1550_PMIC_REG_SW2_VOLT = 0x38, + PF1550_PMIC_REG_SW2_STBY_VOLT = 0x39, + PF1550_PMIC_REG_SW2_SLP_VOLT = 0x3A, + PF1550_PMIC_REG_SW2_CTRL = 0x3B, + PF1550_PMIC_REG_SW2_CTRL1 = 0x3C, + PF1550_PMIC_REG_SW3_VOLT = 0x3E, + PF1550_PMIC_REG_SW3_STBY_VOLT = 0x3F, + PF1550_PMIC_REG_SW3_SLP_VOLT = 0x40, + PF1550_PMIC_REG_SW3_CTRL = 0x41, + PF1550_PMIC_REG_SW3_CTRL1 = 0x42, + PF1550_PMIC_REG_VSNVS_CTRL = 0x48, + PF1550_PMIC_REG_VREFDDR_CTRL = 0x4A, + PF1550_PMIC_REG_LDO1_VOLT = 0x4C, + PF1550_PMIC_REG_LDO1_CTRL = 0x4D, + PF1550_PMIC_REG_LDO2_VOLT = 0x4F, + PF1550_PMIC_REG_LDO2_CTRL = 0x50, + PF1550_PMIC_REG_LDO3_VOLT = 0x52, + PF1550_PMIC_REG_LDO3_CTRL = 0x53, + PF1550_PMIC_REG_PWRCTRL0 = 0x58, + PF1550_PMIC_REG_PWRCTRL1 = 0x59, + PF1550_PMIC_REG_PWRCTRL2 = 0x5A, + PF1550_PMIC_REG_PWRCTRL3 = 0x5B, + PF1550_PMIC_REG_SW1_PWRDN_SEQ = 0x5F, + PF1550_PMIC_REG_SW2_PWRDN_SEQ = 0x60, + PF1550_PMIC_REG_SW3_PWRDN_SEQ = 0x61, + PF1550_PMIC_REG_LDO1_PWRDN_SEQ = 0x62, + PF1550_PMIC_REG_LDO2_PWRDN_SEQ = 0x63, + PF1550_PMIC_REG_LDO3_PWRDN_SEQ = 0x64, + PF1550_PMIC_REG_VREFDDR_PWRDN_SEQ = 0x65, + + PF1550_PMIC_REG_STATE_INFO = 0x67, + PF1550_PMIC_REG_I2C_ADDR = 0x68, + PF1550_PMIC_REG_IO_DRV0 = 0x69, + PF1550_PMIC_REG_IO_DRV1 = 0x6A, + PF1550_PMIC_REG_RC_16MHZ = 0x6B, + PF1550_PMIC_REG_KEY = 0x6F, + + /* charger part */ + PF1550_CHARG_REG_CHG_INT = 0x80, + PF1550_CHARG_REG_CHG_INT_MASK = 0x82, + PF1550_CHARG_REG_CHG_INT_OK = 0x84, + PF1550_CHARG_REG_VBUS_SNS = 0x86, + PF1550_CHARG_REG_CHG_SNS = 0x87, + PF1550_CHARG_REG_BATT_SNS = 0x88, + PF1550_CHARG_REG_CHG_OPER = 0x89, + PF1550_CHARG_REG_CHG_TMR = 0x8A, + PF1550_CHARG_REG_CHG_EOC_CNFG = 0x8D, + PF1550_CHARG_REG_CHG_CURR_CNFG = 0x8E, + PF1550_CHARG_REG_BATT_REG = 0x8F, + PF1550_CHARG_REG_BATFET_CNFG = 0x91, + PF1550_CHARG_REG_THM_REG_CNFG = 0x92, + PF1550_CHARG_REG_VBUS_INLIM_CNFG = 0x94, + PF1550_CHARG_REG_VBUS_LIN_DPM = 0x95, + PF1550_CHARG_REG_USB_PHY_LDO_CNFG = 0x96, + PF1550_CHARG_REG_DBNC_DELAY_TIME = 0x98, + PF1550_CHARG_REG_CHG_INT_CNFG = 0x99, + PF1550_CHARG_REG_THM_ADJ_SETTING = 0x9A, + PF1550_CHARG_REG_VBUS2SYS_CNFG = 0x9B, + PF1550_CHARG_REG_LED_PWM = 0x9C, + PF1550_CHARG_REG_FAULT_BATFET_CNFG = 0x9D, + PF1550_CHARG_REG_LED_CNFG = 0x9E, + PF1550_CHARG_REG_CHGR_KEY2 = 0x9F, + + PF1550_TEST_REG_FMRADDR = 0xC4, + PF1550_TEST_REG_FMRDATA = 0xC5, + PF1550_TEST_REG_KEY3 = 0xDF, + + PF1550_PMIC_REG_END = 0xff, +}; + +#define PF1550_DEVICE_ID 0x7c + +#define PF1550_CHG_TURNON 0x2 + +#define PF1550_CHG_PRECHARGE 0 +#define PF1550_CHG_CONSTANT_CURRENT 1 +#define PF1550_CHG_CONSTANT_VOL 2 +#define PF1550_CHG_EOC 3 +#define PF1550_CHG_DONE 4 +#define PF1550_CHG_TIMER_FAULT 6 +#define PF1550_CHG_SUSPEND 7 +#define PF1550_CHG_OFF_INV 8 +#define PF1550_CHG_BAT_OVER 9 +#define PF1550_CHG_OFF_TEMP 10 +#define PF1550_CHG_LINEAR_ONLY 12 +#define PF1550_CHG_SNS_MASK 0xf +#define PF1550_CHG_INT_MASK 0x51 + +#define PF1550_BAT_NO_VBUS 0 +#define PF1550_BAT_LOW_THAN_PRECHARG 1 +#define PF1550_BAT_CHARG_FAIL 2 +#define PF1550_BAT_HIGH_THAN_PRECHARG 4 +#define PF1550_BAT_OVER_VOL 5 +#define PF1550_BAT_NO_DETECT 6 +#define PF1550_BAT_SNS_MASK 0x7 + +#define PF1550_VBUS_UVLO BIT(2) +#define PF1550_VBUS_IN2SYS BIT(3) +#define PF1550_VBUS_OVLO BIT(4) +#define PF1550_VBUS_VALID BIT(5) + +#define PF1550_CHARG_REG_BATT_REG_CHGCV_MASK 0x3f +#define PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT 6 +#define PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK (0x3 << 6) +#define PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT 2 +#define PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK (0x3 << 2) + +#define PMIC_IRQ_SW1_LS BIT(0) +#define PMIC_IRQ_SW2_LS BIT(1) +#define PMIC_IRQ_SW3_LS BIT(2) +#define PMIC_IRQ_SW1_HS BIT(0) +#define PMIC_IRQ_SW2_HS BIT(1) +#define PMIC_IRQ_SW3_HS BIT(2) +#define PMIC_IRQ_LDO1_FAULT BIT(0) +#define PMIC_IRQ_LDO2_FAULT BIT(1) +#define PMIC_IRQ_LDO3_FAULT BIT(2) +#define PMIC_IRQ_TEMP_110 BIT(0) +#define PMIC_IRQ_TEMP_125 BIT(1) + +#define ONKEY_IRQ_PUSHI BIT(0) +#define ONKEY_IRQ_1SI BIT(1) +#define ONKEY_IRQ_2SI BIT(2) +#define ONKEY_IRQ_3SI BIT(3) +#define ONKEY_IRQ_4SI BIT(4) +#define ONKEY_IRQ_8SI BIT(5) + +#define CHARG_IRQ_BAT2SOCI BIT(1) +#define CHARG_IRQ_BATI BIT(2) +#define CHARG_IRQ_CHGI BIT(3) +#define CHARG_IRQ_VBUSI BIT(5) +#define CHARG_IRQ_DPMI BIT(6) +#define CHARG_IRQ_THMI BIT(7) + +enum pf1550_pmic_irq { + PF1550_PMIC_IRQ_SW1_LS, + PF1550_PMIC_IRQ_SW2_LS, + PF1550_PMIC_IRQ_SW3_LS, + PF1550_PMIC_IRQ_SW1_HS, + PF1550_PMIC_IRQ_SW2_HS, + PF1550_PMIC_IRQ_SW3_HS, + PF1550_PMIC_IRQ_LDO1_FAULT, + PF1550_PMIC_IRQ_LDO2_FAULT, + PF1550_PMIC_IRQ_LDO3_FAULT, + PF1550_PMIC_IRQ_TEMP_110, + PF1550_PMIC_IRQ_TEMP_125, +}; + +enum pf1550_onkey_irq { + PF1550_ONKEY_IRQ_PUSHI, + PF1550_ONKEY_IRQ_1SI, + PF1550_ONKEY_IRQ_2SI, + PF1550_ONKEY_IRQ_3SI, + PF1550_ONKEY_IRQ_4SI, + PF1550_ONKEY_IRQ_8SI, +}; + +enum pf1550_charg_irq { + PF1550_CHARG_IRQ_BAT2SOCI, + PF1550_CHARG_IRQ_BATI, + PF1550_CHARG_IRQ_CHGI, + PF1550_CHARG_IRQ_VBUSI, + PF1550_CHARG_IRQ_THMI, +}; + +enum pf1550_regulators { + PF1550_SW1, + PF1550_SW2, + PF1550_SW3, + PF1550_VREFDDR, + PF1550_LDO1, + PF1550_LDO2, + PF1550_LDO3, +}; + +struct pf1550_dev { + struct device *dev; + struct i2c_client *i2c; + int type; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data_regulator; + struct regmap_irq_chip_data *irq_data_onkey; + struct regmap_irq_chip_data *irq_data_charger; + int irq; +}; + +int pf1550_read_otp(struct pf1550_dev *pf1550, unsigned int index, + unsigned int *val); + +#endif /* __LINUX_MFD_PF1550_H */ From patchwork Tue May 27 22:25:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Kayode via B4 Relay X-Patchwork-Id: 893045 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 414D321770B; Tue, 27 May 2025 22:26:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; cv=none; b=Y8vC0HnJeFAAyevhDQUjwRkF9ECWzRT8WHjzWKu+86P0eTRdBoYLf6J2YgyklTUBn6bEyiTcUmHLw8pLJgM+DKd4RbhFbmnOT4K8/w9dFmmdrGwW/w87oyVKb9L5omLNiXmFNBOqzzZMLNIu4AebWnCcOK1ZqrHVEzZ2bURCdeE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; c=relaxed/simple; bh=1cYL0CAe/rc9iAEFS8/Gd2jkZuQ9N4GWD4ywhF775cY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MPYEw93ctpw3ppenw+m9M0JCm9T822LYggL0NcbW2PAO78krdj5ybHbhxzvXXGXEPgA/5Fq3mKX8YSjrOLNXji1ou3X4+PpYxzrhX4UcSb/SZyuGU5b5X/ZzehpbEnhWDYmV0vCf3tIic/rr23bf3s3WGyLK3GJXyfnO2orFxo0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ETzCgO5B; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ETzCgO5B" Received: by smtp.kernel.org (Postfix) with ESMTPS id DDDD6C4CEF2; Tue, 27 May 2025 22:26:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748384785; bh=1cYL0CAe/rc9iAEFS8/Gd2jkZuQ9N4GWD4ywhF775cY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ETzCgO5Bc284VnXfh7VxXocndccqhEgXNRhv1MGOFJ/FVnca6hzH0qUoYf+P11h75 AioPAUwFsnuoVZqUs+xtKt1nTTPfefWQ9rYx6YlgBO0bGDPJZFRdcV2elwS8FPY1UK JdcFJUSuac4c9sMco3ySHhL5Sub+MneguqI3qs1y5UqgSqur1c20aEAsHJpIKQfQ0E 6VtbgdsaE+1/+ZZdGqzLJkKCfwomA3oSBtLRWAoQfrpHq4wJXdX+FaWNOp5DlOG9Ze dvsfmkJ7BmWWvngnv72AhWwDLT4DCPyurHNrCeF81YWb6iZRgwi8OOuLW19PXyhMYd QO4pDXnG/6Hug== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id CE87BC5B549; Tue, 27 May 2025 22:26:24 +0000 (UTC) From: Samuel Kayode via B4 Relay Date: Tue, 27 May 2025 18:25:35 -0400 Subject: [PATCH v3 3/6] regulator: pf1550: add support for regulator Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250527-pf1550-v3-3-45f69453cd51@savoirfairelinux.com> References: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> In-Reply-To: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Dmitry Torokhov , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, linux-pm@vger.kernel.org, Samuel Kayode , eballetbo@gmail.com, abelvesa@linux.com, b38343@freescale.com, yibin.gong@nxp.com, Abel Vesa X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1748384783; l=13458; i=samuel.kayode@savoirfairelinux.com; s=20250527; h=from:subject:message-id; bh=u7ayKFgCUGGEVmXNoXzopos0ex4Uju0ZK84SSc9xqWk=; b=gsfgPJZ9FVdF+qpEnqaNGpFgHyxErg51lJNnS7Vyr6JkOnBSkiu1AjXLJGaFsFU6/SlFVfTDf dfX2ZRLJVjTCOd51us9/b4Lw04MeVwdeEU4SxFFN38R9r3vFaGW/ghE X-Developer-Key: i=samuel.kayode@savoirfairelinux.com; a=ed25519; pk=TPSQGQ5kywnnPyGs0EQqLajLFbdDu17ahXz8/gxMfio= X-Endpoint-Received: by B4 Relay for samuel.kayode@savoirfairelinux.com/20250527 with auth_id=412 X-Original-From: Samuel Kayode Reply-To: samuel.kayode@savoirfairelinux.com From: Samuel Kayode Add regulator support for the pf1550 PMIC. Signed-off-by: Samuel Kayode --- v3: - Drop duplicate include - Drop unnecessary includes - Accept lower case regulator names from devicetree - Use virqs mapped in core MFD driver v2: - Add driver for regulator --- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/pf1550-regulator.c | 353 +++++++++++++++++++++++++++++++++++ 3 files changed, 363 insertions(+) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 05e32d764028307dcbea3cf28c9834f26d70c34b..f888454228b891a635dab8686dcd09a574a17eaa 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1038,6 +1038,15 @@ config REGULATOR_PV88090 Say y here to support the voltage regulators and convertors on PV88090 +config REGULATOR_PF1550 + tristate "Freescale PF1550 regulator" + depends on MFD_PF1550 + help + Say y here to select this option to enable the regulators on + the PF1550 PMICs. + This driver controls the PF1550 regulators via I2C bus. + The regulators include three bucks and three ldos. + config REGULATOR_PWM tristate "PWM voltage regulator" depends on PWM diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 524e026c02734047021182bec562f903baa44bbc..bbf83fd2c9824858fc6c632c9e7d9ef901363276 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -124,6 +124,7 @@ obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o +obj-$(CONFIG_REGULATOR_PF1550) += pf1550-regulator.o obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o diff --git a/drivers/regulator/pf1550-regulator.c b/drivers/regulator/pf1550-regulator.c new file mode 100644 index 0000000000000000000000000000000000000000..7f2b0a14c1f252fab81a5c50d0b0d769b4dc1ccb --- /dev/null +++ b/drivers/regulator/pf1550-regulator.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pf1550.c - regulator driver for the PF1550 + * + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Robin Gong + * + * This driver is based on pfuze100-regulator.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PF1550_REGULATOR_IRQ_NR 11 +#define PF1550_MAX_REGULATOR 7 + +struct pf1550_desc { + struct regulator_desc desc; + unsigned char stby_reg; + unsigned char stby_mask; +}; + +struct pf1550_regulator_info { + struct device *dev; + struct pf1550_dev *pf1550; + struct pf1550_desc regulator_descs[PF1550_MAX_REGULATOR]; + int irq; +}; + +static const int pf1550_sw12_volts[] = { + 1100000, 1200000, 1350000, 1500000, 1800000, 2500000, 3000000, 3300000, +}; + +static const int pf1550_ldo13_volts[] = { + 750000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, + 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, + 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, + 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000, +}; + +static int pf1550_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + int id = rdev_get_id(rdev); + unsigned int ramp_bits; + int ret; + + if (id > PF1550_VREFDDR) + return -EACCES; + + ramp_delay = 6250 / ramp_delay; + ramp_bits = ramp_delay >> 1; + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg + 4, 0x10, + ramp_bits << 4); + if (ret < 0) + dev_err(&rdev->dev, "ramp failed, err %d\n", ret); + + return ret; +} + +static const struct regulator_ops pf1550_sw1_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = pf1550_set_ramp_delay, +}; + +static const struct regulator_ops pf1550_sw2_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = pf1550_set_ramp_delay, +}; + +static const struct regulator_ops pf1550_ldo1_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_ops pf1550_ldo2_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_ops pf1550_fixed_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, +}; + +#define PF_VREF(_chip, match, _name, voltage) { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = 1, \ + .ops = &pf1550_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (voltage), \ + .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \ + .enable_mask = 0x1, \ + }, \ + .stby_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \ + .stby_mask = 0x2, \ +} + +#define PF_SW1(_chip, match, _name, mask, voltages) { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = ARRAY_SIZE(voltages), \ + .ops = &pf1550_sw1_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .volt_table = voltages, \ + .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \ + .vsel_mask = (mask), \ + }, \ + .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \ + .stby_mask = (mask), \ +} + +#define PF_SW3(_chip, match, _name, min, max, mask, step) { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pf1550_sw2_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \ + .vsel_mask = (mask), \ + }, \ + .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \ + .stby_mask = (mask), \ +} + +#define PF_LDO1(_chip, match, _name, mask, voltages) { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = ARRAY_SIZE(voltages), \ + .ops = &pf1550_ldo1_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .volt_table = voltages, \ + .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \ + .vsel_mask = (mask), \ + .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \ + .enable_mask = 0x1, \ + }, \ + .stby_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \ + .stby_mask = 0x2, \ +} + +#define PF_LDO2(_chip, match, _name, mask, min, max, step) { \ + .desc = { \ + .name = #_name, \ + .of_match = of_match_ptr(match), \ + .regulators_node = of_match_ptr("regulators"), \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .ops = &pf1550_ldo2_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = _chip ## _ ## _name, \ + .owner = THIS_MODULE, \ + .min_uV = (min), \ + .uV_step = (step), \ + .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \ + .vsel_mask = (mask), \ + .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \ + .enable_mask = 0x1, \ + }, \ + .stby_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \ + .stby_mask = 0x2, \ +} + +static struct pf1550_desc pf1550_regulators[] = { + PF_SW3(PF1550, "sw1", SW1, 600000, 1387500, 0x3f, 12500), + PF_SW3(PF1550, "sw2", SW2, 600000, 1387500, 0x3f, 12500), + PF_SW3(PF1550, "sw3", SW3, 1800000, 3300000, 0xf, 100000), + PF_VREF(PF1550, "vrefddr", VREFDDR, 1200000), + PF_LDO1(PF1550, "ldo1", LDO1, 0x1f, pf1550_ldo13_volts), + PF_LDO2(PF1550, "ldo2", LDO2, 0xf, 1800000, 3300000, 100000), + PF_LDO1(PF1550, "ldo3", LDO3, 0x1f, pf1550_ldo13_volts), +}; + +static irqreturn_t pf1550_regulator_irq_handler(int irq, void *data) +{ + struct pf1550_regulator_info *info = data; + struct device *dev = info->dev; + struct irq_domain *domain; + int i, irq_type = -1; + unsigned int virq; + + domain = regmap_irq_get_domain(info->pf1550->irq_data_regulator); + info->irq = irq; + + for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++) { + virq = irq_find_mapping(domain, i); + if (info->irq == virq) + irq_type = i; + } + + switch (irq_type) { + case PF1550_PMIC_IRQ_SW1_LS: + case PF1550_PMIC_IRQ_SW2_LS: + case PF1550_PMIC_IRQ_SW3_LS: + dev_info(dev, "lowside interrupt triggered! irq_type=%d\n", + irq_type); + break; + case PF1550_PMIC_IRQ_SW1_HS: + case PF1550_PMIC_IRQ_SW2_HS: + case PF1550_PMIC_IRQ_SW3_HS: + dev_info(dev, "highside interrupt triggered! irq_type=%d\n", + irq_type); + break; + case PF1550_PMIC_IRQ_LDO1_FAULT: + case PF1550_PMIC_IRQ_LDO2_FAULT: + case PF1550_PMIC_IRQ_LDO3_FAULT: + dev_info(dev, "ldo fault triggered! irq_type=%d\n", irq_type); + break; + case PF1550_PMIC_IRQ_TEMP_110: + case PF1550_PMIC_IRQ_TEMP_125: + dev_info(dev, "thermal exception triggered! irq_type=%d\n", + irq_type); + break; + default: + dev_err(dev, "regulator interrupt: irq %d occurred\n", + irq_type); + } + + return IRQ_HANDLED; +} + +static int pf1550_regulator_probe(struct platform_device *pdev) +{ + struct pf1550_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct pf1550_regulator_info *info; + struct irq_domain *domain; + int i, ret = 0; + struct regulator_config config = { }; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + config.regmap = dev_get_regmap(iodev->dev, NULL); + if (!config.regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "failed to get parent regmap\n"); + + config.dev = iodev->dev; + config.regmap = iodev->regmap; + info->dev = &pdev->dev; + info->pf1550 = iodev; + + memcpy(info->regulator_descs, pf1550_regulators, + sizeof(info->regulator_descs)); + + for (i = 0; i < ARRAY_SIZE(pf1550_regulators); i++) { + struct regulator_dev *rdev; + struct regulator_desc *desc; + unsigned int val; + + desc = &info->regulator_descs[i].desc; + + if (desc->id == PF1550_SW2) { + pf1550_read_otp(info->pf1550, 0x1f, &val); + /* OTP_SW2_DVS_ENB == 1? */ + if ((val & 0x8)) { + desc->volt_table = pf1550_sw12_volts; + desc->n_voltages = ARRAY_SIZE(pf1550_sw12_volts); + desc->ops = &pf1550_sw1_ops; + } + } + + rdev = devm_regulator_register(&pdev->dev, desc, &config); + if (IS_ERR(rdev)) + return dev_err_probe(&pdev->dev, PTR_ERR(rdev), + "failed to initialize regulator-%d\n", + i); + } + + platform_set_drvdata(pdev, info); + + domain = regmap_irq_get_domain(iodev->irq_data_regulator); + + for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++) { + unsigned int virq = irq_find_mapping(domain, i); + + ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, + pf1550_regulator_irq_handler, + IRQF_NO_SUSPEND, + "pf1550-regulator", info); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed: irq request (IRQ: %d)\n", + i); + } + + /* unmask all exception interrupts for regulators */ + regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_SW_INT_MASK0, 0); + regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_SW_INT_MASK1, 0); + regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_LDO_INT_MASK0, 0); + regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_TEMP_INT_MASK0, 0); + + return 0; +} + +static const struct platform_device_id pf1550_regulator_id[] = { + { "pf1550-regulator", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, pf1550_regulator_id); + +static struct platform_driver pf1550_regulator_driver = { + .driver = { + .name = "pf1550-regulator", + }, + .probe = pf1550_regulator_probe, + .id_table = pf1550_regulator_id, +}; +module_platform_driver(pf1550_regulator_driver); + +MODULE_DESCRIPTION("Freescale PF1550 regulator driver"); +MODULE_AUTHOR("Robin Gong "); +MODULE_LICENSE("GPL"); From patchwork Tue May 27 22:25:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Kayode via B4 Relay X-Patchwork-Id: 892850 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 5B26C21770C; Tue, 27 May 2025 22:26:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; cv=none; b=ZXi0aZRYi0Dl/+LBjdrVQDD1TDYr7MAc4u/dSu5vkxES5TjJhy96exW680HyFamLM68RZ8vkAekXtEzcw4HR6OXtyv6KFAHI8ZANkDxxwFT0Gk+2jqMVTEz5AzRxBx2TbCv3DcAWEk9+OcOEiSxxbJ+FwCYW1Bpas9EsEN42cgU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; c=relaxed/simple; bh=4dGG9cNsmbWRrUh8AMfJ3DPeCEL7b5KAdhyrq1boNy0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pmyfNx/gyN+JpY7efMr5GW/N6d2w2kDFwWIcko2QoUzciuhT0Ypm9vVlSUETDMkD4VWj8C5uyrru0BpjM+3b2DjKBU9b1k8joAsIFtT3e/lYWH461WpIDjIEnSzLRh+GjX4wpbtRLevJ6R3PGDLyjSj8HIwoS3gKdxX/HJ4WqlE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BlqpKvnX; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BlqpKvnX" Received: by smtp.kernel.org (Postfix) with ESMTPS id EEF5AC4CEF7; Tue, 27 May 2025 22:26:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748384785; bh=4dGG9cNsmbWRrUh8AMfJ3DPeCEL7b5KAdhyrq1boNy0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=BlqpKvnXxvph5vaY9wypjaoqIMpV6lnqfyDuAgfYDszCxi+g9u3yyPWDI8ww7hY8T iAXmPmSm1MgEt8IRdbHY9+9QT33GyfZsTk97rajoSKg165I4E5d0AxUd1i+GpwCgGX HwFAGc+c1HRQ+z/c4z6c8+CfasHm/X/8j94YvWdpfR1utX/mSZqOWC5pH6HJBzHEcA l9CuoS91BDd3NjADKBT8NhN/VhmUJYnTMjmvbJoO4Sa3j9sCA3GKv79/0hoHH+h5f9 +MBBBnt+Ru7y/Fgd/zHIRxYYkQmqdltEUBospNC2dsAuLQW+fnqRNowG9h/aq5DdfH hOq0+1oE82C3A== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1828C54ED1; Tue, 27 May 2025 22:26:24 +0000 (UTC) From: Samuel Kayode via B4 Relay Date: Tue, 27 May 2025 18:25:36 -0400 Subject: [PATCH v3 4/6] input: pf1550: add onkey support Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250527-pf1550-v3-4-45f69453cd51@savoirfairelinux.com> References: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> In-Reply-To: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Dmitry Torokhov , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, linux-pm@vger.kernel.org, Samuel Kayode , eballetbo@gmail.com, abelvesa@linux.com, b38343@freescale.com, yibin.gong@nxp.com, Abel Vesa X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1748384783; l=8033; i=samuel.kayode@savoirfairelinux.com; s=20250527; h=from:subject:message-id; bh=/wsti50j6s+keD9n41QfbYKR2di1w3YFr5KzADXNbQc=; b=5ldXQyt/42Ui6q4uRuxUv33gUv2By7+g1mu/z1QyvcnwVNwxRURUJjDrDOgsMUYmXThsEx4yb weC2ZWpel3VAxLQKMSCJpWQSkf0gUMda1sTzDeujPgNEgnLXH1QnNCt X-Developer-Key: i=samuel.kayode@savoirfairelinux.com; a=ed25519; pk=TPSQGQ5kywnnPyGs0EQqLajLFbdDu17ahXz8/gxMfio= X-Endpoint-Received: by B4 Relay for samuel.kayode@savoirfairelinux.com/20250527 with auth_id=412 X-Original-From: Samuel Kayode Reply-To: samuel.kayode@savoirfairelinux.com From: Samuel Kayode Add support for the onkey of the pf1550 PMIC. Signed-off-by: Samuel Kayode --- v3: - Address Dmitry's feedback - Drop compatible string - Remove dependency on OF - Use generic device properties - Drop unnecessary includes - Drop unnecessary initializations in probe - Always use the KEY_POWER property for onkey->keycode - Do mapping of irqs in MFD driver - Define onkey->input before interrupts are active - Drop unnecessary input_free_device since devm - Manage onkey irqs instead of the main interrupt line. - Fix integer overflow when unmasking onkey irqs in onkey_resume. v2: - Add driver for onkey --- drivers/input/misc/Kconfig | 11 +++ drivers/input/misc/Makefile | 1 + drivers/input/misc/pf1550-onkey.c | 202 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index f5496ca0c0d2bfcb7968503ccd1844ff43bbc1c0..50ae50628f4d03f54b5678dbd28e3b58f8d02f86 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -179,6 +179,17 @@ config INPUT_PCSPKR To compile this driver as a module, choose M here: the module will be called pcspkr. +config INPUT_PF1550_ONKEY + tristate "PF1550 Onkey support" + depends on MFD_PF1550 + help + Say Y here if you want support for PF1550 PMIC. Onkey can trigger + release and 1s(push hold), 2s, 3s, 4s, 8s interrupt for long press + detect. + + To compile this driver as a module, choose M here. The module will be + called pf1550-onkey. + config INPUT_PM8941_PWRKEY tristate "Qualcomm PM8941 power key support" depends on MFD_SPMI_PMIC diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 6d91804d0a6f761a094e6c380f878f74c3054d63..c652337de464c1eeaf1515d0bc84d10de0cb3a74 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o +obj-$(CONFIG_INPUT_PF1550_ONKEY) += pf1550-onkey.o obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o diff --git a/drivers/input/misc/pf1550-onkey.c b/drivers/input/misc/pf1550-onkey.c new file mode 100644 index 0000000000000000000000000000000000000000..7c10bc75708891a22d8b67b44e55f18c42f09749 --- /dev/null +++ b/drivers/input/misc/pf1550-onkey.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the PF1550 ON_KEY + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PF1550_ONKEY_IRQ_NR 6 + +struct onkey_drv_data { + struct device *dev; + struct pf1550_dev *pf1550; + unsigned int irq; + int keycode; + int wakeup; + struct input_dev *input; +}; + +static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data) +{ + struct onkey_drv_data *onkey = data; + struct irq_domain *domain; + int i, state, irq_type = -1; + unsigned int virq; + + domain = regmap_irq_get_domain(onkey->pf1550->irq_data_onkey); + onkey->irq = irq; + + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + virq = irq_find_mapping(domain, i); + if (onkey->irq == virq) + irq_type = i; + } + + switch (irq_type) { + case PF1550_ONKEY_IRQ_PUSHI: + state = 0; + break; + case PF1550_ONKEY_IRQ_1SI: + case PF1550_ONKEY_IRQ_2SI: + case PF1550_ONKEY_IRQ_3SI: + case PF1550_ONKEY_IRQ_4SI: + case PF1550_ONKEY_IRQ_8SI: + state = 1; + break; + default: + dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n", + irq_type); + return IRQ_HANDLED; + } + + input_event(onkey->input, EV_KEY, onkey->keycode, state); + input_sync(onkey->input); + + return IRQ_HANDLED; +} + +static int pf1550_onkey_probe(struct platform_device *pdev) +{ + struct onkey_drv_data *onkey; + struct input_dev *input; + struct pf1550_dev *pf1550 = dev_get_drvdata(pdev->dev.parent); + struct irq_domain *domain; + int i, error; + + onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + if (!pf1550->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "failed to get regmap\n"); + + onkey->wakeup = device_property_read_bool(pdev->dev.parent, + "wakeup-source"); + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return dev_err_probe(&pdev->dev, -ENOMEM, + "failed to allocate the input device\n"); + + onkey->input = input; + onkey->keycode = KEY_POWER; + + input->name = pdev->name; + input->phys = "pf1550-onkey/input0"; + input->id.bustype = BUS_HOST; + + input_set_capability(input, EV_KEY, onkey->keycode); + + domain = regmap_irq_get_domain(pf1550->irq_data_onkey); + + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + unsigned int virq = irq_find_mapping(domain, i); + + error = devm_request_threaded_irq(&pdev->dev, virq, NULL, + pf1550_onkey_irq_handler, + IRQF_NO_SUSPEND, + "pf1550-onkey", onkey); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed: irq request (IRQ: %d)\n", + i); + } + + error = input_register_device(input); + if (error < 0) + return dev_err_probe(&pdev->dev, error, + "failed to register input device\n"); + + onkey->pf1550 = pf1550; + platform_set_drvdata(pdev, onkey); + + device_init_wakeup(&pdev->dev, onkey->wakeup); + + return 0; +} + +static int pf1550_onkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct onkey_drv_data *onkey = platform_get_drvdata(pdev); + struct irq_domain *domain; + unsigned int virq; + int i; + + domain = regmap_irq_get_domain(onkey->pf1550->irq_data_onkey); + + if (!device_may_wakeup(&pdev->dev)) { + regmap_write(onkey->pf1550->regmap, + PF1550_PMIC_REG_ONKEY_INT_MASK0, + ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI | + ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI); + } else { + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + virq = irq_find_mapping(domain, i); + + if (virq) + enable_irq_wake(virq); + } + } + + return 0; +} + +static int pf1550_onkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct onkey_drv_data *onkey = platform_get_drvdata(pdev); + struct irq_domain *domain; + unsigned int virq; + int i; + + domain = regmap_irq_get_domain(onkey->pf1550->irq_data_onkey); + + if (!device_may_wakeup(&pdev->dev)) { + regmap_write(onkey->pf1550->regmap, + PF1550_PMIC_REG_ONKEY_INT_MASK0, + ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | + ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | + ONKEY_IRQ_8SI))); + } else { + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + virq = irq_find_mapping(domain, i); + + if (virq) + disable_irq_wake(virq); + } + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend, + pf1550_onkey_resume); + +static const struct platform_device_id pf1550_onkey_id[] = { + { "pf1550-onkey", PF1550 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, pf1550_onkey_id); + +static struct platform_driver pf1550_onkey_driver = { + .driver = { + .name = "pf1550-onkey", + .pm = &pf1550_onkey_pm_ops, + }, + .probe = pf1550_onkey_probe, + .id_table = pf1550_onkey_id, +}; +module_platform_driver(pf1550_onkey_driver); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_DESCRIPTION("PF1550 onkey Driver"); +MODULE_LICENSE("GPL"); From patchwork Tue May 27 22:25:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Kayode via B4 Relay X-Patchwork-Id: 893044 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 A1B9C218AD2; Tue, 27 May 2025 22:26:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; cv=none; b=PGijxTWUbUP1H3DRjiMH8Qcs55qmYWdbBT7j93qC98vK/clVuN+woXleEO3+vsKDDAqBP4GKKvxPjfk/in1oyVKpv3fIaTneefnYmMpUJwjASvLoYCEAcljdPYNHRGejMn7/N+qUrc4TKz60NhhGyiX5Oo0HI7IvGC7AO446paU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; c=relaxed/simple; bh=Eux9xrBUXlNsVUmBgroNk8YVwBcjHrhqiMJGrjkR+Eg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=q5OuPuPPZ2S0907lYve622do5YYzhy6gyYhSslUZUpH1ROxGvuHbzAhBghVbYwKcKTo20nxlLGbsBei4HUef+AHG3eWPIRtDtpXwgSfJunp49aHERKk4u6kTQN9K0SFyaKiZaqB+ojJEzH3QMaqiE5r6noQgEmzKzIJgLOAKgY4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=R1augIJ0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="R1augIJ0" Received: by smtp.kernel.org (Postfix) with ESMTPS id 0AC43C4CEF6; Tue, 27 May 2025 22:26:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748384785; bh=Eux9xrBUXlNsVUmBgroNk8YVwBcjHrhqiMJGrjkR+Eg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=R1augIJ0GkGF6i1RiwXqtPPmcsrDrH/wg2hRJ3Sn3UUq8skY1LqSAFDwYpN35VQc7 t6FRoTwJjI38Sr43bI0wCjuBsfZB0Vl+731yxsDaoyT7IQB1EItsW5hj/G5c/TAoW6 oAGwqr7K1ca9yKV5OziVzz6OkIc7EcZdG1n/NlpFzWNLGxxzO+wNotFshNHLsZ8GZa ZU0FpJoM9WkPUlJGimQdAse7x1LwNm7L9IqgXTGac0EFXXcdgVVS4pgO7I504oS8nK DMNCVmHAv4ZwvEnyGlsExZ8vQRLB3TIKsr9galrVlv0cJpXMLUjtdRMI+N6JThKrsm 82PfJHIu48bLQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id F290AC5B54E; Tue, 27 May 2025 22:26:24 +0000 (UTC) From: Samuel Kayode via B4 Relay Date: Tue, 27 May 2025 18:25:37 -0400 Subject: [PATCH v3 5/6] power: supply: pf1550: add battery charger support Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250527-pf1550-v3-5-45f69453cd51@savoirfairelinux.com> References: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> In-Reply-To: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Dmitry Torokhov , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, linux-pm@vger.kernel.org, Samuel Kayode , eballetbo@gmail.com, abelvesa@linux.com, b38343@freescale.com, yibin.gong@nxp.com, Abel Vesa X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1748384783; l=19262; i=samuel.kayode@savoirfairelinux.com; s=20250527; h=from:subject:message-id; bh=k/4Ly5H3ZRPVpfqWACRQHqDlpoKzXxlNvJysLFqCHnU=; b=R2wAriOOhsMfHVj4I6Cwxelggfp6AGT52e3Ou9qFBqvl3uyRuTEfIjijQLIM2u1nRCRP4dlg7 WdoUOAGLAY+CiO+GRtPogq+8+PolFZsngNKWUSwuDDWw2Ywd1+DMWng X-Developer-Key: i=samuel.kayode@savoirfairelinux.com; a=ed25519; pk=TPSQGQ5kywnnPyGs0EQqLajLFbdDu17ahXz8/gxMfio= X-Endpoint-Received: by B4 Relay for samuel.kayode@savoirfairelinux.com/20250527 with auth_id=412 X-Original-From: Samuel Kayode Reply-To: samuel.kayode@savoirfairelinux.com From: Samuel Kayode Add support for the battery charger for pf1550 PMIC. Signed-off-by: Samuel Kayode --- v3: - Use struct power_supply_get_battery_info to get constant charge voltage if specified - Use virqs mapped in MFD driver v2: - Address feedback from Enric Balletbo Serra --- drivers/power/supply/Kconfig | 11 + drivers/power/supply/Makefile | 1 + drivers/power/supply/pf1550-charger.c | 639 ++++++++++++++++++++++++++++++++++ 3 files changed, 651 insertions(+) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 8dbd39afa43cba67cddb0e8ca62e6e44d4864434..c262452dcecda5e1708bcc1290f67ca5dd19628a 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -449,6 +449,17 @@ config CHARGER_88PM860X help Say Y here to enable charger for Marvell 88PM860x chip. +config CHARGER_PF1550 + tristate "Freescale PF1550 battery charger driver" + depends on MFD_PF1550 + help + Say Y to enable support for the Freescale PF1550 battery charger. + The device is a single cell Li-Ion/Li-Polymer battery charger for + portable application. + + This driver can also be built as a module. If so, the module will be + called pf1550-charger. + config BATTERY_RX51 tristate "Nokia RX-51 (N900) battery driver" depends on TWL4030_MADC diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 61677be328b0cb1d31440a54b06e201dadfcda7b..6c6f1535bea7aeb7db159a268ff088e24ec617c4 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_CHARGER_RT9467) += rt9467-charger.o obj-$(CONFIG_CHARGER_RT9471) += rt9471.o obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o +obj-$(CONFIG_CHARGER_PF1550) += pf1550-charger.o obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o diff --git a/drivers/power/supply/pf1550-charger.c b/drivers/power/supply/pf1550-charger.c new file mode 100644 index 0000000000000000000000000000000000000000..2827b0321e266370aaa37ee697d45eeb63428c3f --- /dev/null +++ b/drivers/power/supply/pf1550-charger.c @@ -0,0 +1,639 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pf1550_charger.c - regulator driver for the PF1550 + * + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Robin Gong + */ + +#include +#include +#include +#include +#include + +#define PF1550_CHARGER_NAME "pf1550-charger" +#define PF1550_DEFAULT_CONSTANT_VOLT 4200000 +#define PF1550_DEFAULT_MIN_SYSTEM_VOLT 3500000 +#define PF1550_DEFAULT_THERMAL_TEMP 75 +#define PF1550_CHARGER_IRQ_NR 5 + +static const char *pf1550_charger_model = "PF1550"; +static const char *pf1550_charger_manufacturer = "Freescale"; + +struct pf1550_charger { + struct device *dev; + struct pf1550_dev *pf1550; + struct power_supply *charger; + struct power_supply_desc psy_desc; + int irq; + struct delayed_work irq_work; + struct mutex mutex; + + u32 constant_volt; + u32 min_system_volt; + u32 thermal_regulation_temp; +}; + +static int pf1550_get_charger_state(struct regmap *regmap, int *val) +{ + int ret; + unsigned int data; + + ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data); + if (ret < 0) + return ret; + + data &= PF1550_CHG_SNS_MASK; + + switch (data) { + case PF1550_CHG_PRECHARGE: + case PF1550_CHG_CONSTANT_CURRENT: + *val = POWER_SUPPLY_STATUS_CHARGING; + break; + case PF1550_CHG_CONSTANT_VOL: + *val = POWER_SUPPLY_STATUS_CHARGING; + break; + case PF1550_CHG_EOC: + *val = POWER_SUPPLY_STATUS_CHARGING; + break; + case PF1550_CHG_DONE: + *val = POWER_SUPPLY_STATUS_FULL; + break; + case PF1550_CHG_TIMER_FAULT: + case PF1550_CHG_SUSPEND: + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case PF1550_CHG_OFF_INV: + case PF1550_CHG_OFF_TEMP: + case PF1550_CHG_LINEAR_ONLY: + *val = POWER_SUPPLY_STATUS_DISCHARGING; + break; + default: + *val = POWER_SUPPLY_STATUS_UNKNOWN; + } + + return 0; +} + +static int pf1550_get_charge_type(struct regmap *regmap, int *val) +{ + int ret; + unsigned int data; + + ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data); + if (ret < 0) + return ret; + + data &= PF1550_CHG_SNS_MASK; + + switch (data) { + case PF1550_CHG_SNS_MASK: + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case PF1550_CHG_CONSTANT_CURRENT: + case PF1550_CHG_CONSTANT_VOL: + case PF1550_CHG_EOC: + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case PF1550_CHG_DONE: + case PF1550_CHG_TIMER_FAULT: + case PF1550_CHG_SUSPEND: + case PF1550_CHG_OFF_INV: + case PF1550_CHG_BAT_OVER: + case PF1550_CHG_OFF_TEMP: + case PF1550_CHG_LINEAR_ONLY: + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + default: + *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + } + + return 0; +} + +/* + * Supported health statuses: + * - POWER_SUPPLY_HEALTH_DEAD + * - POWER_SUPPLY_HEALTH_GOOD + * - POWER_SUPPLY_HEALTH_OVERVOLTAGE + * - POWER_SUPPLY_HEALTH_UNKNOWN + */ +static int pf1550_get_battery_health(struct regmap *regmap, int *val) +{ + int ret; + unsigned int data; + + ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data); + if (ret < 0) + return ret; + + data &= PF1550_BAT_SNS_MASK; + + switch (data) { + case PF1550_BAT_NO_DETECT: + *val = POWER_SUPPLY_HEALTH_DEAD; + break; + case PF1550_BAT_NO_VBUS: + case PF1550_BAT_LOW_THAN_PRECHARG: + case PF1550_BAT_CHARG_FAIL: + case PF1550_BAT_HIGH_THAN_PRECHARG: + *val = POWER_SUPPLY_HEALTH_GOOD; + break; + case PF1550_BAT_OVER_VOL: + *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + break; + default: + *val = POWER_SUPPLY_HEALTH_UNKNOWN; + break; + } + + return 0; +} + +static int pf1550_get_present(struct regmap *regmap, int *val) +{ + unsigned int data; + int ret; + + ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data); + if (ret < 0) + return ret; + + data &= PF1550_BAT_SNS_MASK; + *val = (data == PF1550_BAT_NO_DETECT) ? 0 : 1; + + return 0; +} + +static int pf1550_get_online(struct regmap *regmap, int *val) +{ + unsigned int data; + int ret; + + ret = regmap_read(regmap, PF1550_CHARG_REG_VBUS_SNS, &data); + if (ret < 0) + return ret; + + *val = (data & PF1550_VBUS_VALID) ? 1 : 0; + + return 0; +} + +static void pf1550_chg_bat_isr(struct pf1550_charger *chg) +{ + unsigned int data; + + if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_BATT_SNS, &data)) { + dev_err(chg->dev, "Read BATT_SNS error.\n"); + return; + } + + switch (data & PF1550_BAT_SNS_MASK) { + case PF1550_BAT_NO_VBUS: + dev_dbg(chg->dev, "No valid VBUS input.\n"); + break; + case PF1550_BAT_LOW_THAN_PRECHARG: + dev_dbg(chg->dev, "VBAT < VPRECHG.LB.\n"); + break; + case PF1550_BAT_CHARG_FAIL: + dev_dbg(chg->dev, "Battery charging failed.\n"); + break; + case PF1550_BAT_HIGH_THAN_PRECHARG: + dev_dbg(chg->dev, "VBAT > VPRECHG.LB.\n"); + break; + case PF1550_BAT_OVER_VOL: + dev_dbg(chg->dev, "VBAT > VBATOV.\n"); + break; + case PF1550_BAT_NO_DETECT: + dev_dbg(chg->dev, "Battery not detected.\n"); + break; + default: + dev_err(chg->dev, "Unknown value read:%x\n", + data & PF1550_CHG_SNS_MASK); + } +} + +static void pf1550_chg_chg_isr(struct pf1550_charger *chg) +{ + unsigned int data; + + if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_SNS, &data)) { + dev_err(chg->dev, "Read CHG_SNS error.\n"); + return; + } + + switch (data & PF1550_CHG_SNS_MASK) { + case PF1550_CHG_PRECHARGE: + dev_dbg(chg->dev, "In pre-charger mode.\n"); + break; + case PF1550_CHG_CONSTANT_CURRENT: + dev_dbg(chg->dev, "In fast-charge constant current mode.\n"); + break; + case PF1550_CHG_CONSTANT_VOL: + dev_dbg(chg->dev, "In fast-charge constant voltage mode.\n"); + break; + case PF1550_CHG_EOC: + dev_dbg(chg->dev, "In EOC mode.\n"); + break; + case PF1550_CHG_DONE: + dev_dbg(chg->dev, "In DONE mode.\n"); + break; + case PF1550_CHG_TIMER_FAULT: + dev_info(chg->dev, "In timer fault mode.\n"); + break; + case PF1550_CHG_SUSPEND: + dev_info(chg->dev, "In thermistor suspend mode.\n"); + break; + case PF1550_CHG_OFF_INV: + dev_info(chg->dev, "Input invalid, charger off.\n"); + break; + case PF1550_CHG_BAT_OVER: + dev_info(chg->dev, "Battery over-voltage.\n"); + break; + case PF1550_CHG_OFF_TEMP: + dev_info(chg->dev, "Temp high, charger off.\n"); + break; + case PF1550_CHG_LINEAR_ONLY: + dev_dbg(chg->dev, "In Linear mode, not charging.\n"); + break; + default: + dev_err(chg->dev, "Unknown value read:%x\n", + data & PF1550_CHG_SNS_MASK); + } +} + +static void pf1550_chg_vbus_isr(struct pf1550_charger *chg) +{ + enum power_supply_type old_type; + unsigned int data; + + if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS, &data)) { + dev_err(chg->dev, "Read VBUS_SNS error.\n"); + return; + } + + old_type = chg->psy_desc.type; + + if (data & PF1550_VBUS_UVLO) { + chg->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; + dev_dbg(chg->dev, "VBUS deattached.\n"); + } + if (data & PF1550_VBUS_IN2SYS) + dev_dbg(chg->dev, "VBUS_IN2SYS_SNS.\n"); + if (data & PF1550_VBUS_OVLO) + dev_dbg(chg->dev, "VBUS_OVLO_SNS.\n"); + if (data & PF1550_VBUS_VALID) { + chg->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; + dev_dbg(chg->dev, "VBUS attached.\n"); + } + + if (old_type != chg->psy_desc.type) + power_supply_changed(chg->charger); +} + +static irqreturn_t pf1550_charger_irq_handler(int irq, void *data) +{ + struct pf1550_charger *chg = data; + + chg->irq = irq; + + schedule_delayed_work(&chg->irq_work, msecs_to_jiffies(10)); + + return IRQ_HANDLED; +} + +static void pf1550_charger_irq_work(struct work_struct *work) +{ + struct pf1550_charger *chg = container_of(to_delayed_work(work), + struct pf1550_charger, + irq_work); + struct irq_domain *domain; + int i, irq_type = -1; + unsigned int virq; + unsigned int status; + + if (!chg->charger) + return; + + domain = regmap_irq_get_domain(chg->pf1550->irq_data_charger); + if (!domain) + return; + + mutex_lock(&chg->mutex); + + for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) { + virq = irq_find_mapping(domain, i); + if (chg->irq == virq) + irq_type = i; + } + + switch (irq_type) { + case PF1550_CHARG_IRQ_BAT2SOCI: + dev_info(chg->dev, "BAT to SYS Overcurrent interrupt.\n"); + break; + case PF1550_CHARG_IRQ_BATI: + pf1550_chg_bat_isr(chg); + break; + case PF1550_CHARG_IRQ_CHGI: + pf1550_chg_chg_isr(chg); + break; + case PF1550_CHARG_IRQ_VBUSI: + pf1550_chg_vbus_isr(chg); + break; + case PF1550_CHARG_IRQ_THMI: + dev_info(chg->dev, "Thermal interrupt.\n"); + break; + default: + dev_err(chg->dev, "unknown interrupt occurred.\n"); + } + + if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT, &status)) + dev_err(chg->dev, "Read CHG_INT error.\n"); + if (regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT, status)) + dev_err(chg->dev, "clear CHG_INT error.\n"); + + mutex_unlock(&chg->mutex); +} + +static enum power_supply_property pf1550_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static int pf1550_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pf1550_charger *chg = power_supply_get_drvdata(psy); + struct regmap *regmap = chg->pf1550->regmap; + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + ret = pf1550_get_charger_state(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + ret = pf1550_get_charge_type(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_HEALTH: + ret = pf1550_get_battery_health(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_PRESENT: + ret = pf1550_get_present(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_ONLINE: + ret = pf1550_get_online(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = pf1550_charger_model; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = pf1550_charger_manufacturer; + break; + default: + return -EINVAL; + } + + return ret; +} + +static int pf1550_set_constant_volt(struct pf1550_charger *chg, + unsigned int uvolt) +{ + unsigned int data; + + if (uvolt >= 3500000 && uvolt <= 4440000) + data = 8 + (uvolt - 3500000) / 20000; + else + return dev_err_probe(chg->dev, -EINVAL, + "Wrong value for constant voltage\n"); + + dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt, + data); + + return regmap_update_bits(chg->pf1550->regmap, + PF1550_CHARG_REG_BATT_REG, + PF1550_CHARG_REG_BATT_REG_CHGCV_MASK, data); +} + +static int pf1550_set_min_system_volt(struct pf1550_charger *chg, + unsigned int uvolt) +{ + unsigned int data; + + switch (uvolt) { + case 3500000: + data = 0x0; + break; + case 3700000: + data = 0x1; + break; + case 4300000: + data = 0x2; + break; + default: + return dev_err_probe(chg->dev, -EINVAL, + "Wrong value for minimum system voltage\n"); + } + + data <<= PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT; + + dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n", + uvolt, data); + + return regmap_update_bits(chg->pf1550->regmap, + PF1550_CHARG_REG_BATT_REG, + PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK, data); +} + +static int pf1550_set_thermal_regulation_temp(struct pf1550_charger *chg, + unsigned int cels) +{ + unsigned int data; + + switch (cels) { + case 60: + data = 0x0; + break; + case 75: + data = 0x1; + break; + case 90: + data = 0x2; + break; + case 105: + data = 0x3; + break; + default: + return dev_err_probe(chg->dev, -EINVAL, + "Wrong value for thermal temperature\n"); + } + + data <<= PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT; + + dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n", + cels, data); + + return regmap_update_bits(chg->pf1550->regmap, + PF1550_CHARG_REG_THM_REG_CNFG, + PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK, + data); +} + +/* + * Sets charger registers to proper and safe default values. + */ +static int pf1550_reg_init(struct pf1550_charger *chg) +{ + struct device *dev = chg->dev; + int ret; + unsigned int data; + + /* Unmask charger interrupt, mask DPMI and reserved bit */ + ret = regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT_MASK, + PF1550_CHG_INT_MASK); + if (ret) + return dev_err_probe(dev, ret, + "Error unmask charger interrupt\n"); + + ret = regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS, + &data); + if (ret) + return dev_err_probe(dev, ret, "Read charg vbus_sns error\n"); + + if (data & PF1550_VBUS_VALID) + chg->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; + + ret = pf1550_set_constant_volt(chg, chg->constant_volt); + if (ret) + return ret; + + ret = pf1550_set_min_system_volt(chg, chg->min_system_volt); + if (ret) + return ret; + + ret = pf1550_set_thermal_regulation_temp(chg, + chg->thermal_regulation_temp); + if (ret) + return ret; + + /* Turn on charger */ + ret = regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_OPER, + PF1550_CHG_TURNON); + if (ret) + return dev_err_probe(dev, ret, "Error turn on charger\n"); + + return 0; +} + +static void pf1550_dt_parse_dev_info(struct pf1550_charger *chg) +{ + struct device *dev = chg->dev; + struct power_supply_battery_info *info; + + power_supply_get_battery_info(chg->charger, &info); + + if (!info || !info->constant_charge_voltage_max_uv) + chg->constant_volt = PF1550_DEFAULT_CONSTANT_VOLT; + + if (device_property_read_u32(dev->parent, "fsl,min-system-microvolt", + &chg->min_system_volt)) + chg->min_system_volt = PF1550_DEFAULT_MIN_SYSTEM_VOLT; + + if (device_property_read_u32(dev->parent, "fsl,thermal-regulation", + &chg->thermal_regulation_temp)) + chg->thermal_regulation_temp = PF1550_DEFAULT_THERMAL_TEMP; +} + +static int pf1550_charger_probe(struct platform_device *pdev) +{ + struct pf1550_charger *chg; + struct power_supply_config psy_cfg = {}; + struct pf1550_dev *pf1550 = dev_get_drvdata(pdev->dev.parent); + struct irq_domain *domain; + int i, ret; + + chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); + if (!chg) + return -ENOMEM; + + chg->dev = &pdev->dev; + chg->pf1550 = pf1550; + + if (!chg->pf1550->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "failed to get regmap\n"); + + platform_set_drvdata(pdev, chg); + + mutex_init(&chg->mutex); + + INIT_DELAYED_WORK(&chg->irq_work, pf1550_charger_irq_work); + + domain = regmap_irq_get_domain(pf1550->irq_data_charger); + + for (i = 0; i < PF1550_CHARGER_IRQ_NR; i++) { + unsigned int virq = irq_find_mapping(domain, i); + + ret = devm_request_threaded_irq(&pdev->dev, virq, NULL, + pf1550_charger_irq_handler, + IRQF_NO_SUSPEND, + "pf1550-charger", chg); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed irq request\n"); + } + + psy_cfg.drv_data = chg; + + chg->psy_desc.name = PF1550_CHARGER_NAME; + chg->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY; + chg->psy_desc.get_property = pf1550_charger_get_property; + chg->psy_desc.properties = pf1550_charger_props; + chg->psy_desc.num_properties = ARRAY_SIZE(pf1550_charger_props); + + chg->charger = devm_power_supply_register(&pdev->dev, &chg->psy_desc, + &psy_cfg); + if (IS_ERR(chg->charger)) + return dev_err_probe(&pdev->dev, PTR_ERR(chg->charger), + "failed: power supply register\n"); + + pf1550_dt_parse_dev_info(chg); + + ret = pf1550_reg_init(chg); + + return ret; +} + +static void pf1550_charger_remove(struct platform_device *pdev) +{ + struct pf1550_charger *chg = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&chg->irq_work); +} + +static const struct platform_device_id pf1550_charger_id[] = { + { "pf1550-charger", PF1550 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, pf1550_charger_id); + +static struct platform_driver pf1550_charger_driver = { + .driver = { + .name = "pf1550-charger", + }, + .probe = pf1550_charger_probe, + .remove = pf1550_charger_remove, + .id_table = pf1550_charger_id, +}; +module_platform_driver(pf1550_charger_driver); + +MODULE_AUTHOR("Robin Gong "); +MODULE_DESCRIPTION("PF1550 charger driver"); +MODULE_LICENSE("GPL"); From patchwork Tue May 27 22:25:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Samuel Kayode via B4 Relay X-Patchwork-Id: 892849 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 C7E2E219307; Tue, 27 May 2025 22:26:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; cv=none; b=VKU8PSmIn7dJoZrNMahRtAok+8/C+/gnS9R3YPU0mKjiRMx94IggknZZqnNFI+c/Jed0xjOYgM3C8hJ3mIRWB7EvZ9SBK68diN8LG3GjNIR2nJejEjd2jFG1Tu5mJgj22jamCBZq7VbK7bgpbAs5WUI9omvaomv34LnoVyBtaOQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748384785; c=relaxed/simple; bh=zRmRsJT6zhzDSuXbgOvOnJhhy3nPlwowYHwtO5D0rxY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fm8CxduPV4XU9BDRfE+Wt4ruNmARXAKrqHDOpmSH5qYkU1udaGSVzwIkoYrHXBUbJEuxZojzukrEy97nchpG/tdhqsCDgj5ekc8W1SuqMrerbgoJRImt6hjxh6Ai591eqSljZ/VN/qv972qPqrui5Znc+Vu3G1Upc6hvfkhGP6g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hLMSalmk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hLMSalmk" Received: by smtp.kernel.org (Postfix) with ESMTPS id 1CA8AC4CEF9; Tue, 27 May 2025 22:26:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1748384785; bh=zRmRsJT6zhzDSuXbgOvOnJhhy3nPlwowYHwtO5D0rxY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=hLMSalmkULYK2vdY3477xLMhfHSkQHSZ+Gor8HRAXuUZHyK/LVeZ1bcun6O/6uJRw UddWzglc3/rSWSGujxmUs+ttJs4D/lHYBy6LIcMo1EU9fNMXBM96+dtWVXJjR95MIw rEhGoOM5ECr+8awiD+sU9q2p+IqdyU27I6T9Q+O5rBKRqjV+g+t1IQYqcJzhAUPCQd 7erBcdrzvAFaOWmEiT+Q1xobk7uFfOc2wiI+EaIxm9MoO9dRKl4FRtLqFcyorAqPbU RyBkx6sUasrVeoe5nAJ2U8GIrVewUUHla0r56f/j49auBRmyenOF0CJoPuxuUF9U7q 1tTVijC01Fcvg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 12927C5B543; Tue, 27 May 2025 22:26:25 +0000 (UTC) From: Samuel Kayode via B4 Relay Date: Tue, 27 May 2025 18:25:38 -0400 Subject: [PATCH v3 6/6] MAINTAINERS: add an entry for pf1550 mfd driver Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250527-pf1550-v3-6-45f69453cd51@savoirfairelinux.com> References: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> In-Reply-To: <20250527-pf1550-v3-0-45f69453cd51@savoirfairelinux.com> To: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Dmitry Torokhov , Sebastian Reichel Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, linux-pm@vger.kernel.org, Samuel Kayode , eballetbo@gmail.com, abelvesa@linux.com, b38343@freescale.com, yibin.gong@nxp.com, Abel Vesa X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1748384783; l=966; i=samuel.kayode@savoirfairelinux.com; s=20250527; h=from:subject:message-id; bh=P6wBCq9GpDy9ARq/1XDkixCcTLLaGUgI/CZwwZXFs4U=; b=CMM65Np1ztt3CDZ3fr0531DlK7o56shRW0QR18RIdCbHunxQHohl+CRzQyfw4eqtad36pcNA4 phTgtEvDAJqAacrrbw5sE8JntLuWRivHi1X8f9j+5lqHuUJf59VCn1x X-Developer-Key: i=samuel.kayode@savoirfairelinux.com; a=ed25519; pk=TPSQGQ5kywnnPyGs0EQqLajLFbdDu17ahXz8/gxMfio= X-Endpoint-Received: by B4 Relay for samuel.kayode@savoirfairelinux.com/20250527 with auth_id=412 X-Original-From: Samuel Kayode Reply-To: samuel.kayode@savoirfairelinux.com From: Samuel Kayode Add MAINTAINERS entry for pf1550 PMIC. Signed-off-by: Samuel Kayode Reviewed-by: Krzysztof Kozlowski --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 830ef5f9d86487a599236a2392e422f0e424a313..2be65383c3c7b1c1487577d23bff483aa437c4c8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17688,6 +17688,16 @@ F: Documentation/devicetree/bindings/clock/imx* F: drivers/clk/imx/ F: include/dt-bindings/clock/imx* +NXP PF1550 PMIC MFD DRIVER +M: Samuel Kayode +S: Maintained +F: Documentation/devicetree/bindings/mfd/pf1550.yaml +F: drivers/input/misc/pf1550-onkey.c +F: drivers/mfd/pf1550.c +F: drivers/power/supply/pf1550-charger.c +F: drivers/regulator/pf1550-regulator.c +F: include/linux/mfd/pfd1550.h + NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER M: Jagan Teki S: Maintained