diff --git a/src/ipa/libipa/fixedpoint.cpp b/src/ipa/libipa/fixedpoint.cpp
index 43d76f745d8a..6a15f9b068c7 100644
--- a/src/ipa/libipa/fixedpoint.cpp
+++ b/src/ipa/libipa/fixedpoint.cpp
@@ -15,28 +15,6 @@ namespace libcamera {
 
 namespace ipa {
 
-/**
- * \fn R floatingToFixedPoint(T number)
- * \brief Convert a floating point number to a fixed-point representation
- * \tparam I Bit width of the integer part of the fixed-point
- * \tparam F Bit width of the fractional part of the fixed-point
- * \tparam R Return type of the fixed-point representation
- * \tparam T Input type of the floating point representation
- * \param number The floating point number to convert to fixed point
- * \return The converted value
- */
-
-/**
- * \fn R fixedToFloatingPoint(T number)
- * \brief Convert a fixed-point number to a floating point representation
- * \tparam I Bit width of the integer part of the fixed-point
- * \tparam F Bit width of the fractional part of the fixed-point
- * \tparam R Return type of the floating point representation
- * \tparam T Input type of the fixed-point representation
- * \param number The fixed point number to convert to floating point
- * \return The converted value
- */
-
 /**
  * \struct libcamera::ipa::FixedPointQTraits
  * \brief Traits type implementing fixed-point quantisation conversions
diff --git a/src/ipa/libipa/fixedpoint.h b/src/ipa/libipa/fixedpoint.h
index 4f6ee081604b..1d53b0b9fdde 100644
--- a/src/ipa/libipa/fixedpoint.h
+++ b/src/ipa/libipa/fixedpoint.h
@@ -16,55 +16,6 @@ namespace libcamera {
 
 namespace ipa {
 
-#ifndef __DOXYGEN__
-template<unsigned int I, unsigned int F, typename R, typename T,
-	 std::enable_if_t<std::is_integral_v<R> &&
-			  std::is_floating_point_v<T>> * = nullptr>
-#else
-template<unsigned int I, unsigned int F, typename R, typename T>
-#endif
-constexpr R floatingToFixedPoint(T number)
-{
-	static_assert(sizeof(int) >= sizeof(R));
-	static_assert(I + F <= sizeof(R) * 8);
-
-	/*
-	 * The intermediate cast to int is needed on arm platforms to properly
-	 * cast negative values. See
-	 * https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/
-	 */
-	R mask = (1 << (F + I)) - 1;
-	R frac = static_cast<R>(static_cast<int>(std::round(number * (1 << F)))) & mask;
-
-	return frac;
-}
-
-#ifndef __DOXYGEN__
-template<unsigned int I, unsigned int F, typename R, typename T,
-	 std::enable_if_t<std::is_floating_point_v<R> &&
-			  std::is_integral_v<T>> * = nullptr>
-#else
-template<unsigned int I, unsigned int F, typename R, typename T>
-#endif
-constexpr R fixedToFloatingPoint(T number)
-{
-	static_assert(sizeof(int) >= sizeof(T));
-	static_assert(I + F <= sizeof(T) * 8);
-
-	if constexpr (std::is_unsigned_v<T>)
-		return static_cast<R>(number) / static_cast<R>(1 << F);
-
-	/*
-	 * Recreate the upper bits in case of a negative number by shifting the sign
-	 * bit from the fixed point to the first bit of the unsigned and then right shifting
-	 * by the same amount which keeps the sign bit in place.
-	 * This can be optimized by the compiler quite well.
-	 */
-	int remaining_bits = sizeof(int) * 8 - (I + F);
-	int t = static_cast<int>(static_cast<unsigned>(number) << remaining_bits) >> remaining_bits;
-	return static_cast<R>(t) / static_cast<R>(1 << F);
-}
-
 template<unsigned int I, unsigned int F, typename T>
 struct FixedPointQTraits {
 private:
@@ -91,11 +42,25 @@ public:
 
 	static constexpr float toFloat(QuantizedType q)
 	{
-		return fixedToFloatingPoint<I, F, float, QuantizedType>(q);
+		if constexpr (std::is_unsigned_v<T>)
+			return static_cast<float>(q) / static_cast<float>(1 << F);
+
+		/*
+		 * Recreate the upper bits in case of a negative number by
+		 * shifting the sign bit from the fixed point to the first bit
+		 * of the unsigned and then right shifting by the same amount
+		 * which keeps the sign bit in place. This can be optimized by
+		 * the compiler quite well.
+		 */
+		static_assert(sizeof(int) >= sizeof(T));
+
+		int remaining_bits = sizeof(int) * 8 - (I + F);
+		int t = static_cast<int>(static_cast<unsigned>(q) << remaining_bits) >> remaining_bits;
+		return static_cast<float>(t) / static_cast<float>(1 << F);
 	}
 
-	static constexpr float min = fixedToFloatingPoint<I, F, float>(qMin);
-	static constexpr float max = fixedToFloatingPoint<I, F, float>(qMax);
+	static constexpr float min = toFloat(qMin);
+	static constexpr float max = toFloat(qMax);
 
 	static_assert(min < max, "FixedPointQTraits: Minimum must be less than maximum");
 
@@ -103,7 +68,13 @@ public:
 	static QuantizedType fromFloat(float v)
 	{
 		v = std::clamp(v, min, max);
-		return floatingToFixedPoint<I, F, QuantizedType, float>(v);
+
+		/*
+		 * The intermediate cast to int is needed on arm platforms to
+		 * properly cast negative values. See
+		 * https://embeddeduse.com/2013/08/25/casting-a-negative-float-to-an-unsigned-int/
+		 */
+		return static_cast<T>(static_cast<int>(std::round(v * (1 << F)))) & bitMask;
 	}
 };
 
