diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h
index 9b37dfb16b89..d827318ee0fa 100644
--- a/include/libcamera/controls.h
+++ b/include/libcamera/controls.h
@@ -117,11 +117,13 @@ public:
 	const_iterator begin() const { return controls_.begin(); }
 	const_iterator end() const { return controls_.end(); }
 
+	bool contains(ControlId id) const;
 	bool contains(const ControlInfo *info) const { return controls_.count(info); };
 	bool empty() const { return controls_.empty(); }
 	std::size_t size() const { return controls_.size(); }
 	void clear() { controls_.clear(); }
 
+	ControlValue &operator[](ControlId id);
 	ControlValue &operator[](const ControlInfo *info) { return controls_[info]; }
 
 	void update(const ControlList &list);
diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp
index e4c41b97a354..17e09fc7f153 100644
--- a/src/libcamera/controls.cpp
+++ b/src/libcamera/controls.cpp
@@ -10,6 +10,8 @@
 #include <sstream>
 #include <string>
 
+#include <libcamera/camera.h>
+
 #include "log.h"
 #include "utils.h"
 
@@ -372,6 +374,30 @@ ControlList::ControlList(Camera *camera)
  * instance
  */
 
+/**
+ * \brief Check if the ist contains a control with the specified \a id
+ * \param[in] id The control ID
+ *
+ * The behaviour is undefined if the control \a id is not supported by the
+ * camera that the ControlList refers to.
+ *
+ * \return True if the list contains a matching control, false otherwise
+ */
+bool ControlList::contains(ControlId id) const
+{
+	const ControlInfoMap &controls = camera_->controls();
+	const auto iter = controls.find(id);
+	if (iter == controls.end()) {
+		LOG(Controls, Error)
+			<< "Camera " << camera_->name()
+			<< " does not support control " << id;
+
+		return false;
+	}
+
+	return controls_.find(&iter->second) != controls_.end();
+}
+
 /**
  * \fn ControlList::contains(const ControlInfo *info) const
  * \brief Check if the ist contains a control with the specified \a info
@@ -396,6 +422,34 @@ ControlList::ControlList(Camera *camera)
  * \brief Removes all controls from the list
  */
 
+/**
+ * \brief Access or insert the control specified by \a id
+ * \param[in] id The control ID
+ *
+ * This method returns a reference to the control identified by \a id, inserting
+ * it in the list if the ID is not already present.
+ *
+ * The behaviour is undefined if the control \a id is not supported by the
+ * camera that the ControlList refers to.
+ *
+ * \return A reference to the value of the control identified by \a id
+ */
+ControlValue &ControlList::operator[](ControlId id)
+{
+	const ControlInfoMap &controls = camera_->controls();
+	const auto iter = controls.find(id);
+	if (iter == controls.end()) {
+		LOG(Controls, Error)
+			<< "Camera " << camera_->name()
+			<< " does not support control " << id;
+
+		static ControlValue empty;
+		return empty;
+	}
+
+	return controls_[&iter->second];
+}
+
 /**
  * \fn ControlList::operator[](const ControlInfo *info)
  * \brief Access or insert the control specified by \a info
@@ -413,6 +467,9 @@ ControlList::ControlList(Camera *camera)
  *
  * Update all controls in the ControlList, by the values given by \a list
  * If the list already contains a control of this ID then it will be overwritten
+ *
+ * The behaviour is undefined if the two lists refer to different Camera
+ * instances.
  */
 void ControlList::update(const ControlList &list)
 {
