diff --git a/include/libcamera/ipa/agc_algorithm.h b/include/libcamera/ipa/agc_algorithm.h
new file mode 100644
index 00000000..4dd17103
--- /dev/null
+++ b/include/libcamera/ipa/agc_algorithm.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * agc_algorithm.h - AGC/AEC control algorithm interface
+ */
+#ifndef __LIBCAMERA_AGC_ALGORITHM_H__
+#define __LIBCAMERA_AGC_ALGORITHM_H__
+
+#include <libcamera/ipa/ipa_algorithm.h>
+
+namespace libcamera {
+
+class AgcAlgorithm : public IPAAlgorithm
+{
+public:
+	AgcAlgorithm(IPAController *controller)
+		: IPAAlgorithm(controller) {}
+	/* An AGC algorithm must provide the following: */
+	virtual unsigned int GetConvergenceFrames() const = 0;
+	virtual void SetEv(double ev) = 0;
+	virtual void SetFlickerPeriod(double flicker_period) = 0;
+	virtual void SetFixedShutter(double fixed_shutter) = 0; // microseconds
+	virtual void SetMaxShutter(double max_shutter) = 0; // microseconds
+	virtual void SetFixedAnalogueGain(double fixed_analogue_gain) = 0;
+	virtual void SetMeteringMode(std::string const &metering_mode_name) = 0;
+	virtual void SetExposureMode(std::string const &exposure_mode_name) = 0;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_AGC_ALGORITHM_H__ */
diff --git a/include/libcamera/ipa/awb_algorithm.h b/include/libcamera/ipa/awb_algorithm.h
new file mode 100644
index 00000000..37464d12
--- /dev/null
+++ b/include/libcamera/ipa/awb_algorithm.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * awb_algorithm.h - AWB control algorithm interface
+ */
+#ifndef __LIBCAMERA_AWB_ALGORITHM_H__
+#define __LIBCAMERA_AWB_ALGORITHM_H__
+
+#include <libcamera/ipa/ipa_algorithm.h>
+
+namespace libcamera {
+
+class AwbAlgorithm : public IPAAlgorithm
+{
+public:
+	AwbAlgorithm(IPAController *controller)
+		: IPAAlgorithm(controller) {}
+	/* An AWB algorithm must provide the following: */
+	virtual unsigned int GetConvergenceFrames() const = 0;
+	virtual void SetMode(std::string const &mode_name) = 0;
+	virtual void SetManualGains(double manual_r, double manual_b) = 0;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_AWB_ALGORITHM_H__ */
diff --git a/include/libcamera/ipa/ipa_algorithm.h b/include/libcamera/ipa/ipa_algorithm.h
new file mode 100644
index 00000000..e48b99a6
--- /dev/null
+++ b/include/libcamera/ipa/ipa_algorithm.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * ipa_algorithm.h - ISP control algorithm interface
+ */
+#ifndef __LIBCAMERA_IPA_ALGORITHM_H__
+#define __LIBCAMERA_IPA_ALGORITHM_H__
+
+/* All algorithms should be derived from this class and made available to the
+ * Controller. */
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "ipa_controller.h"
+
+namespace libcamera {
+
+/* This defines the basic interface for all control algorithms. */
+
+class IPAAlgorithm
+{
+public:
+	IPAAlgorithm(IPAController *controller)
+		: controller_(controller), paused_(false)
+	{
+	}
+	virtual ~IPAAlgorithm() = default;
+	virtual char const *Name() const = 0;
+	virtual bool IsPaused() const { return paused_; }
+	virtual void Pause() { paused_ = true; }
+	virtual void Resume() { paused_ = false; }
+	virtual void Initialise();
+	virtual void Prepare();
+	virtual void Process();
+
+private:
+	[[maybe_unused]] IPAController *controller_;
+	bool paused_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPA_ALGORITHM_H__ */
diff --git a/include/libcamera/ipa/ipa_controller.h b/include/libcamera/ipa/ipa_controller.h
new file mode 100644
index 00000000..953cad4a
--- /dev/null
+++ b/include/libcamera/ipa/ipa_controller.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * ipa_controller.h - ISP controller interface
+ */
+#ifndef __LIBCAMERA_IPA_CONTROLLER_H__
+#define __LIBCAMERA_IPA_CONTROLLER_H__
+
+// The Controller is simply a container for a collecting together a number of
+// "control algorithms" (such as AWB etc.) and for running them all in a
+// convenient manner.
+
+#include <string>
+#include <vector>
+
+namespace libcamera {
+
+class IPAAlgorithm;
+typedef std::unique_ptr<IPAAlgorithm> IPAAlgorithmPtr;
+
+class IPAController
+{
+public:
+	IPAController();
+	~IPAController();
+	IPAAlgorithm *CreateAlgorithm(char const *name);
+	void Initialise();
+	void Prepare();
+	void Process();
+	IPAAlgorithm *GetAlgorithm(std::string const &name) const;
+
+protected:
+	std::vector<IPAAlgorithmPtr> algorithms_;
+};
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPA_CONTROLLER_H__ */
diff --git a/include/libcamera/ipa/meson.build b/include/libcamera/ipa/meson.build
index a4d3f868..e56d8b00 100644
--- a/include/libcamera/ipa/meson.build
+++ b/include/libcamera/ipa/meson.build
@@ -1,6 +1,10 @@
 # SPDX-License-Identifier: CC0-1.0
 
 libcamera_ipa_headers = files([
+    'agc_algorithm.h',
+    'awb_algorithm.h',
+    'ipa_algorithm.h',
+    'ipa_controller.h',
     'ipa_controls.h',
     'ipa_interface.h',
     'ipa_module_info.h',
diff --git a/src/ipa/libipa/ipa_algorithm.cpp b/src/ipa/libipa/ipa_algorithm.cpp
new file mode 100644
index 00000000..16fb29ce
--- /dev/null
+++ b/src/ipa/libipa/ipa_algorithm.cpp
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * ipa_algorithm.cpp - ISP control algorithms
+ */
+#include <iostream>
+
+#include <libcamera/ipa/ipa_algorithm.h>
+
+using namespace libcamera;
+
+void IPAAlgorithm::Initialise()
+{
+	std::cout << "Entering: " << __func__ << std::endl;
+}
+
+void IPAAlgorithm::Prepare() {}
+
+void IPAAlgorithm::Process() {}
diff --git a/src/ipa/libipa/ipa_controller.cpp b/src/ipa/libipa/ipa_controller.cpp
new file mode 100644
index 00000000..e2cde8ce
--- /dev/null
+++ b/src/ipa/libipa/ipa_controller.cpp
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * ipa_controller.cpp - ISP controller
+ */
+
+#include "libcamera/internal/log.h"
+
+#include <libcamera/ipa/ipa_algorithm.h>
+#include <libcamera/ipa/ipa_controller.h>
+
+using namespace libcamera;
+
+LOG_DEFINE_CATEGORY(IPAController)
+
+IPAController::IPAController() {}
+
+IPAController::~IPAController() {}
+
+IPAAlgorithm *IPAController::CreateAlgorithm(char const *name)
+{
+	LOG(IPAController, Error) << "Create algorithm " << name;
+	return nullptr;
+}
+
+void IPAController::Initialise()
+{
+	for (auto &algo : algorithms_)
+		algo->Initialise();
+}
+
+void IPAController::Prepare()
+{
+	for (auto &algo : algorithms_)
+		if (!algo->IsPaused())
+			algo->Prepare();
+}
+
+void IPAController::Process()
+{
+	for (auto &algo : algorithms_)
+		if (!algo->IsPaused())
+			algo->Process();
+}
diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
index b29ef0f4..1693e489 100644
--- a/src/ipa/libipa/meson.build
+++ b/src/ipa/libipa/meson.build
@@ -4,6 +4,8 @@ libipa_headers = files([
 ])
 
 libipa_sources = files([
+    'ipa_algorithm.cpp',
+    'ipa_controller.cpp',
 ])
 
 libipa_includes = include_directories('..')
