From nobody Fri Dec 19 15:50:24 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 5D8D0331A48 for ; Thu, 6 Nov 2025 14:11:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438319; cv=none; b=JXl0tmMGwHUklbQxGoGZgcJv3i+Ru4WcTfQyDfLfwXHwmm0gJ70Jsg4aRJhFnh5sWLT/9eiYCTjhAHzk81DdbBCfUFnETIhbyySQepZ/D+vlIWyAXDpwxNuxfBjjJ98xqrxU+qnLgARZPTojGvoAcsnGMWpljK/c9pJqDLsuS4I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438319; c=relaxed/simple; bh=XpqlKZjHzTmLvSm+nckycnojsWHa2lg6Y8cnK210Lcs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jqPe5GY5PWK+atbfVZ7XxAIpb+99nON4GvZlV8jjeXScY7PkBbwEb4VqL60QyR+I7ghUPeFJwPi5QP8ryFKLCgwghGOy2iQjVQECvdGKDKOXVjS+p+Hu3XLJZ7KQSsjs/zJTaqLJZK4t9l+pNUCK36RjMvh/ZVDBpKOVZbreO64= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=kXON5HZH; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="kXON5HZH" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id A51944E4156D; Thu, 6 Nov 2025 14:11:55 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 7749B6068C; Thu, 6 Nov 2025 14:11:55 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 6AF4911850DB9; Thu, 6 Nov 2025 15:11:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1762438314; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=EqLXomScIwCFlw0WQOWiUhZrnkDjdcW4X0TXbsmBNvk=; b=kXON5HZHPf88h52xYRb3H1sdlItjIRnVAM7+0l2TId6S/9F9CsikxG+kbScyc7HCUja3T5 3p5d4HanXI3quqJYNHuzO6Uaah0LtT/6ex2v545D9hKIIT8siEW5Wb/q2rruxVjcMrHgzw 2KXzI3ydlFaHmzFBWMPpGvEcIwXbKqo6kn3pgDSvw5puZEoyVOmPdQ4rkghiYfecFuluGG zcVTnVt65fU6a9m1B5a40nSMBKbToKZn5FOyEfp8EEKpYeiA3u5E8kbcHoMFeofNWOPxdk zLLZOBPu2ZQIiDhSd3d+Q4eISbuhH3EoP12rLNExYqbXRcXBxSgOvckE5CEl6A== From: Romain Gantois Date: Thu, 06 Nov 2025 15:11:46 +0100 Subject: [PATCH v3 1/5] regulator: dt-bindings: Add Linear Technology LTM8054 regulator Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251106-ltm8054-driver-v3-1-fd1feae0f65a@bootlin.com> References: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> In-Reply-To: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko Cc: Hans de Goede , Thomas Petazzoni , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-iio@vger.kernel.org, Romain Gantois X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 The Linear Technology LTM8054 is a Buck-Boost voltage regulator with an input range of 5V to 36V and an output range of 1.2V to 36V. The LTM8054's output voltage level is typically set using a voltage divider between the Vout and FB pins, the FB pin being constantly regulated to 1.2V. The output current limit of the LTM8054 may be statically set by placing a sense resistor on a dedicated pin. This limit can then be lowered by controlling the voltage level on the CTL pin. Describe the LTM8054 voltage regulator. Signed-off-by: Romain Gantois Reviewed-by: Conor Dooley --- .../devicetree/bindings/regulator/adi,ltm8054.yaml | 71 ++++++++++++++++++= ++++ MAINTAINERS | 5 ++ 2 files changed, 76 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/adi,ltm8054.yaml b= /Documentation/devicetree/bindings/regulator/adi,ltm8054.yaml new file mode 100644 index 000000000000..a982daecb4cf --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/adi,ltm8054.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/adi,ltm8054.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices LTM8054 buck-boost regulator + +maintainers: + - Romain Gantois + +description: + This regulator operates over an input voltage range of 5V to 36V, and can + output from 1.2V to 36V. The output voltage level is typically set with a + voltage divider between the Vout pin and the FB pin which is internally + regulated to 1.2V. + + The output current of the LTM8054 can be limited by tying the Iout pin t= o a + current sense resistor. This limit can be further lowered by applying a + voltage below 1.2V to the CTL pin. + +allOf: + - $ref: /schemas/regulator/regulator.yaml# + +properties: + compatible: + const: adi,ltm8054 + + enable-gpios: + description: GPIO connected to the RUN pin. + maxItems: 1 + + regulator-fb-voltage-divider-ohms: + description: Feedback voltage divider resistor values, in Ohms. + items: + - description: Top resistor value. + - description: Bottom resistor value. + + adi,iout-rsense-micro-ohms: + description: + Value of the output current sense resistor, in micro Ohms. + + io-channels: + items: + - description: DAC controlling the voltage level of the CTL pin. + + io-channel-names: + items: + - const: ctl + +required: + - compatible + - regulator-fb-voltage-divider-ohms + +additionalProperties: false + +examples: + - | + #include + regulator { + compatible =3D "adi,ltm8054"; + + enable-gpios =3D <&gpio0 1 GPIO_ACTIVE_HIGH>; + + regulator-fb-voltage-divider-ohms =3D <1000000 68000>; + + adi,iout-rsense-micro-ohms =3D <20000>; + + io-channels =3D <&dac 1>; + io-channel-names =3D "ctl"; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 8fd3be0162dc..96552be2fcdd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14785,6 +14785,11 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt F: drivers/i2c/muxes/i2c-mux-ltc4306.c =20 +LTM8054 REGULATOR DRIVER +M: Romain Gantois +S: Maintained +F: Documentation/devicetree/bindings/regulator/adi,ltm8054.yaml + LTP (Linux Test Project) M: Andrea Cervesato M: Cyril Hrubis --=20 2.51.2 From nobody Fri Dec 19 15:50:24 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 937E032AAAB for ; Thu, 6 Nov 2025 14:11:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438320; cv=none; b=V0PFG7/tDLZv51Kp89iN5mJkVm5hltS9u6G8zUrROIToy2T+yTRhY5OKZT/I2BhevoMoD5pv8Nb+fwbxYcBw9Qq/7etFq8JWpPzFp3UhhFUm36cT3bktnLQHB1uWwvm8m0Y68Ljwi1ZSorIHk5PnrAD/X7WAFojmwrqR6CwrlKg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438320; c=relaxed/simple; bh=rOo5MltLrdmDrYc6NQrTGXqBhoCeH9F49xDdyJh/GR0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fdcL52dolGw8U1U11zJi0gV+Qt1+GMzzHrSjRTVJlsAkqNp1lGkdDTjQQgoxBi/cMRDc1cCz+ZfSzwUzOxWJSg6qXIK+RKkTkXi3FNgjlPFIs28RPkSa+XLpVgWpbdRQ/Uaib4B4uJMhEYdYE9VQMk0vKK/tMFKYiCMCbGP8dGU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=Sp0CUhs5; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="Sp0CUhs5" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 1F137C0FA8D; Thu, 6 Nov 2025 14:11:36 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 300996068C; Thu, 6 Nov 2025 14:11:57 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id E359311850837; Thu, 6 Nov 2025 15:11:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1762438315; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=XDLg7NMQMzVNMtuCaTNCwQAMAalsvgOyuQ+Sw7NpVlM=; b=Sp0CUhs5pTUtFqsx3RI8QxgoMbPOO7IudArJzJb3uPqUXiZERvOn5gC86vCQ0hekEem5KJ WSrBITumwXuc2jXUzWCDc6EGk7JbluvvgjuKf/uMQ4WzhPKiLcAQQ2+Kc/qqoZ4PHziSeU X63stTUZTvTdks1eeyi1PNLOiQ1dAIqwmQgAnmlh96raDDnFu5urDiov0sKMH2sgR72CsX 6xRXzDSCR8V2kiWN6qCPyHmrgXCcPS2HVTCc+ChhbMCsfwQkYsCp/JOunnroX9qQ2/RGCJ O4XBFFqc1h3o/X5+Y7cnElD47Now6WEnzZ0GdtGmd7/k2v0tFvorGRkxqYEwZg== From: Romain Gantois Date: Thu, 06 Nov 2025 15:11:47 +0100 Subject: [PATCH v3 2/5] iio: add processed write API Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251106-ltm8054-driver-v3-2-fd1feae0f65a@bootlin.com> References: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> In-Reply-To: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko Cc: Hans de Goede , Thomas Petazzoni , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-iio@vger.kernel.org, Romain Gantois X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 Add a function to allow IIO consumers to write a processed value to a channel. Signed-off-by: Romain Gantois --- drivers/iio/inkern.c | 129 +++++++++++++++++++++++++++++++++++++++= ++++ include/linux/iio/consumer.h | 37 +++++++++++++ 2 files changed, 166 insertions(+) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 1e5eb5a41271..bd0bbaef6045 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -635,6 +635,57 @@ int iio_multiply_value(int *result, s64 multiplier, } EXPORT_SYMBOL_NS_GPL(iio_multiply_value, "IIO_UNIT_TEST"); =20 +int iio_divide_by_value(int *result, s64 numerator, + unsigned int type, int val, int val2) +{ + s64 tmp_num, tmp_den; + + switch (type) { + case IIO_VAL_INT: + tmp_num =3D numerator; + tmp_den =3D val; + break; + case IIO_VAL_INT_PLUS_MICRO: + case IIO_VAL_INT_PLUS_NANO: + switch (type) { + case IIO_VAL_INT_PLUS_MICRO: + tmp_num =3D MICRO; + tmp_den =3D MICRO; + break; + + case IIO_VAL_INT_PLUS_NANO: + tmp_num =3D NANO; + tmp_den =3D NANO; + break; + } + + tmp_num *=3D numerator; + tmp_den =3D (s64)abs(val) * tmp_den + (s64)abs(val2); + + if (val < 0 || val2 < 0) + tmp_num *=3D -1; + + break; + case IIO_VAL_FRACTIONAL: + tmp_num =3D (s64)numerator * (s64)val2; + tmp_den =3D val; + break; + case IIO_VAL_FRACTIONAL_LOG2: + tmp_num =3D (s64)numerator << val2; + tmp_den =3D val; + break; + default: + return -EINVAL; + } + + if (!tmp_den) + return -ERANGE; + + *result =3D div64_s64(tmp_num, tmp_den); + + return IIO_VAL_INT; +} + static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, int raw, int *processed, unsigned int scale) @@ -703,6 +754,64 @@ int iio_convert_raw_to_processed(struct iio_channel *c= han, int raw, } EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); =20 +static int iio_convert_processed_to_raw_unlocked(struct iio_channel *chan, + int processed, int *raw, + unsigned int scale) +{ + int scale_type, scale_val, scale_val2; + int offset_type, offset_val, offset_val2; + int ret, half_step =3D 0; + + scale_type =3D iio_channel_read(chan, &scale_val, &scale_val2, + IIO_CHAN_INFO_SCALE); + if (scale_type >=3D 0) { + ret =3D iio_divide_by_value(raw, processed, scale_type, scale_val, scale= _val2); + if (ret < 0) + return ret; + } else { + *raw =3D processed; + } + + if (!scale) + return -ERANGE; + + *raw =3D div_s64(*raw, scale); + + offset_type =3D iio_channel_read(chan, &offset_val, &offset_val2, + IIO_CHAN_INFO_OFFSET); + if (offset_type >=3D 0) { + switch (offset_type) { + case IIO_VAL_INT: + case IIO_VAL_INT_PLUS_MICRO: + half_step =3D MICRO / 2; + break; + case IIO_VAL_INT_PLUS_NANO: + half_step =3D NANO / 2; + break; + case IIO_VAL_FRACTIONAL: + offset_val =3D DIV_ROUND_CLOSEST(offset_val, offset_val2); + break; + case IIO_VAL_FRACTIONAL_LOG2: + offset_val >>=3D offset_val2; + break; + default: + return -EINVAL; + } + + /* Round fractional part to closest to reduce rounding bias. */ + if (half_step) { + if (offset_val2 >=3D half_step) + *raw -=3D 1; + else if (offset_val2 <=3D -half_step) + *raw +=3D 1; + } + + *raw -=3D offset_val; + } + + return 0; +} + int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *va= l2, enum iio_chan_info_enum attribute) { @@ -1039,3 +1148,23 @@ ssize_t iio_read_channel_label(struct iio_channel *c= han, char *buf) return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf); } EXPORT_SYMBOL_GPL(iio_read_channel_label); + +int iio_write_channel_processed_scale(struct iio_channel *chan, int val, + unsigned int scale) +{ + struct iio_dev_opaque *iio_dev_opaque =3D to_iio_dev_opaque(chan->indio_d= ev); + int ret, processed; + + guard(mutex)(&iio_dev_opaque->info_exist_lock); + + if (!chan->indio_dev->info) + return -ENODEV; + + ret =3D iio_convert_processed_to_raw_unlocked(chan, val, &processed, scal= e); + if (ret) + return ret; + + return iio_channel_write(chan, processed, 0, IIO_CHAN_INFO_RAW); +} +EXPORT_SYMBOL_GPL(iio_write_channel_processed_scale); + diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index a38b277c2c02..29d08b57bac9 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -399,6 +399,24 @@ int iio_read_channel_scale(struct iio_channel *chan, i= nt *val, int iio_multiply_value(int *result, s64 multiplier, unsigned int type, int val, int val2); =20 +/** + * iio_divide_by_value() - Divide by an IIO value + * @result: Destination pointer for the division result + * @numerator: Numerator. + * @type: One of the IIO_VAL_* constants. This decides how the @val + * and @val2 parameters are interpreted. + * @val: Denominator. + * @val2: Denominator. @val2 use depends on type. + * + * Divide an s64 number by an IIO value, storing the result as + * IIO_VAL_INT. This is typically used for scaling. + * + * Returns: + * IIO_VAL_INT on success or a negative error-number on failure. + */ +int iio_divide_by_value(int *result, s64 numerator, + unsigned int type, int val, int val2); + /** * iio_convert_raw_to_processed() - Converts a raw value to a processed va= lue * @chan: The channel being queried @@ -469,4 +487,23 @@ ssize_t iio_write_channel_ext_info(struct iio_channel = *chan, const char *attr, */ ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf); =20 +/** + * iio_write_channel_processed_scale() - scale and write processed value t= o a given channel + * @chan: The channel being queried. + * @val: Value to write. + * @scale: Processed value is divided by this scale factor during the con= version. + * + * This function writes a processed value to a channel. A processed value = means + * that this value will have the correct unit and not some device internal + * representation. If the device does not support writing a processed valu= e, the + * function will query the channel's scale and offset and write an appropr= iately + * transformed raw value. + * + * Context: May sleep. + * Return: an error code or 0. + * + */ +int iio_write_channel_processed_scale(struct iio_channel *chan, int val, + unsigned int scale); + #endif --=20 2.51.2 From nobody Fri Dec 19 15:50:24 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 29EF133CEB1; Thu, 6 Nov 2025 14:12:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438322; cv=none; b=ZrHitU+2EQ824XI3Fqizd6BoH8CGgcArbVMOX2556CONmewJFlpZb2HBrzupMhdexOWY7cVb6VhZpjSVx8D8kWuRXhhrJuIa5NEXk1ZxN+7DO12W1D9KcBhhhIKwLlmJPSod8O+SaPr3EOfGZwRSbNb+HfZtavWdHNzEcRFjeHQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438322; c=relaxed/simple; bh=Ry+fowjGz0ivpRlfCc0e2X9+4/EC+74dsNsgN7IocgA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZiMUGAllJi6MKx0VeteUk+8MDkRgJLkgttUmuPQ6cJM3Ta34576GtQhhnJ5Kg6Tdy/I+u2Sh9AD+4VJjT29lp3QY/ib3MR6IWEt5PGL2Du6OfqCvUiDv2FjJnZ5P/v0ZWzQBDvYqsg7Khj7ZFyDH2Ky6ldRQ5gvTwM6cJcIHbQA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=y0oWO4yd; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="y0oWO4yd" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id E630D4E41570; Thu, 6 Nov 2025 14:11:58 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id BBA516068C; Thu, 6 Nov 2025 14:11:58 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 678A911851157; Thu, 6 Nov 2025 15:11:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1762438317; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=2yVa3NA6su/n2ohTZe2bhGaW7obtfjYTE3bOzUVwQtQ=; b=y0oWO4yd9yDYHD8eTig2OUelmpjhgEl6tV+eZHVky8uK+2fN9hUsY7awJT2kbdyJ8v3t4k Yvnws8CUtUiwB8ncjfKzYY6c6amlmclvrQW8ZD2ILg+ICKoGcxb95Yx5DV9MzKQHilhvdr 7vRtN/mvRimQlJfEy9CBVd9tsvjDYnG1zjlmOOIPW0qLpn8SfdoKIq0MzWSClCBlwGcisJ ut/8OLjqNUykLAmNyWWwxAnOD5F0FlS/B5nc9bnHGZkUsjMVf8UJlS7uB1bD6CWu040rOv ++xbntz2StYCW8/SRKBrYhhvrOuAI7Vbv8aoz2ehvBfe/E0SMRWu7UOBzR7LVg== From: Romain Gantois Date: Thu, 06 Nov 2025 15:11:48 +0100 Subject: [PATCH v3 3/5] iio: test: Add kunit tests for iio_divide_by_value() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251106-ltm8054-driver-v3-3-fd1feae0f65a@bootlin.com> References: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> In-Reply-To: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko Cc: Hans de Goede , Thomas Petazzoni , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-iio@vger.kernel.org, Romain Gantois X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 Add kunit tests for iio_divide_by_value(), these are similar to the existing tests for iio_multiply_value(), but the operand values used differ slightly. Signed-off-by: Romain Gantois --- drivers/iio/test/Kconfig | 12 +++ drivers/iio/test/Makefile | 1 + drivers/iio/test/iio-test-divide.c | 215 +++++++++++++++++++++++++++++++++= ++++ 3 files changed, 228 insertions(+) diff --git a/drivers/iio/test/Kconfig b/drivers/iio/test/Kconfig index 6e65e929791c..3aa1fc78966c 100644 --- a/drivers/iio/test/Kconfig +++ b/drivers/iio/test/Kconfig @@ -4,6 +4,18 @@ # =20 # Keep in alphabetical order +config IIO_DIVIDE_KUNIT_TEST + tristate "Test IIO division functions" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + build unit tests for the IIO division functions. + + For more information on KUnit and unit tests in general, please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + config IIO_GTS_KUNIT_TEST tristate "Test IIO gain-time-scale helpers" if !KUNIT_ALL_TESTS depends on KUNIT diff --git a/drivers/iio/test/Makefile b/drivers/iio/test/Makefile index 0c846bc21acd..16344eedc46a 100644 --- a/drivers/iio/test/Makefile +++ b/drivers/iio/test/Makefile @@ -5,6 +5,7 @@ =20 # Keep in alphabetical order obj-$(CONFIG_IIO_RESCALE_KUNIT_TEST) +=3D iio-test-rescale.o +obj-$(CONFIG_IIO_DIVIDE_KUNIT_TEST) +=3D iio-test-divide.o obj-$(CONFIG_IIO_FORMAT_KUNIT_TEST) +=3D iio-test-format.o obj-$(CONFIG_IIO_GTS_KUNIT_TEST) +=3D iio-test-gts.o obj-$(CONFIG_IIO_MULTIPLY_KUNIT_TEST) +=3D iio-test-multiply.o diff --git a/drivers/iio/test/iio-test-divide.c b/drivers/iio/test/iio-test= -divide.c new file mode 100644 index 000000000000..d117f868dd76 --- /dev/null +++ b/drivers/iio/test/iio-test-divide.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Unit tests for IIO division functions + * + * Copyright (c) 2025 Bootlin + * Based on iio-test-multiply.c which is: + * Copyright (c) 2025 Hans de Goede + * Based on iio-test-format.c which is: + * Copyright (c) 2020 Lars-Peter Clausen + */ + +#include +#include + +static void __iio_test_iio_divide_by_integer(struct kunit *test, s64 numer= ator) +{ + int ret, result, val; + + val =3D 42; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT, val, 0); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator, val)); + + val =3D -23; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT, val, 0); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator, val)); + + val =3D 0; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT, val, 0); + KUNIT_EXPECT_EQ(test, ret, -EDOM); +} + +static void iio_test_iio_divide_by_integer(struct kunit *test) +{ + __iio_test_iio_divide_by_integer(test, 2000); + __iio_test_iio_divide_by_integer(test, -2000); +} + +static void __iio_test_iio_divide_by_fixedpoint(struct kunit *test, s64 nu= merator) +{ + int ret, result, val, val2; + + /* positive >=3D 1 (1.5) */ + val =3D 1; + val2 =3D 500000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_MICRO, v= al, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * 10, 15)); + + val =3D 1; + val2 =3D 500000000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_NANO, va= l, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * 10, 15)); + + /* positive < 1 (0.5) */ + val =3D 0; + val2 =3D 500000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_MICRO, v= al, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * 10, 5)); + + val =3D 0; + val2 =3D 500000000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_NANO, va= l, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * 10, 5)); + + /* negative <=3D -1 (-1.5) */ + val =3D -1; + val2 =3D 500000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_MICRO, v= al, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * -10, 15)); + + val =3D -1; + val2 =3D 500000000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_NANO, va= l, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * -10, 15)); + + /* negative > -1 (-0.5) */ + val =3D 0; + val2 =3D -500000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_MICRO, v= al, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * -10, 5)); + + val =3D 0; + val2 =3D -500000000; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_INT_PLUS_NANO, va= l, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * -10, 5)); + + /* Zero */ + val =3D 0; + val2 =3D 0; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL_LOG2, = val, val2); + KUNIT_EXPECT_EQ(test, ret, -EDOM); +} + +static void iio_test_iio_divide_by_fixedpoint(struct kunit *test) +{ + __iio_test_iio_divide_by_fixedpoint(test, 2000); + __iio_test_iio_divide_by_fixedpoint(test, -2000); +} + +static void __iio_test_iio_divide_by_fractional(struct kunit *test, s64 nu= merator) +{ + int ret, result, val, val2; + + /* positive < 1 (1/10)*/ + val =3D 1; + val2 =3D 10; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL, val, = val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * val2, val)); + + /* positive >=3D 1 (100/3)*/ + val =3D 100; + val2 =3D 3; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL, val, = val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * val2, val)); + + /* negative > -1 (-1/10) */ + val =3D -1; + val2 =3D 10; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL, val, = val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * val2, val)); + + /* negative <=3D -1 (-200/3)*/ + val =3D -200; + val2 =3D 3; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL, val, = val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64(numerator * val2, val)); + + /* Zero */ + val =3D 0; + val2 =3D 0; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL, val, = val2); + KUNIT_EXPECT_EQ(test, ret, -EDOM); +} + +static void iio_test_iio_divide_by_fractional(struct kunit *test) +{ + __iio_test_iio_divide_by_fractional(test, 2000); + __iio_test_iio_divide_by_fractional(test, -2000); +} + +static void __iio_test_iio_divide_by_fractional_log2(struct kunit *test, s= 64 numerator) +{ + int ret, result, val, val2; + + /* positive < 1 (123/1024) */ + val =3D 123; + val2 =3D 10; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL_LOG2, = val, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64((numerator * 1024), val)); + + /* positive >=3D 1 (1234567/1024) */ + val =3D 1234567; + val2 =3D 10; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL_LOG2, = val, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64((numerator * 1024), val)); + + /* negative > -1 (-123/1024) */ + val =3D -123; + val2 =3D 10; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL_LOG2, = val, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64((numerator * 1024), val)); + + /* negative <=3D -1 (-1234567/1024) */ + val =3D -1234567; + val2 =3D 10; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL_LOG2, = val, val2); + KUNIT_EXPECT_EQ(test, ret, IIO_VAL_INT); + KUNIT_EXPECT_EQ(test, result, div_s64((numerator * 1024), val)); + + /* Zero */ + val =3D 0; + val2 =3D 0; + ret =3D iio_divide_by_value(&result, numerator, IIO_VAL_FRACTIONAL_LOG2, = val, val2); + KUNIT_EXPECT_EQ(test, ret, -EDOM); +} + +static void iio_test_iio_divide_by_fractional_log2(struct kunit *test) +{ + __iio_test_iio_divide_by_fractional_log2(test, 2000); + __iio_test_iio_divide_by_fractional_log2(test, -2000); +} + +static struct kunit_case iio_divide_test_cases[] =3D { + KUNIT_CASE(iio_test_iio_divide_by_integer), + KUNIT_CASE(iio_test_iio_divide_by_fixedpoint), + KUNIT_CASE(iio_test_iio_divide_by_fractional), + KUNIT_CASE(iio_test_iio_divide_by_fractional_log2), + { } +}; + +static struct kunit_suite iio_divide_test_suite =3D { + .name =3D "iio-divide", + .test_cases =3D iio_divide_test_cases, +}; + +kunit_test_suite(iio_divide_test_suite); + +MODULE_AUTHOR("Romain Gantois "); +MODULE_DESCRIPTION("Test IIO division functions"); +MODULE_LICENSE("GPL"); --=20 2.51.2 From nobody Fri Dec 19 15:50:24 2025 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (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 19A3133EAE4; Thu, 6 Nov 2025 14:12:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438324; cv=none; b=kvmjbFGz+TEmVMqpo4ztpdWsFdC1QmvuW8akms6noZez1PqRtMJOxhv4xnlRysHzQm1TlzWZ5UIGXNnmCZtv1Ow2GTubkoA7rimqGS44mQpOspNwYJ9UNJ1XYtgpdy3LjKzfnTm9Mh8BrLawa/2Kx4OlsZ2PxZK2XvRIFw+EOe0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438324; c=relaxed/simple; bh=FpxVQB1INbV+80OzoaW6i4u58HK/pggkqM01al2Kpa4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lVcZ3QV1L+ipj2OH5PXY795OTVTP4xNzJud0g8yqb/WIsKbebf7Zh62wqmf4tc66Cq46CvJAKw3Pgi3AtbZUEvDN9B4V2Tc80oWOhNx4BhXITV7S2TSrt62DXjlbap/Gji5MJWEa64DzPfs2vSPR+7eb7HpUcusggaMTXQ2GV7A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=dt7rl4Fk; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="dt7rl4Fk" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 72F261A18F2; Thu, 6 Nov 2025 14:12:00 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 476596068C; Thu, 6 Nov 2025 14:12:00 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 244C911851155; Thu, 6 Nov 2025 15:11:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1762438319; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=BHpWHfNsMm/O8uvLkpHCGYuFYP58PxmK8ahqwS8SU9M=; b=dt7rl4Fk419ka+j4AXX9FMZqTqMU3K2cmZos153TfZQZY6snNfBZsh0TI5VILosd98ZCio WiacUqgVCXvePcc7z3Wsjv4R2W9UMAy5pyApK1njA2jk2O3v8BH7BmX6W2/TRYb6CdN9oy P1pI/G8iCjvKqa9+sZmO7lYN0yhr0XP6NqzlAqAq04CG8snqFX3fTBnGExDOgVOCelxwYY 30WxBuw1FXJaDzUCTleR/UzFPLTzzk8WdeGbINchTQzcmYZmX8fH57I07adi9XpuQdrx3f 5qR3eHJU3+1WfpJMA3+fI3L1YeTnAjbLM+izJdh+nQEn8L1O4F2lxDeNu908IA== From: Romain Gantois Date: Thu, 06 Nov 2025 15:11:49 +0100 Subject: [PATCH v3 4/5] regulator: Support the LTM8054 voltage regulator Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251106-ltm8054-driver-v3-4-fd1feae0f65a@bootlin.com> References: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> In-Reply-To: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko Cc: Hans de Goede , Thomas Petazzoni , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-iio@vger.kernel.org, Romain Gantois X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 Add a stub driver for the Linear Technology LTM8054 Buck-Boost voltage regulator. This version only supports enabling/disabling the regulator via a GPIO, and reporting the output voltage level from the resistor divider values given in the device tree. Signed-off-by: Romain Gantois Reviewed-by: Andy Shevchenko --- MAINTAINERS | 1 + drivers/regulator/Kconfig | 8 +++ drivers/regulator/Makefile | 1 + drivers/regulator/ltm8054-regulator.c | 125 ++++++++++++++++++++++++++++++= ++++ 4 files changed, 135 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 96552be2fcdd..45906509508d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14789,6 +14789,7 @@ LTM8054 REGULATOR DRIVER M: Romain Gantois S: Maintained F: Documentation/devicetree/bindings/regulator/adi,ltm8054.yaml +F: drivers/regulator/ltm8054-regulator.c =20 LTP (Linux Test Project) M: Andrea Cervesato diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 403890a76070..f5c6d4a21a88 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -585,6 +585,14 @@ config REGULATOR_LTC3676 This enables support for the LTC3676 8-output regulators controlled via I2C. =20 +config REGULATOR_LTM8054 + tristate "LTM8054 Buck-Boost voltage regulator" + help + This driver provides support for the Analog Devices LTM8054 + Buck-Boost micromodule regulator. The LTM8054 has an adjustable + output current limitation and a feedback pin for setting the + output voltage level. + config REGULATOR_MAX14577 tristate "Maxim 14577/77836 regulator" depends on MFD_MAX14577 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b3101376029d..f2687755c291 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_REGULATOR_LP8788) +=3D lp8788-ldo.o obj-$(CONFIG_REGULATOR_LP8755) +=3D lp8755.o obj-$(CONFIG_REGULATOR_LTC3589) +=3D ltc3589.o obj-$(CONFIG_REGULATOR_LTC3676) +=3D ltc3676.o +obj-$(CONFIG_REGULATOR_LTM8054) +=3D ltm8054-regulator.o obj-$(CONFIG_REGULATOR_MAX14577) +=3D max14577-regulator.o obj-$(CONFIG_REGULATOR_MAX1586) +=3D max1586.o obj-$(CONFIG_REGULATOR_MAX5970) +=3D max5970-regulator.o diff --git a/drivers/regulator/ltm8054-regulator.c b/drivers/regulator/ltm8= 054-regulator.c new file mode 100644 index 000000000000..b5783f6629e3 --- /dev/null +++ b/drivers/regulator/ltm8054-regulator.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices LTM8054 Buck-Boost regulator driver + * + * Copyright (C) 2025 Bootlin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* The LTM8054 regulates its FB pin to 1.2V */ +#define LTM8054_FB_uV 1200000 + +struct ltm8054_priv { + struct regulator_desc rdesc; +}; + +static int ltm8054_scale(unsigned int uV, u32 r1, u32 r2) +{ + u64 tmp; + + tmp =3D (u64)uV * r1; + do_div(tmp, r2); + + return uV + tmp; +} + +static const struct regulator_ops ltm8054_regulator_ops =3D { }; + +static int ltm8054_of_parse(struct device *dev, struct ltm8054_priv *priv, + struct regulator_config *config) +{ + u32 r[2]; + int ret; + + ret =3D device_property_read_u32_array(dev, "regulator-fb-voltage-divider= -ohms", + r, ARRAY_SIZE(r)); + if (ret) + return ret; + + priv->rdesc.fixed_uV =3D ltm8054_scale(LTM8054_FB_uV, r[0], r[1]); + priv->rdesc.min_uV =3D priv->rdesc.fixed_uV; + priv->rdesc.n_voltages =3D 1; + + config->of_node =3D dev_of_node(dev); + config->init_data =3D of_get_regulator_init_data(dev, + config->of_node, + &priv->rdesc); + if (!config->init_data) + return -EINVAL; + + config->ena_gpiod =3D devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LO= W); + if (IS_ERR(config->ena_gpiod)) + return PTR_ERR(config->ena_gpiod); + + return 0; +} + +static int ltm8054_probe(struct platform_device *pdev) +{ + struct regulator_config config =3D { }; + struct device *dev =3D &pdev->dev; + struct regulator_dev *rdev; + struct ltm8054_priv *priv; + int ret; + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->rdesc.name =3D "ltm8054-regulator"; + priv->rdesc.ops =3D <m8054_regulator_ops; + priv->rdesc.type =3D REGULATOR_VOLTAGE; + priv->rdesc.owner =3D THIS_MODULE; + + config.dev =3D dev; + config.driver_data =3D priv; + + ret =3D ltm8054_of_parse(dev, priv, &config); + if (ret) + return dev_err_probe(dev, ret, "failed to parse device tree\n"); + + rdev =3D devm_regulator_register(dev, &priv->rdesc, &config); + if (IS_ERR(rdev)) + return dev_err_probe(dev, PTR_ERR(rdev), "failed to register regulator\n= "); + + return 0; +} + +static const struct of_device_id ltm8054_of_match[] =3D { + { .compatible =3D "adi,ltm8054" }, + {} +}; +MODULE_DEVICE_TABLE(of, ltm8054_of_match); + +static struct platform_driver ltm8054_driver =3D { + .probe =3D ltm8054_probe, + .driver =3D { + .name =3D "ltm8054", + .of_match_table =3D ltm8054_of_match, + }, +}; +module_platform_driver(ltm8054_driver); + +MODULE_DESCRIPTION("LTM8054 regulator driver"); +MODULE_AUTHOR("Romain Gantois "); +MODULE_LICENSE("GPL"); --=20 2.51.2 From nobody Fri Dec 19 15:50:24 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 55D3433EB0E for ; Thu, 6 Nov 2025 14:12:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438325; cv=none; b=oA1nfsJ/Kpf+wV7/JGpf+uBqR/FAFqnmiUmCiGlzAS1HJARpOkYKPxGdfq9SFe3W52qDoft3dddH1RKXHvoWj+FzSzL/dl/rM1OUS6z4/Liy82LUm1zIpELzIgOtXNb4Da2UfqIjmh3I4Go9YdVzvTMaM1Gbh++zeCKcxYVlkPQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762438325; c=relaxed/simple; bh=tBrLnoN6fk+Xqnm3U9nOXSYuDRrAPCj1BStgPuNDt7Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Fbd4JossXWlrgx/mH9uKbAAKl541y+9ZwBdFDuCDHwSeh1DTbosIPoyB74SYQFJyNX1rYayT5fgFEFo20RTIz87LUUsSGBy1TqtyR8eJWcowuf+96BED8VoBYLDGB1dSBKbwVzedrKitrfnR1aPIC/lceZprklFDZ7Y69G12NeY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=LI9HEaQ1; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="LI9HEaQ1" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id CC56D4E4156D; Thu, 6 Nov 2025 14:12:01 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id A24A96068C; Thu, 6 Nov 2025 14:12:01 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id B3D721185115B; Thu, 6 Nov 2025 15:11:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1762438320; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=ZKeWFZxA04Nf3/9eL/Uw741y2vR3pCplWxqb3hcOC3s=; b=LI9HEaQ1i0wvEe68W/tfHeEZ/AHtRXpsEbeYhliUApXxyy47PLgV1dQcYu1x/8xCwx4oj+ nMACmlmkv0j2aRLaR1CsAWJFUjcR6ewc69wIz+D0hslv/GDWGtOEFCEYUbfPIDtdZh8KT5 jYjQZZ/mcAG4ToTMk+3ybnw3ogU5zg06bJf1Irwre8wknpb+Y3XX1RvEC5dc1zJpg/MhMZ A7juBUx4D4TpNO1ZmiKKCq8eKaOU9iv9NFo2fJWr+EOWqKmjdzHAuHpHDv1rDNc6LKlLak Z8Q606K7qiJHuCs9tLWYSxQg+wvSOPKIu+CamLVd2esyrbXMvOUjhvWhjR4mdA== From: Romain Gantois Date: Thu, 06 Nov 2025 15:11:50 +0100 Subject: [PATCH v3 5/5] regulator: ltm8054: Support output current limit control Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251106-ltm8054-driver-v3-5-fd1feae0f65a@bootlin.com> References: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> In-Reply-To: <20251106-ltm8054-driver-v3-0-fd1feae0f65a@bootlin.com> To: Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Jonathan Cameron , David Lechner , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko Cc: Hans de Goede , Thomas Petazzoni , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-iio@vger.kernel.org, Romain Gantois X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 The LTM8054 supports setting a fixed output current limit using a sense resistor connected to a dedicated pin. This limit can then be lowered dynamically by varying the voltage level of the CTL pin. Support controlling the LTM8054's output current limit. Signed-off-by: Romain Gantois --- drivers/regulator/Kconfig | 1 + drivers/regulator/ltm8054-regulator.c | 273 ++++++++++++++++++++++++++++++= +++- 2 files changed, 268 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index f5c6d4a21a88..aad8c523420a 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -587,6 +587,7 @@ config REGULATOR_LTC3676 =20 config REGULATOR_LTM8054 tristate "LTM8054 Buck-Boost voltage regulator" + depends on IIO help This driver provides support for the Analog Devices LTM8054 Buck-Boost micromodule regulator. The LTM8054 has an adjustable diff --git a/drivers/regulator/ltm8054-regulator.c b/drivers/regulator/ltm8= 054-regulator.c index b5783f6629e3..38072231b8e4 100644 --- a/drivers/regulator/ltm8054-regulator.c +++ b/drivers/regulator/ltm8054-regulator.c @@ -6,6 +6,7 @@ */ =20 #include +#include #include #include #include @@ -15,7 +16,11 @@ #include =20 #include +#include +#include +#include #include +#include #include #include #include @@ -26,10 +31,42 @@ #include #include =20 +#include +#include + /* The LTM8054 regulates its FB pin to 1.2V */ #define LTM8054_FB_uV 1200000 =20 +/* Threshold voltage between the Vout and Iout pins which triggers current + * limiting. + */ +#define LTM8054_VOUT_IOUT_MAX_uV 58000 + +#define LTM8054_MAX_CTL_uV 1200000 +#define LTM8054_MIN_CTL_uV 50000 + +#define LTM8054_CTL_RW_TIMEOUT msecs_to_jiffies(500) + +/* CTL pin read/write transaction */ +struct ltm8054_ctl_pin_work { + struct work_struct work; + unsigned int ctl_val; + bool write; + int ret; +}; + struct ltm8054_priv { + struct device *dev; + + struct iio_channel *ctl_dac; + struct ltm8054_ctl_pin_work ctl_work; + /* Lock for ctl_work. */ + struct mutex ctl_work_lock; + struct completion ctl_rw_done; + + int min_uA; + int max_uA; + struct regulator_desc rdesc; }; =20 @@ -43,14 +80,190 @@ static int ltm8054_scale(unsigned int uV, u32 r1, u32 = r2) return uV + tmp; } =20 -static const struct regulator_ops ltm8054_regulator_ops =3D { }; +static void ltm8054_do_ctl_work(struct work_struct *work) +{ + struct ltm8054_ctl_pin_work *ctl_work =3D container_of_const(work, + struct ltm8054_ctl_pin_work, + work); + struct ltm8054_priv *priv =3D container_of_const(ctl_work, + struct ltm8054_priv, + ctl_work); + unsigned int val; + bool write; + int ret; + + lockdep_assert_not_held(&priv->ctl_work_lock); + + mutex_lock(&priv->ctl_work_lock); + val =3D ctl_work->ctl_val; + write =3D ctl_work->write; + mutex_unlock(&priv->ctl_work_lock); + + /* Standard IIO voltage unit is mV, scale accordingly. */ + if (write) + ret =3D iio_write_channel_processed_scale(priv->ctl_dac, + val, 1000); + else + ret =3D iio_read_channel_processed_scale(priv->ctl_dac, + &val, 1000); + + pr_debug("LTM8054: %s CTL IO channel, val: %duV\n", write ? "wrote" : "re= ading", val); + + mutex_lock(&priv->ctl_work_lock); + ctl_work->ret =3D ret; + ctl_work->ctl_val =3D val; + mutex_unlock(&priv->ctl_work_lock); + + complete(&priv->ctl_rw_done); +} + +static int ltm8054_ctl_pin_rw(struct ltm8054_priv *priv, bool write, unsig= ned int *ctl_val) +{ + struct ltm8054_ctl_pin_work *ctl_work =3D &priv->ctl_work; + int ret =3D 0; + + lockdep_assert_not_held(&priv->ctl_work_lock); + + /* The get/set_current_limit() callbacks have an active regulator core + * reservation ID (obtained with ww_acquire_init()). + * + * Or, the IO channel driver may call something like + * regulator_enable(), meaning this thread would acquire a new + * regulator core reservation ID before the current one is dropped + * (using ww_acquire_fini()). This is forbidden. + * + * Thus, perform the IO channel read/write in a different thread, and + * wait for it to complete, with a timeout to avoid deadlocking. + */ + + scoped_guard(mutex, &priv->ctl_work_lock) { + if (work_busy(&ctl_work->work)) + return -EBUSY; + + if (write) { + ctl_work->ctl_val =3D *ctl_val; + ctl_work->write =3D 1; + } else { + ctl_work->write =3D 0; + } + + schedule_work(&ctl_work->work); + } + + ret =3D wait_for_completion_timeout(&priv->ctl_rw_done, LTM8054_CTL_RW_TI= MEOUT); + reinit_completion(&priv->ctl_rw_done); + + if (unlikely(!ret)) + return -ETIMEDOUT; + + scoped_guard(mutex, &priv->ctl_work_lock) { + ret =3D ctl_work->ret; + + if (!ret && !write) + *ctl_val =3D ctl_work->ctl_val; + } + + return ret; +} + +static int ltm8054_set_current_limit(struct regulator_dev *rdev, int min_u= A, int max_uA) +{ + struct ltm8054_priv *priv =3D rdev_get_drvdata(rdev); + unsigned int ctl_val; + u64 vdac_uV; + + min_uA =3D clamp_t(int, min_uA, priv->min_uA, priv->max_uA); + + /* adjusted current limit =3D Rsense current limit * CTL pin voltage / ma= x CTL pin voltage */ + vdac_uV =3D (u64)min_uA * LTM8054_MAX_CTL_uV; + do_div(vdac_uV, priv->max_uA); + + dev_dbg(&rdev->dev, + "Setting current limit to %duA, CTL pin to %lluuV\n", min_uA, vdac_uV); + + ctl_val =3D vdac_uV; + + return ltm8054_ctl_pin_rw(priv, 1, &ctl_val); +} + +static int ltm8054_get_current_limit(struct regulator_dev *rdev) +{ + struct ltm8054_priv *priv =3D rdev_get_drvdata(rdev); + unsigned int ctl_val; + int ret; + u64 uA; + + ret =3D ltm8054_ctl_pin_rw(priv, 0, &ctl_val); + if (ret) + return ret; + + uA =3D (u64)ctl_val * priv->max_uA; + do_div(uA, LTM8054_MAX_CTL_uV); + + return uA; +} + +static const struct regulator_ops ltm8054_no_ctl_ops =3D { }; + +static const struct regulator_ops ltm8054_ctl_ops =3D { + .set_current_limit =3D ltm8054_set_current_limit, + .get_current_limit =3D ltm8054_get_current_limit, +}; + +static struct iio_channel *ltm8054_init_ctl_dac(struct platform_device *pd= ev) +{ + struct iio_channel *ctl_dac; + enum iio_chan_type type; + int ret; + + ctl_dac =3D devm_iio_channel_get(&pdev->dev, "ctl"); + if (IS_ERR(ctl_dac)) { + if (PTR_ERR(ctl_dac) =3D=3D -ENODEV) + return ERR_PTR(-EPROBE_DEFER); + + return ctl_dac; + } + + ret =3D iio_get_channel_type(ctl_dac, &type); + if (ret) + return ERR_PTR(ret); + + if (type !=3D IIO_VOLTAGE) + return ERR_PTR(-EINVAL); + + return ctl_dac; +} =20 static int ltm8054_of_parse(struct device *dev, struct ltm8054_priv *priv, struct regulator_config *config) { + u32 rsense; u32 r[2]; + u64 tmp; int ret; =20 + ret =3D device_property_read_u32(dev, "adi,iout-rsense-micro-ohms", &rsen= se); + if (ret) + return ret; + + if (rsense =3D=3D 0) + return -EINVAL; + + /* The maximum output current limit is the one set by the Rsense resistor= */ + tmp =3D (u64)LTM8054_VOUT_IOUT_MAX_uV * MICRO; + do_div(tmp, rsense); + priv->max_uA =3D tmp; + + /* + * Applying a voltage below LTM8054_MAX_CTL_uV on the CTL pin reduces + * the output current limit. If this level drops below + * LTM8054_MIN_CTL_uV the regulator stops switching. + */ + + tmp =3D (u64)priv->max_uA * LTM8054_MIN_CTL_uV; + do_div(tmp, LTM8054_MAX_CTL_uV); + priv->min_uA =3D tmp; + ret =3D device_property_read_u32_array(dev, "regulator-fb-voltage-divider= -ohms", r, ARRAY_SIZE(r)); if (ret) @@ -60,6 +273,9 @@ static int ltm8054_of_parse(struct device *dev, struct l= tm8054_priv *priv, priv->rdesc.min_uV =3D priv->rdesc.fixed_uV; priv->rdesc.n_voltages =3D 1; =20 + dev_dbg(dev, "max_uA: %d min_uA: %d fixed_uV: %d\n", + priv->max_uA, priv->min_uA, priv->rdesc.fixed_uV); + config->of_node =3D dev_of_node(dev); config->init_data =3D of_get_regulator_init_data(dev, config->of_node, @@ -77,32 +293,76 @@ static int ltm8054_of_parse(struct device *dev, struct= ltm8054_priv *priv, static int ltm8054_probe(struct platform_device *pdev) { struct regulator_config config =3D { }; + struct iio_channel *ctl_dac =3D NULL; struct device *dev =3D &pdev->dev; struct regulator_dev *rdev; struct ltm8054_priv *priv; int ret; =20 + /* Do this first, as it might defer. */ + if (device_property_match_string(dev, "io-channel-names", "ctl") >=3D 0) { + ctl_dac =3D ltm8054_init_ctl_dac(pdev); + if (IS_ERR(ctl_dac)) + return dev_err_probe(dev, PTR_ERR(ctl_dac), + "failed to initialize CTL DAC\n"); + } + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; =20 + platform_set_drvdata(pdev, priv); + + priv->dev =3D dev; priv->rdesc.name =3D "ltm8054-regulator"; - priv->rdesc.ops =3D <m8054_regulator_ops; + priv->rdesc.ops =3D <m8054_no_ctl_ops; priv->rdesc.type =3D REGULATOR_VOLTAGE; priv->rdesc.owner =3D THIS_MODULE; =20 + if (ctl_dac) { + priv->ctl_dac =3D ctl_dac; + + INIT_WORK(&priv->ctl_work.work, ltm8054_do_ctl_work); + init_completion(&priv->ctl_rw_done); + mutex_init(&priv->ctl_work_lock); + + priv->rdesc.ops =3D <m8054_ctl_ops; + } + config.dev =3D dev; config.driver_data =3D priv; =20 ret =3D ltm8054_of_parse(dev, priv, &config); - if (ret) - return dev_err_probe(dev, ret, "failed to parse device tree\n"); + if (ret) { + ret =3D dev_err_probe(dev, ret, "failed to parse device tree\n"); + goto out_err; + } =20 rdev =3D devm_regulator_register(dev, &priv->rdesc, &config); - if (IS_ERR(rdev)) - return dev_err_probe(dev, PTR_ERR(rdev), "failed to register regulator\n= "); + if (IS_ERR(rdev)) { + ret =3D dev_err_probe(dev, PTR_ERR(rdev), "failed to register regulator\= n"); + goto out_err; + } =20 return 0; + +out_err: + if (ctl_dac) { + cancel_work_sync(&priv->ctl_work.work); + mutex_destroy(&priv->ctl_work_lock); + } + + return ret; +} + +static void ltm8054_remove(struct platform_device *pdev) +{ + struct ltm8054_priv *priv =3D platform_get_drvdata(pdev); + + if (priv->ctl_dac) { + cancel_work_sync(&priv->ctl_work.work); + mutex_destroy(&priv->ctl_work_lock); + } } =20 static const struct of_device_id ltm8054_of_match[] =3D { @@ -113,6 +373,7 @@ MODULE_DEVICE_TABLE(of, ltm8054_of_match); =20 static struct platform_driver ltm8054_driver =3D { .probe =3D ltm8054_probe, + .remove =3D ltm8054_remove, .driver =3D { .name =3D "ltm8054", .of_match_table =3D ltm8054_of_match, --=20 2.51.2