diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst
index 71ef2050..9792442d 100644
--- a/Documentation/guides/pipeline-handler.rst
+++ b/Documentation/guides/pipeline-handler.rst
@@ -209,7 +209,7 @@ methods for the overridden class members.
           int exportFrameBuffers(Camera *camera, Stream *stream,
           std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
-          int start(Camera *camera) override;
+          int start(Camera *camera, ControlList *controls) override;
           void stop(Camera *camera) override;
 
           int queueRequestDevice(Camera *camera, Request *request) override;
@@ -239,7 +239,7 @@ methods for the overridden class members.
           return -1;
    }
 
-   int PipelineHandlerVivid::start(Camera *camera)
+   int PipelineHandlerVivid::start(Camera *camera, ControlList *controls)
    {
           return -1;
    }
diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
index a2ee4e7e..a29caf08 100644
--- a/include/libcamera/camera.h
+++ b/include/libcamera/camera.h
@@ -99,7 +99,7 @@ public:
 	Request *createRequest(uint64_t cookie = 0);
 	int queueRequest(Request *request);
 
-	int start();
+	int start(ControlList *controls = nullptr);
 	int stop();
 
 private:
diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h
index a4e1b529..43de1110 100644
--- a/include/libcamera/internal/pipeline_handler.h
+++ b/include/libcamera/internal/pipeline_handler.h
@@ -78,7 +78,7 @@ public:
 	virtual int exportFrameBuffers(Camera *camera, Stream *stream,
 				       std::vector<std::unique_ptr<FrameBuffer>> *buffers) = 0;
 
-	virtual int start(Camera *camera) = 0;
+	virtual int start(Camera *camera, ControlList *controls) = 0;
 	virtual void stop(Camera *camera) = 0;
 
 	int queueRequest(Camera *camera, Request *request);
diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index fb76077f..3342214f 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -922,9 +922,10 @@ int Camera::queueRequest(Request *request)
 /**
  * \brief Start capture from camera
  *
- * Start the camera capture session. Once the camera is started the application
- * can queue requests to the camera to process and return to the application
- * until the capture session is terminated with \a stop().
+ * Start the camera capture session, optionally providing a list of controls to
+ * action before starting. Once the camera is started the application can queue
+ * requests to the camera to process and return to the application until the
+ * capture session is terminated with \a stop().
  *
  * \context This function may only be called when the camera is in the
  * Configured state as defined in \ref camera_operation, and shall be
@@ -935,7 +936,7 @@ int Camera::queueRequest(Request *request)
  * \retval -ENODEV The camera has been disconnected from the system
  * \retval -EACCES The camera is not in a state where it can be started
  */
-int Camera::start()
+int Camera::start(ControlList *controls)
 {
 	int ret = p_->isAccessAllowed(Private::CameraConfigured);
 	if (ret < 0)
@@ -944,7 +945,7 @@ int Camera::start()
 	LOG(Camera, Debug) << "Starting capture";
 
 	ret = p_->pipe_->invokeMethod(&PipelineHandler::start,
-				      ConnectionTypeBlocking, this);
+				      ConnectionTypeBlocking, this, controls);
 	if (ret)
 		return ret;
 
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index f5a20d30..1ef60555 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -100,7 +100,7 @@ public:
 	int exportFrameBuffers(Camera *camera, Stream *stream,
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
-	int start(Camera *camera) override;
+	int start(Camera *camera, ControlList *controls) override;
 	void stop(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
@@ -591,7 +591,7 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera)
 	return 0;
 }
 
