@@ -64,6 +64,8 @@  struct ipa_context_ops {
 	void (*destroy)(struct ipa_context *ctx);
 	void *(*get_interface)(struct ipa_context *ctx);
 	void (*init)(struct ipa_context *ctx);
+	int (*start)(struct ipa_context *ctx);
+	void (*stop)(struct ipa_context *ctx);
 	void (*register_callbacks)(struct ipa_context *ctx,
 				   const struct ipa_callback_ops *callbacks,
 				   void *cb_ctx);
@@ -120,6 +122,8 @@  public:
 	virtual ~IPAInterface() {}
 
 	virtual int init() = 0;
+	virtual int start() = 0;
+	virtual void stop() = 0;
 
 	virtual void configure(const std::map<unsigned int, IPAStream> &streamConfig,
 			       const std::map<unsigned int, const ControlInfoMap &> &entityControls) = 0;
@@ -15,6 +15,8 @@  namespace libcamera {
 enum IPAOperationCode {
 	IPAOperationNone,
 	IPAOperationInit,
+	IPAOperationStart,
+	IPAOperationStop,
 };
 
 } /* namespace libcamera */
@@ -86,6 +86,20 @@  void IPAInterfaceWrapper::init(struct ipa_context *_ctx)
 	ctx->ipa_->init();
 }
 
+int IPAInterfaceWrapper::start(struct ipa_context *_ctx)
+{
+	IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
+
+	return ctx->ipa_->start();
+}
+
+void IPAInterfaceWrapper::stop(struct ipa_context *_ctx)
+{
+	IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
+
+	ctx->ipa_->stop();
+}
+
 void IPAInterfaceWrapper::register_callbacks(struct ipa_context *_ctx,
 					     const struct ipa_callback_ops *callbacks,
 					     void *cb_ctx)
