From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-181.mta1.migadu.com (out-181.mta1.migadu.com [95.215.58.181]) (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 26DE548124D for ; Wed, 1 Jul 2026 12:43:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.181 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782909820; cv=none; b=gUytGHYTrTvUIC/KJxQXUs+rgzNGn7s5KzhQxydIzTJKVyzHeHu9trAq1QvNBX+rRBax6bmbHL9JtCjXv8VxIJx9TmMLp2Yb0laUzEGNi/R/gkAmYLjZsdbbD7jr2bHMgHkOfP1HDVtb28YQXAESvs0VGm9dtmcn3CjIvmDkS70= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782909820; c=relaxed/simple; bh=pn6zxE+1WTiIFDxKh0I4LdacUkL70hhw0eyXPcK4PLs=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=YRFwjrn007aiCsRx56W/6RJ1DHBO0qDCDpnZ1jTyAcr7LPL8EeAlDmeDTL9hPZlHFtJdVRRQqaeSPI41/1ZEwWP/PfYvr0WGT70w0Lic8/DTtaYjU/DTRmf8UASZda4lp70Udf9Zap26w1vcq3xZTrO1fcYawZm6hiub5cwdSto= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=wD2z95S5; arc=none smtp.client-ip=95.215.58.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="wD2z95S5" Date: Wed, 1 Jul 2026 15:43:25 +0300 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1782909817; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references; bh=esSpBPhemXLnxs/Q2OuNPPMcw6p09Lrxem7J48IXO1E=; b=wD2z95S5xOjRehAaNAfz/DkRjgURwm4Zeb98hYHXLNLOkOlRhZv1LL++86VNNZXiXDqTUo xT17vMCFSaSq3YcYEVFIBqvTD7KJW639PuCnxvLE+P9vEMDXFCvWTtO0MRp+l2jp5Cp3iF PggnuLGFee/oo6a7fRa0/tye1ly8l6w= X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Matti Vaittinen To: Matti Vaittinen , Matti Vaittinen , Matti Vaittinen Cc: Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Liam Girdwood , Mark Brown , Matti Vaittinen , Michael Turquette , Stephen Boyd , Brian Masney , Linus Walleij , Bartosz Golaszewski , Alexandre Belloni , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-clk@vger.kernel.org, linux-gpio@vger.kernel.org, linux-rtc@vger.kernel.org Subject: [PATCH 7/8] gpio: bd73800: Support ROHM BD73800 PMIC GPIOs Message-ID: <27fb93d0e61704d495e3adf4ed614edac1642267.1782909323.git.mazziesaccount@gmail.com> Reply-To: Matti Vaittinen References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="uokM9BT9+b3KyMQa" Content-Disposition: inline In-Reply-To: X-Migadu-Flow: FLOW_OUT --uokM9BT9+b3KyMQa Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable =46rom: Matti Vaittinen The ROHM BD73800 PMIC has 4 pins (named GPIO1, CLKOUT, FAULT_B and EXTEN_OUT) which might have been set to operate as a GPI or GPO when OTP (One Time Programmable memory) is written at device manufacturing. Support the GPI/GPO use-case via GPIO framework. The default OTP for these pins is to not use any of them as GPI or GPO. (The GPIO1 defaults as an ADC input regardless the naming). Hence the driver assumes none of these pins is a GPI/GPO unless explicitly pointed as GPI or GPO via device tree. Furthermore, pin's direction can't be changed after OTP configuration is done. Also the default drive type for a GPO (CMOS / Open Drain) is set by the OTP configuration. The BD73800 has a set of undocumented test registers which should allow changing the drive type. Access to the test register area or the test registers aren't documented and so this driver does not support configuring the drive type even though it might be doable. Signed-off-by: Matti Vaittinen --- drivers/gpio/Kconfig | 11 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-bd73800.c | 234 ++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/gpio/gpio-bd73800.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 28cf6d2e83c2..09d87c3b756f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1363,6 +1363,17 @@ config GPIO_BD72720 be configured to GPO on the ROHM PMIC. The pin configuration is done on OTP at manufacturing. =20 +config GPIO_BD73800 + tristate "ROHM BD73800 GPIO support" + depends on MFD_ROHM_BD71828 + help + Support for GPIOs on ROHM BD73800 PMIC. There can be up to 4 + GPI or GPO pins available on the PMIC in total. The purpose of + the pins is decided at the device manufacturing by OTP + configuration and can't be reconfigured later. Enable this + if your PMIC has pins set as GPIs or GPOs and if you wish to + control the pins via the GPIO framework. + config GPIO_BD9571MWV tristate "ROHM BD9571 GPIO support" depends on MFD_BD9571MWV diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4d0e900402fc..3041c06aa933 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BCM_XGS_IPROC) +=3D gpio-xgs-iproc.o obj-$(CONFIG_GPIO_BD71815) +=3D gpio-bd71815.o obj-$(CONFIG_GPIO_BD71828) +=3D gpio-bd71828.o obj-$(CONFIG_GPIO_BD72720) +=3D gpio-bd72720.o +obj-$(CONFIG_GPIO_BD73800) +=3D gpio-bd73800.o obj-$(CONFIG_GPIO_BD9571MWV) +=3D gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BLZP1600) +=3D gpio-blzp1600.o obj-$(CONFIG_GPIO_BRCMSTB) +=3D gpio-brcmstb.o diff --git a/drivers/gpio/gpio-bd73800.c b/drivers/gpio/gpio-bd73800.c new file mode 100644 index 000000000000..3fe4b7f167b8 --- /dev/null +++ b/drivers/gpio/gpio-bd73800.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support to GPIOs on ROHM BD73800 + * Copyright 2024 ROHM Semiconductors. + * Author: Matti Vaittinen + */ + +#include +#include +#include +#include +#include +#include +#include + +#define BD73800_GPIO_MAX_PINS 4 +/* + * The BD73800 has several "one time programmable" (OTP) configurations wh= ich + * can be set at manufacturing phase. Some of these options allow using + * individual pins as GPI or GPO (not both at the same time). The OTP + * configuration can't be read at run-time, so drivers rely on device-tree= to + * advertise the OTP programmed in manufacturing. + * + * The pins which can be used as GPIO are: + * GPIO1, CLKOUT (GPIO2), FAULT_B, EXTEN_OUT. + * + * The OTP options 2 and 3 state for all the pins: + * - OTP2: GPI (also IRQ source) + * - OTP3: GPO (NOTE: This is actually 2 different OTP options. Either a + * register controllable output or a power-sequence controlled output. + * The "gpo" referred here means only the register controllable output. + * The datasheet refers to this as: " output is controlled by + * GPIO_OUT or power on/off sequencer to control external VRs. ON/OFF + * sequence timing is configurable." + * + * The data-sheet further says that the GPI/GPO is not a default OTP + * configuration for any of the pins. Hence the GPIO driver defaults to a = pin + * not being a GPI or GPO, but requires the pin to be explicitly marked as= a + * GPI or GPO in the device-tree. + * + * DT properties: + * "rohm,pin-gpio1", "rohm,pin-clkout", "rohm,pin-fault-b", "rohm,pin-exte= n" + * can be set to one of the values "gpi" or "gpo" to enable them to be use= d as + * GPIO. + */ + +enum bd73800_gpio_state { + BD73800_PIN_UNKNOWN, + BD73800_PIN_GPI, + BD73800_PIN_GPO, +}; + +struct bd73800_gpio_pin_cfg { + enum bd73800_gpio_state state; + int mask; /* GPIO_OUT and INT_SRC have same bit offsets for GPIO */ +}; + +struct bd73800_gpio { + /* chip.parent points the MFD which provides DT node and regmap */ + struct gpio_chip chip; + struct bd73800_gpio_pin_cfg pin[BD73800_GPIO_MAX_PINS]; + int num_pins; + /* dev points to the platform device for devm and prints */ + struct device *dev; + struct regmap *regmap; +}; + +static int bd73800_gpio_get_pins(struct bd73800_gpio *g) +{ + static const char * const properties[] =3D {"rohm,pin-gpio1", + "rohm,pin-clkout", "rohm,pin-fault-b", "rohm,pin-exten"}; + const char *val; + int i, ret; + + for (i =3D 0; i < ARRAY_SIZE(properties); i++) { + ret =3D fwnode_property_read_string(dev_fwnode(g->dev->parent), + properties[i], &val); + + if (ret) { + if (ret =3D=3D -EINVAL) + continue; + + return dev_err_probe(g->dev, ret, + "pin %d (%s), bad configuration\n", i, + properties[i]); + } + + if (strcmp(val, "gpi") =3D=3D 0) { + g->pin[g->num_pins].state =3D BD73800_PIN_GPI; + g->pin[g->num_pins].mask =3D BIT(i); + g->num_pins++; + } else if (strcmp(val, "gpo") =3D=3D 0) { + g->pin[g->num_pins].state =3D BD73800_PIN_GPO; + g->pin[g->num_pins].mask =3D BIT(i); + g->num_pins++; + } + } + + return 0; +} + +static int bd73800gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct bd73800_gpio *bdgpio =3D gpiochip_get_data(chip); + struct bd73800_gpio_pin_cfg *pin =3D &bdgpio->pin[offset]; + int ret, val; + + /* Only pins configured as GPI via OTP can have their status read */ + if (pin->state !=3D BD73800_PIN_GPI) { + dev_dbg(bdgpio->dev, "pin %d (%x) not input. State %d\n", + offset, pin->mask, pin->state); + return -EINVAL; + } + + ret =3D regmap_read(bdgpio->regmap, BD73800_REG_INT_5_SRC, &val); + if (ret) + return ret; + + return val & pin->mask; +} + +static int bd73800gpo_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct bd73800_gpio *bdgpio =3D gpiochip_get_data(chip); + struct bd73800_gpio_pin_cfg *pin =3D &bdgpio->pin[offset]; + + if (pin->state !=3D BD73800_PIN_GPO) { + dev_dbg(bdgpio->dev, "pin %d (%d) not output. State %d\n", + offset, pin->mask, pin->state); + + return -EINVAL; + } + + if (value) + return regmap_set_bits(bdgpio->regmap, BD73800_REG_GPO_OUT, + pin->mask); + + return regmap_clear_bits(bdgpio->regmap, BD73800_REG_GPO_OUT, pin->mask); +} + +static int bd73800gpio_direction_get(struct gpio_chip *chip, + unsigned int offset) +{ + struct bd73800_gpio *bdgpio =3D gpiochip_get_data(chip); + + if (bdgpio->pin[offset].state =3D=3D BD73800_PIN_GPO) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +/* + * Template for GPIO chip. The BD73800 GPO supports both CMOS and open dra= in + * configurations. The default however depends on the OTP. The runtime con= fig + * can be done via undocumented test registers - but at the moment there i= s no + * support for this. + * + * NOTE: When the BD73800 GPIO pins are used as IRQ source, the users are + * expected to request them directly from the regmap_irq IRQ-chip (impleme= nted + * in the MFD driver). This way we don't need to populate another IRQ-chip + * here. + */ +static const struct gpio_chip bd73800gpio_chip =3D { + .label =3D "bd73800", + .owner =3D THIS_MODULE, + .get =3D bd73800gpio_get, + .get_direction =3D bd73800gpio_direction_get, + .set =3D bd73800gpo_set, + .can_sleep =3D true, +}; + +static int gpo_bd73800_probe(struct platform_device *pdev) +{ + struct bd73800_gpio *g; + struct device *parent, *dev; + int ret; + + /* + * Bind devm lifetime to this platform device =3D> use dev for devm. + * also the prints should originate from this device. + */ + dev =3D &pdev->dev; + /* The device-tree and regmap come from MFD =3D> use parent for that */ + parent =3D dev->parent; + + g =3D devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); + if (!g) + return -ENOMEM; + + g->chip =3D bd73800gpio_chip; + g->chip.base =3D -1; + g->chip.parent =3D parent; + g->regmap =3D dev_get_regmap(parent, NULL); + g->dev =3D dev; + + ret =3D bd73800_gpio_get_pins(g); + if (ret) + return ret; + + if (!g->num_pins) { + /* + * The BD73800 may or may not have pins allocated for GPIO + * depending on the OTP used at manufacturing. Free the memory + * and go out if there is no pins as then we have nothing to do + */ + dev_dbg(dev, "no GPIO pins\n"); + devm_kfree(dev, g); + return 0; + } + g->chip.ngpio =3D g->num_pins; + + return devm_gpiochip_add_data(dev, &g->chip, g); +} + +static const struct platform_device_id bd73800_gpio_id[] =3D { + { "bd73800-gpio" }, + { }, +}; +MODULE_DEVICE_TABLE(platform, bd73800_gpio_id); + +static struct platform_driver gpo_bd73800_driver =3D { + .driver =3D { + .name =3D "bd73800-gpio", + .probe_type =3D PROBE_PREFER_ASYNCHRONOUS, + }, + .probe =3D gpo_bd73800_probe, + .id_table =3D bd73800_gpio_id, +}; +module_platform_driver(gpo_bd73800_driver); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("GPIO interface for BD73800"); +MODULE_LICENSE("GPL"); --=20 2.54.0 --uokM9BT9+b3KyMQa Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQEzBAEBCgAdFiEEIx+f8wZb28fLKEhTeFA3/03aocUFAmpFC20ACgkQeFA3/03a ocW1Ngf/Yk0OtsGCFeTf599j2YARt4yJqPbniANCLnLbvDwGYqB28R9hfxNU7/Tp QkYFO+raWpPLL0sadBleGeAwS0O5q2GrrVn4HU31/k3ff30DaGkBoiIXC8SBJh3R G+0dtIHtf1unnvt4UZvpu98etHvd1Boz3iCNtekcUyxraIioFco/v7boHO9IfhBS UXqtxoTVOSDl4Kt/EiBHL1mzQF6Q9/me1nQd3eQzx7KvJ8lYnwAkGYY88pd87hBJ BQkjro4gYmCbSTpvVEpKLoPB8VMOqNaK6g2ybU0DOJHSz3O2yzbz80zIc2leudmI 8aHhZ4u2KdWZi4ims0dncKDa8sQ51A== =DkN/ -----END PGP SIGNATURE----- --uokM9BT9+b3KyMQa--