-int PipelineHandlerIPU3::start(Camera *camera)
+int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] ControlList *controls)
 {
 	IPU3CameraData *data = cameraData(camera);
 	CIO2Device *cio2 = &data->cio2_;
diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index 1052bdce..307ed9a2 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -230,7 +230,7 @@ public:
 	int exportFrameBuffers(Camera *camera, Stream *stream,
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
-	int start(Camera *camera) override;
+	int start(Camera *camera, ControlList *controls) override;
 	void stop(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
@@ -712,7 +712,7 @@ int PipelineHandlerRPi::exportFrameBuffers([[maybe_unused]] Camera *camera, Stre
 	return ret;
 }
 
-int PipelineHandlerRPi::start(Camera *camera)
+int PipelineHandlerRPi::start(Camera *camera, [[maybe_unused]] ControlList *controls)
 {
 	RPiCameraData *data = cameraData(camera);
 	int ret;
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index aec590ff..15af7e5c 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -187,7 +187,7 @@ public:
 	int exportFrameBuffers(Camera *camera, Stream *stream,
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
-	int start(Camera *camera) override;
+	int start(Camera *camera, ControlList *controls) override;
 	void stop(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
@@ -822,7 +822,7 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera)
 	return 0;
 }
 
-int PipelineHandlerRkISP1::start(Camera *camera)
+int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] ControlList *controls)
 {
 	RkISP1CameraData *data = cameraData(camera);
 	int ret;
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 10223a9b..b842e16e 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -125,7 +125,7 @@ public:
 	int exportFrameBuffers(Camera *camera, Stream *stream,
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
-	int start(Camera *camera) override;
+	int start(Camera *camera, ControlList *controls) override;
 	void stop(Camera *camera) override;
 
 	bool match(DeviceEnumerator *enumerator) override;
@@ -637,7 +637,7 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,
 		return data->video_->exportBuffers(count, buffers);
 }
 
-int SimplePipelineHandler::start(Camera *camera)
+int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] ControlList *controls)
 {
 	SimpleCameraData *data = cameraData(camera);
 	V4L2VideoDevice *video = data->video_;
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index ba0efc8b..0c871b19 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -76,7 +76,7 @@ public:
 	int exportFrameBuffers(Camera *camera, Stream *stream,
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
-	int start(Camera *camera) override;
+	int start(Camera *camera, ControlList *controls) override;
 	void stop(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
@@ -236,7 +236,7 @@ int PipelineHandlerUVC::exportFrameBuffers(Camera *camera, Stream *stream,
 	return data->video_->exportBuffers(count, buffers);
 }
 
-int PipelineHandlerUVC::start(Camera *camera)
+int PipelineHandlerUVC::start(Camera *camera, [[maybe_unused]] ControlList *controls)
 {
 	UVCCameraData *data = cameraData(camera);
 	unsigned int count = data->stream_.configuration().bufferCount;
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index fc8085f1..3b868e4b 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -92,7 +92,7 @@ public:
 	int exportFrameBuffers(Camera *camera, Stream *stream,
 			       std::vector<std::unique_ptr<FrameBuffer>> *buffers) override;
 
-	int start(Camera *camera) override;
+	int start(Camera *camera, ControlList *controls) override;
 	void stop(Camera *camera) override;
 
 	int queueRequestDevice(Camera *camera, Request *request) override;
@@ -313,7 +313,7 @@ int PipelineHandlerVimc::exportFrameBuffers(Camera *camera, Stream *stream,
 	return data->video_->exportBuffers(count, buffers);
 }
 
-int PipelineHandlerVimc::start(Camera *camera)
+int PipelineHandlerVimc::start(Camera *camera, [[maybe_unused]] ControlList *controls)
 {
 	VimcCameraData *data = cameraData(camera);
 	unsigned int count = data->stream_.configuration().bufferCount;
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 918aea1e..60339e3e 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -351,6 +351,7 @@ const ControlList &PipelineHandler::properties(const Camera *camera) const
  * \fn PipelineHandler::start()
  * \brief Start capturing from a group of streams
  * \param[in] camera The camera to start
+ * \param[in] controls Controls for the IPA to action before starting the camera
  *
  * Start the group of streams that have been configured for capture by
  * \a configure(). The intended caller of this method is the Camera class which