@@ -234,6 +248,8 @@  const struct ipa_context_ops IPAInterfaceWrapper::operations_ = {
 	.destroy = &IPAInterfaceWrapper::destroy,
 	.get_interface = &IPAInterfaceWrapper::get_interface,
 	.init = &IPAInterfaceWrapper::init,
+	.start = &IPAInterfaceWrapper::start,
+	.stop = &IPAInterfaceWrapper::stop,
 	.register_callbacks = &IPAInterfaceWrapper::register_callbacks,
 	.configure = &IPAInterfaceWrapper::configure,
 	.map_buffers = &IPAInterfaceWrapper::map_buffers,
@@ -24,6 +24,8 @@  private:
 	static void destroy(struct ipa_context *ctx);
 	static void *get_interface(struct ipa_context *ctx);
 	static void init(struct ipa_context *ctx);
+	static int start(struct ipa_context *ctx);
+	static void stop(struct ipa_context *ctx);
 	static void register_callbacks(struct ipa_context *ctx,
 				       const struct ipa_callback_ops *callbacks,
 				       void *cb_ctx);
@@ -33,6 +33,8 @@  class IPARkISP1 : public IPAInterface
 {
 public:
 	int init() override { return 0; }
+	int start() override { return 0; }
+	void stop() override {}
 
 	void configure(const std::map<unsigned int, IPAStream> &streamConfig,
 		       const std::map<unsigned int, const ControlInfoMap &> &entityControls) override;
@@ -32,6 +32,10 @@  public:
 	~IPAVimc();
 
 	int init() override;
+
+	int start() override;
+	void stop() override;
+
 	void configure(const std::map<unsigned int, IPAStream> &streamConfig,
 		       const std::map<unsigned int, const ControlInfoMap &> &entityControls) override {}
 	void mapBuffers(const std::vector<IPABuffer> &buffers) override {}
@@ -66,6 +70,22 @@  int IPAVimc::init()
 	return 0;
 }
 
+int IPAVimc::start()
+{
+	trace(IPAOperationStart);
+
+	LOG(IPAVimc, Debug) << "start vimc IPA!";
+
+	return 0;
+}
+
+void IPAVimc::stop()
+{
+	trace(IPAOperationStop);
+
+	LOG(IPAVimc, Debug) << "stop vimc IPA!";
+}
+
 void IPAVimc::initTrace()
 {
 	struct stat fifoStat;
@@ -20,6 +20,8 @@  public:
 	~IPAContextWrapper();
 
 	int init() override;
+	int start() override;
+	void stop() override;
 	void configure(const std::map<unsigned int, IPAStream> &streamConfig,
 		       const std::map<unsigned int, const ControlInfoMap &> &entityControls) override;
 
@@ -82,6 +82,28 @@  int IPAContextWrapper::init()
 	return 0;
 }
 
+int IPAContextWrapper::start()
+{
+	if (intf_)
+		return intf_->start();
+
+	if (!ctx_)
+		return 0;
+
+	return ctx_->ops->start(ctx_);
+}
+
+void IPAContextWrapper::stop()
+{
+	if (intf_)
+		return intf_->stop();
+
+	if (!ctx_)
+		return;
+
+	ctx_->ops->stop(ctx_);
+}
+
 void IPAContextWrapper::configure(const std::map<unsigned int, IPAStream> &streamConfig,
 				  const std::map<unsigned int, const ControlInfoMap &> &entityControls)
 {
@@ -235,6 +235,20 @@ 
  * \sa libcamera::IPAInterface::init()
  */
 
+/**
+ * \var ipa_context_ops::start
+ * \brief Start the IPA context
+ *
+ * \sa libcamera::IPAInterface::start()
+ */
+
+/**
+ * \var ipa_context_ops::stop
+ * \brief Stop the IPA context
+ *
+ * \sa libcamera::IPAInterface::stop()
+ */
+
 /**
  * \var ipa_context_ops::register_callbacks
  * \brief Register callback operation from the IPA to the pipeline handler
@@ -412,6 +426,24 @@  namespace libcamera {
  * \brief Initialise the IPAInterface
  */
 
+/**
+ * \fn IPAInterface::start()
+ * \brief Start the IPA
+ *
+ * This method informs the IPA module that the camera is about to be started.
+ * The IPA module shall prepare any resources it needs to operate.
+ *
+ * \return 0 on success or a negative error code otherwise
+ */
+
+/**
+ * \fn IPAInterface::stop()
+ * \brief Stop the IPA
+ *
+ * This method informs the IPA module that the camera is stopped. The IPA module
+ * shall release resources prepared in start().
+ */
+
 /**
  * \fn IPAInterface::configure()
  * \brief Configure the IPA stream and sensor settings
@@ -27,6 +27,8 @@  public:
 	~IPAProxyLinux();
 
 	int init() override { return 0; }
+	int start() override { return 0; }
+	void stop() override {}
 	void configure(const std::map<unsigned int, IPAStream> &streamConfig,
 		       const std::map<unsigned int, const ControlInfoMap &> &entityControls) override {}
 	void mapBuffers(const std::vector<IPABuffer> &buffers) override {}
@@ -109,6 +109,28 @@  protected:
 			return TestFail;
 		}
 
+		/* Test start of IPA module. */
+		ipa_->start();
+		timer.start(1000);
+		while (timer.isRunning() && trace_ != IPAOperationStart)
+			dispatcher->processEvents();
+
+		if (trace_ != IPAOperationStart) {
+			cerr << "Failed to test IPA start sequence" << endl;
+			return TestFail;
+		}
+
+		/* Test stop of IPA module. */
+		ipa_->stop();
+		timer.start(1000);
+		while (timer.isRunning() && trace_ != IPAOperationStop)
+			dispatcher->processEvents();
+
+		if (trace_ != IPAOperationStop) {
+			cerr << "Failed to test IPA stop sequence" << endl;
+			return TestFail;
+		}
+
 		return TestPass;
 	}
 
@@ -27,6 +27,8 @@  using namespace std;
 
 enum Operation {
 	Op_init,
+	Op_start,
+	Op_stop,
 	Op_configure,
 	Op_mapBuffers,
 	Op_unmapBuffers,
@@ -47,6 +49,17 @@  public:
 		return 0;
 	}
 
+	int start() override
+	{
+		report(Op_start, TestPass);
+		return 0;
+	}
+
+	void stop() override
+	{
+		report(Op_stop, TestPass);
+	}
+
 	void configure(const std::map<unsigned int, IPAStream> &streamConfig,
 		       const std::map<unsigned int, const ControlInfoMap &> &entityControls) override
 	{
@@ -323,12 +336,26 @@  protected:
 			return TestFail;
 
 		/*
-		 * Test init() last to ensure nothing in the wrappers or
-		 * serializer depends on init() being called first.
+		 * Test init(), start() and stop() last to ensure nothing in the
+		 * wrappers or serializer depends on them being called first.
 		 */
 		ret = INVOKE(init);
-		if (ret == TestFail)
+		if (ret == TestFail) {
+			cerr << "Failed to run init()";
 			return TestFail;
+		}
+
+		ret = INVOKE(start);
+		if (ret == TestFail) {
+			cerr << "Failed to run start()";
+			return TestFail;
+		}
+
+		ret = INVOKE(stop);
+		if (ret == TestFail) {
+			cerr << "Failed to run stop()";
+			return TestFail;
+		}
 
 		return TestPass;
 	}