diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h
index 06c8292ca30129de..b3aaaeaf829d97c0 100644
--- a/include/libcamera/internal/camera_sensor.h
+++ b/include/libcamera/internal/camera_sensor.h
@@ -47,6 +47,7 @@ public:
 	int init();
 
 	const std::string &model() const { return model_; }
+	const std::string &id() const { return id_; }
 	const MediaEntity *entity() const { return entity_; }
 	const std::vector<unsigned int> &mbusCodes() const { return mbusCodes_; }
 	const std::vector<Size> &sizes() const { return sizes_; }
@@ -65,6 +66,7 @@ public:
 
 protected:
 	std::string logPrefix() const override;
+	virtual std::string generateID() const;
 
 private:
 	const MediaEntity *entity_;
@@ -72,6 +74,7 @@ private:
 	unsigned int pad_;
 
 	std::string model_;
+	std::string id_;
 
 	V4L2Subdevice::Formats formats_;
 	Size resolution_;
diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp
index 350f49accad99c7b..282cedecaf28fb3c 100644
--- a/src/libcamera/camera_sensor.cpp
+++ b/src/libcamera/camera_sensor.cpp
@@ -204,6 +204,11 @@ int CameraSensor::init()
 	if (ret < 0)
 		return ret;
 
+	/* Generate a unique ID for the sensor. */
+	id_ = generateID();
+	if (id_.empty())
+		return -EINVAL;
+
 	/* Retrieve and store the camera sensor properties. */
 	const ControlInfoMap &controls = subdev_->controls();
 	int32_t propertyValue;
@@ -283,6 +288,16 @@ int CameraSensor::init()
  * \return The sensor model name
  */
 
+/**
+ * \fn CameraSensor::id()
+ * \brief Retrieve the sensor ID
+ *
+ * The sensor ID is a free-form string that uniquely identifies the sensor in
+ * the system. The ID satisfy the requirements to be used as a camera ID.
+ *
+ * \return The sensor ID
+ */
+
 /**
  * \fn CameraSensor::entity()
  * \brief Retrieve the sensor media entity
@@ -541,4 +556,29 @@ std::string CameraSensor::logPrefix() const
 	return "'" + entity_->name() + "'";
 }
 
+/**
+ * \brief Generate a sensor ID for the sensor
+ *
+ * The generated string satisfy the requirements to be used as ID for a camera.
+ * This default implementation retrieves the ID form the firmware ID associated
+ * with the sensors V4L2 subdevice, that meets this criteria.
+ *
+ * It is possible to override this function to allow for more advanced IDs to be
+ * generated for specific sensors. Any alternative implementation is responsible
+ * for that the generated ID satisfy the requirements to be used as a camera ID.
+ *
+ * \sa id()
+ * \return Sensor ID on success or empty string on failure
+ */
+std::string CameraSensor::generateID() const
+{
+	std::string id;
+	if (utils::tryLookupFirmwareID(subdev_->devicePath(), &id)) {
+		LOG(CameraSensor, Error) << "Can't get sensor ID from firmware";
+		return {};
+	}
+
+	return id;
+}
+
 } /* namespace libcamera */
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index 4f461b928514022d..b3348ab5d987d506 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -38,6 +38,21 @@ namespace libcamera {
 
 LOG_DEFINE_CATEGORY(VIMC)
 
+class VimcCameraSensor : public CameraSensor
+{
+public:
+	VimcCameraSensor(const MediaEntity *entity)
+		: CameraSensor(entity)
+	{
+	}
+
+protected:
+	std::string generateID() const override
+	{
+		return "VIMC " + entity()->name();
+	}
+};
+
 class VimcCameraData : public CameraData
 {
 public:
@@ -61,7 +76,7 @@ public:
 	void bufferReady(FrameBuffer *buffer);
 
 	MediaDevice *media_;
-	CameraSensor *sensor_;
+	VimcCameraSensor *sensor_;
 	V4L2Subdevice *debayer_;
 	V4L2Subdevice *scaler_;
 	V4L2VideoDevice *video_;
@@ -457,7 +472,7 @@ int VimcCameraData::init()
 		return ret;
 
 	/* Create and open the camera sensor, debayer, scaler and video device. */
-	sensor_ = new CameraSensor(media_->getEntityByName("Sensor B"));
+	sensor_ = new VimcCameraSensor(media_->getEntityByName("Sensor B"));
 	ret = sensor_->init();
 	if (ret)
 		return ret;
diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp
index 8c7fd1d2d4445db3..50157b234fd40933 100644
--- a/test/camera-sensor.cpp
+++ b/test/camera-sensor.cpp
@@ -17,6 +17,7 @@
 #include "libcamera/internal/v4l2_subdevice.h"
 
 #include "test.h"
+#include "vimc_sensor_test.h"
 
 using namespace std;
 using namespace libcamera;
@@ -50,7 +51,7 @@ protected:
 			return TestFail;
 		}
 
-		sensor_ = new CameraSensor(entity);
+		sensor_ = new TestVimcCameraSensor(entity);
 		if (sensor_->init() < 0) {
 			cerr << "Unable to initialise camera sensor" << endl;
 			return TestFail;
diff --git a/test/libtest/vimc_sensor_test.h b/test/libtest/vimc_sensor_test.h
new file mode 100644
index 0000000000000000..1454a1c310f0dc9c
--- /dev/null
+++ b/test/libtest/vimc_sensor_test.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * vimc_sensor_test.h - vimc_sensor test class
+ */
+#ifndef __LIBCAMERA_VIMC_SENSOR_TEST_H__
+#define __LIBCAMERA_VIMC_SENSOR_TEST_H__
+
+#include "libcamera/internal/camera_sensor.h"
+
+using namespace libcamera;
+
+class TestVimcCameraSensor : public CameraSensor
+{
+public:
+	TestVimcCameraSensor(const MediaEntity *entity)
+		: CameraSensor(entity)
+	{
+	}
+
+protected:
+	std::string generateID() const override
+	{
+		return "VIMC " + entity()->name();
+	}
+};
+
+#endif /* __LIBCAMERA_VIMC_SENSOR_TEST_H__ */
diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
index f23aaf8f514bc050..c7a3479963be9b78 100644
--- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp
+++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
@@ -12,6 +12,8 @@
 #include "libcamera/internal/device_enumerator.h"
 #include "libcamera/internal/media_device.h"
 
+#include "vimc_sensor_test.h"
+
 #include "v4l2_videodevice_test.h"
 
 using namespace std;
@@ -61,7 +63,7 @@ int V4L2VideoDeviceTest::init()
 		return TestFail;
 
 	if (driver_ == "vimc") {
-		sensor_ = new CameraSensor(media_->getEntityByName("Sensor A"));
+		sensor_ = new TestVimcCameraSensor(media_->getEntityByName("Sensor A"));
 		if (sensor_->init())
 			return TestFail;
 
