new file mode 100644
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025, matthias.fend@emfend.at
+ *
+ * Camera flash support
+ */
+#pragma once
+
+#include <memory>
+#include <stdint.h>
+#include <string>
+
+#include <libcamera/base/class.h>
+#include <libcamera/base/log.h>
+
+#include <libcamera/controls.h>
+
+namespace libcamera {
+
+class MediaEntity;
+class V4L2Subdevice;
+
+class CameraFlash : protected Loggable
+{
+public:
+ enum class Mode {
+ None,
+ Flash,
+ Torch,
+ };
+
+ enum class StrobeSource {
+ Software,
+ External,
+ };
+
+ explicit CameraFlash(const MediaEntity *entity);
+ ~CameraFlash();
+ int init();
+ std::optional<Mode> getMode() const;
+ int setMode(Mode mode);
+ const ControlInfo &getFlashIntensityInfo() const;
+ std::optional<int32_t> getFlashIntensity() const;
+ int setFlashIntensity(int32_t intensity);
+ const ControlInfo &getFlashTimeoutInfo() const;
+ std::optional<int32_t> getFlashTimeout() const;
+ int setFlashTimeout(int32_t timeout_us);
+ std::optional<StrobeSource> getStrobeSource() const;
+ int setStrobeSource(StrobeSource source);
+ int startStrobe();
+ int stopStrobe();
+ const ControlInfo &getTorchIntensityInfo() const;
+ std::optional<int32_t> getTorchIntensity() const;
+ int setTorchIntensity(int32_t intensity);
+
+protected:
+ std::string logPrefix() const override;
+
+private:
+ LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraFlash)
+
+ std::optional<int32_t> getSubdevControl(uint32_t id) const;
+ int setSubdevControl(uint32_t id, int32_t value);
+ int validateDriver();
+
+ const MediaEntity *entity_;
+ std::unique_ptr<V4L2Subdevice> subdev_;
+ std::string model_;
+ const ControlInfoMap *controlInfoMap_ = nullptr;
+};
+
+} /* namespace libcamera */
@@ -28,6 +28,7 @@
namespace libcamera {
+class CameraFlash;
class CameraLens;
class MediaEntity;
class SensorConfiguration;
@@ -48,6 +49,7 @@ public:
virtual V4L2Subdevice *device() = 0;
virtual CameraLens *focusLens() = 0;
+ virtual CameraFlash *flash() = 0;
virtual const std::vector<unsigned int> &mbusCodes() const = 0;
virtual std::vector<Size> sizes(unsigned int mbusCode) const = 0;
new file mode 100644
@@ -0,0 +1,249 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2025, matthias.fend@emfend.at
+ *
+ * Camera flash support
+ */
+
+#include "libcamera/internal/camera_flash.h"
+
+#include <libcamera/base/utils.h>
+
+#include "libcamera/internal/v4l2_subdevice.h"
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(CameraFlash)
+
+CameraFlash::CameraFlash(const MediaEntity *entity)
+ : entity_(entity)
+{
+}
+
+CameraFlash::~CameraFlash() = default;
+
+int CameraFlash::init()
+{
+ if (entity_->function() != MEDIA_ENT_F_FLASH) {
+ LOG(CameraFlash, Error)
+ << "Invalid flash function "
+ << utils::hex(entity_->function());
+ return -EINVAL;
+ }
+
+ subdev_ = std::make_unique<V4L2Subdevice>(entity_);
+ int ret = subdev_->open();
+ if (ret < 0)
+ return ret;
+
+ controlInfoMap_ = &subdev_->controls();
+
+ ret = validateDriver();
+ if (ret)
+ return ret;
+
+ model_ = subdev_->model();
+
+ return 0;
+}
+
+std::optional<CameraFlash::Mode> CameraFlash::getMode() const
+{
+ Mode mode;
+
+ auto v4l2Mode = getSubdevControl(V4L2_CID_FLASH_LED_MODE);
+ if (!v4l2Mode)
+ return std::nullopt;
+
+ switch (*v4l2Mode) {
+ case V4L2_FLASH_LED_MODE_FLASH:
+ mode = Mode::Flash;
+ break;
+ case V4L2_FLASH_LED_MODE_TORCH:
+ mode = Mode::Torch;
+ break;
+ case V4L2_FLASH_LED_MODE_NONE:
+ default:
+ mode = Mode::None;
+ break;
+ }
+
+ return mode;
+}
+
+int CameraFlash::setMode(Mode mode)
+{
+ int32_t v4l2Mode;
+
+ switch (mode) {
+ case Mode::Flash:
+ v4l2Mode = V4L2_FLASH_LED_MODE_FLASH;
+ break;
+ case Mode::Torch:
+ v4l2Mode = V4L2_FLASH_LED_MODE_TORCH;
+ break;
+ case Mode::None:
+ v4l2Mode = V4L2_FLASH_LED_MODE_NONE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return setSubdevControl(V4L2_CID_FLASH_LED_MODE, v4l2Mode);
+}
+
+const ControlInfo &CameraFlash::getFlashIntensityInfo() const
+{
+ return controlInfoMap_->find(V4L2_CID_FLASH_INTENSITY)->second;
+}
+
+std::optional<int32_t> CameraFlash::getFlashIntensity() const
+{
+ return getSubdevControl(V4L2_CID_FLASH_INTENSITY);
+}
+
+int CameraFlash::setFlashIntensity(int32_t intensity)
+{
+ return setSubdevControl(V4L2_CID_FLASH_INTENSITY, intensity);
+}
+
+const ControlInfo &CameraFlash::getFlashTimeoutInfo() const
+{
+ return controlInfoMap_->find(V4L2_CID_FLASH_TIMEOUT)->second;
+}
+
+std::optional<int32_t> CameraFlash::getFlashTimeout() const
+{
+ return getSubdevControl(V4L2_CID_FLASH_TIMEOUT);
+}
+
+int CameraFlash::setFlashTimeout(int32_t timeout)
+{
+ return setSubdevControl(V4L2_CID_FLASH_TIMEOUT, timeout);
+}
+
+std::optional<CameraFlash::StrobeSource> CameraFlash::getStrobeSource() const
+{
+ StrobeSource source;
+
+ auto v4l2Source = getSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE);
+ if (!v4l2Source)
+ return std::nullopt;
+
+ switch (*v4l2Source) {
+ case V4L2_FLASH_STROBE_SOURCE_EXTERNAL:
+ source = StrobeSource::External;
+ break;
+ case V4L2_FLASH_STROBE_SOURCE_SOFTWARE:
+ default:
+ source = StrobeSource::Software;
+ break;
+ }
+
+ return source;
+}
+
+int CameraFlash::setStrobeSource(StrobeSource source)
+{
+ int32_t v4l2Source;
+
+ switch (source) {
+ case StrobeSource::External:
+ v4l2Source = V4L2_FLASH_STROBE_SOURCE_EXTERNAL;
+ break;
+ case StrobeSource::Software:
+ v4l2Source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return setSubdevControl(V4L2_CID_FLASH_STROBE_SOURCE, v4l2Source);
+}
+
+int CameraFlash::startStrobe()
+{
+ return setSubdevControl(V4L2_CID_FLASH_STROBE, 1);
+}
+
+int CameraFlash::stopStrobe()
+{
+ return setSubdevControl(V4L2_CID_FLASH_STROBE_STOP, 1);
+}
+
+const ControlInfo &CameraFlash::getTorchIntensityInfo() const
+{
+ return controlInfoMap_->find(V4L2_CID_FLASH_TORCH_INTENSITY)->second;
+}
+
+std::optional<int32_t> CameraFlash::getTorchIntensity() const
+{
+ return getSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY);
+}
+
+int CameraFlash::setTorchIntensity(int32_t intensity)
+{
+ return setSubdevControl(V4L2_CID_FLASH_TORCH_INTENSITY, intensity);
+}
+
+std::string CameraFlash::logPrefix() const
+{
+ return "'" + entity_->name() + "'";
+}
+
+std::optional<int32_t> CameraFlash::getSubdevControl(uint32_t id) const
+{
+ ControlList controlList = subdev_->getControls(std::array{ id });
+
+ if (controlList.contains(id))
+ return std::nullopt;
+
+ return controlList.get(id).get<int32_t>();
+}
+
+int CameraFlash::setSubdevControl(uint32_t id, int32_t value)
+{
+ ControlList flashCtrls(*controlInfoMap_);
+
+ flashCtrls.set(id, value);
+
+ if (subdev_->setControls(&flashCtrls))
+ return -EINVAL;
+
+ return 0;
+}
+
+int CameraFlash::validateDriver()
+{
+ int ret = 0;
+ static constexpr uint32_t mandatoryControls[] = {
+ V4L2_CID_FLASH_LED_MODE,
+ V4L2_CID_FLASH_STROBE_SOURCE,
+ V4L2_CID_FLASH_STROBE,
+ V4L2_CID_FLASH_TIMEOUT,
+ V4L2_CID_FLASH_INTENSITY,
+ V4L2_CID_FLASH_TORCH_INTENSITY,
+ };
+
+ for (uint32_t ctrl : mandatoryControls) {
+ if (!controlInfoMap_->count(ctrl)) {
+ LOG(CameraFlash, Error)
+ << "Mandatory V4L2 control " << utils::hex(ctrl)
+ << " not available";
+ ret = -EINVAL;
+ }
+ }
+
+ if (ret) {
+ LOG(CameraFlash, Error)
+ << "The flash kernel driver needs to be fixed";
+ LOG(CameraFlash, Error)
+ << "See Documentation/flash_driver_requirements.rst in"
+ << " the libcamera sources for more information";
+ return ret;
+ }
+
+ return ret;
+}
+
+} /* namespace libcamera */
@@ -20,6 +20,7 @@ libcamera_internal_sources = files([
'bayer_format.cpp',
'byte_stream_buffer.cpp',
'camera_controls.cpp',
+ 'camera_flash.cpp',
'camera_lens.cpp',
'clock_recovery.cpp',
'control_serializer.cpp',
@@ -31,6 +31,7 @@
#include <libcamera/ipa/core_ipa_interface.h>
#include "libcamera/internal/bayer_format.h"
+#include "libcamera/internal/camera_flash.h"
#include "libcamera/internal/camera_lens.h"
#include "libcamera/internal/camera_sensor.h"
#include "libcamera/internal/camera_sensor_properties.h"
@@ -68,6 +69,7 @@ public:
V4L2Subdevice *device() override { return subdev_.get(); }
CameraLens *focusLens() override { return focusLens_.get(); }
+ CameraFlash *flash() override { return flash_.get(); }
const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; }
std::vector<Size> sizes(unsigned int mbusCode) const override;
@@ -139,6 +141,7 @@ private:
ControlList properties_;
std::unique_ptr<CameraLens> focusLens_;
+ std::unique_ptr<CameraFlash> flash_;
};
/**
@@ -665,6 +668,16 @@ int CameraSensorLegacy::discoverAncillaryDevices()
}
break;
+ case MEDIA_ENT_F_FLASH:
+ flash_ = std::make_unique<CameraFlash>(ancillary);
+ ret = flash_->init();
+ if (ret) {
+ LOG(CameraSensor, Error)
+ << "Flash initialisation failed, flash disabled";
+ flash_.reset();
+ }
+ break;
+
default:
LOG(CameraSensor, Warning)
<< "Unsupported ancillary entity function "
@@ -32,6 +32,7 @@
#include <libcamera/ipa/core_ipa_interface.h>
#include "libcamera/internal/bayer_format.h"
+#include "libcamera/internal/camera_flash.h"
#include "libcamera/internal/camera_lens.h"
#include "libcamera/internal/camera_sensor.h"
#include "libcamera/internal/camera_sensor_properties.h"
@@ -69,6 +70,7 @@ public:
V4L2Subdevice *device() override { return subdev_.get(); }
CameraLens *focusLens() override { return focusLens_.get(); }
+ CameraFlash *flash() override { return flash_.get(); }
const std::vector<unsigned int> &mbusCodes() const override { return mbusCodes_; }
std::vector<Size> sizes(unsigned int mbusCode) const override;
@@ -150,6 +152,7 @@ private:
ControlList properties_;
std::unique_ptr<CameraLens> focusLens_;
+ std::unique_ptr<CameraFlash> flash_;
};
/**
@@ -513,6 +516,16 @@ std::optional<int> CameraSensorRaw::init()
}
break;
+ case MEDIA_ENT_F_FLASH:
+ flash_ = std::make_unique<CameraFlash>(ancillary);
+ ret = flash_->init();
+ if (ret) {
+ LOG(CameraSensor, Error)
+ << "Flash initialisation failed, flash disabled";
+ flash_.reset();
+ }
+ break;
+
default:
LOG(CameraSensor, Warning)
<< "Unsupported ancillary entity function "
Add a class to model camera flash devices. Currently, only v4l2 flash devices are supported. The v4l2 flash devices are implemented similar to the camera lenses. Signed-off-by: Matthias Fend <matthias.fend@emfend.at> --- include/libcamera/internal/camera_flash.h | 72 ++++++++ include/libcamera/internal/camera_sensor.h | 2 + src/libcamera/camera_flash.cpp | 249 ++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + src/libcamera/sensor/camera_sensor_legacy.cpp | 13 ++ src/libcamera/sensor/camera_sensor_raw.cpp | 13 ++ 6 files changed, 350 insertions(+)