diff --git a/src/ipa/raspberrypi/controller/controller.cpp b/src/ipa/raspberrypi/controller/controller.cpp
index bceb62540dbd..bbd382bce3ab 100644
--- a/src/ipa/raspberrypi/controller/controller.cpp
+++ b/src/ipa/raspberrypi/controller/controller.cpp
@@ -44,26 +44,58 @@ int Controller::read(char const *filename)
 	}
 
 	std::unique_ptr<YamlObject> root = YamlParser::parse(file);
+	double version = (*root)["version"].get<double>(1.0);
 
-	for (auto const &[key, value] : root->asDict()) {
-		Algorithm *algo = createAlgorithm(key.c_str());
-		if (algo) {
-			int ret = algo->read(value);
+	if (version < 2.0) {
+		LOG(RPiController, Warning)
+			<< "This format of the tuning file will be deprecated soon!"
+			<< " Please use the convert_tuning.py utility to update to version 2.0.";
+
+		for (auto const &[key, value] : root->asDict()) {
+			int ret = createAlgorithm(key, value);
 			if (ret)
 				return ret;
-			algorithms_.push_back(AlgorithmPtr(algo));
-		} else
-			LOG(RPiController, Warning)
-				<< "No algorithm found for \"" << key << "\"";
+		}
+	} else if (version < 3.0) {
+		if (!root->contains("algorithms")) {
+			LOG(RPiController, Error)
+				<< "Tuning file " << filename
+				<< " does not have an \"algorithms\" list!";
+			return -EINVAL;
+		}
+
+		for (auto const &rootAlgo : (*root)["algorithms"].asList())
+			for (auto const &[key, value] : rootAlgo.asDict()) {
+				int ret = createAlgorithm(key, value);
+				if (ret)
+					return ret;
+			}
+	} else {
+		LOG(RPiController, Error)
+			<< "Unrecognised version " << version
+			<< " for the tuning file " << filename;
+		return -EINVAL;
 	}
 
 	return 0;
 }
 
-Algorithm *Controller::createAlgorithm(char const *name)
+int Controller::createAlgorithm(const std::string &name, const YamlObject &params)
 {
-	auto it = getAlgorithms().find(std::string(name));
-	return it != getAlgorithms().end() ? (*it->second)(this) : nullptr;
+	auto it = getAlgorithms().find(name);
+	if (it == getAlgorithms().end()) {
+		LOG(RPiController, Warning)
+			<< "No algorithm found for \"" << name << "\"";
+		return 0;
+	}
+
+	Algorithm *algo = (*it->second)(this);
+	int ret = algo->read(params);
+	if (ret)
+		return ret;
+
+	algorithms_.push_back(AlgorithmPtr(algo));
+	return 0;
 }
 
 void Controller::initialise()
diff --git a/src/ipa/raspberrypi/controller/controller.h b/src/ipa/raspberrypi/controller/controller.h
index 841783bb7a5c..6be1e3cfa156 100644
--- a/src/ipa/raspberrypi/controller/controller.h
+++ b/src/ipa/raspberrypi/controller/controller.h
@@ -17,6 +17,8 @@
 
 #include <linux/bcm2835-isp.h>
 
+#include "libcamera/internal/yaml_parser.h"
+
 #include "camera_mode.h"
 #include "device_status.h"
 #include "metadata.h"
@@ -40,7 +42,6 @@ public:
 	Controller();
 	Controller(char const *jsonFilename);
 	~Controller();
-	Algorithm *createAlgorithm(char const *name);
 	int read(char const *filename);
 	void initialise();
 	void switchMode(CameraMode const &cameraMode, Metadata *metadata);
@@ -50,6 +51,8 @@ public:
 	Algorithm *getAlgorithm(std::string const &name) const;
 
 protected:
+	int createAlgorithm(const std::string &name, const libcamera::YamlObject &params);
+
 	Metadata globalMetadata_;
 	std::vector<AlgorithmPtr> algorithms_;
 	bool switchModeCalled_;
