[{"id":38626,"web_url":"https://patchwork.libcamera.org/comment/38626/","msgid":"<aepehzQC1IlaKrkv@zed>","date":"2026-04-23T18:02:16","subject":"Re: [PATCH v8 3/8] libcamera: mali-c55: Split TPG and Inline camera\n\thandling","submitter":{"id":143,"url":"https://patchwork.libcamera.org/api/people/143/","name":"Jacopo Mondi","email":"jacopo.mondi@ideasonboard.com"},"content":"Hi Dan\n\nOn Thu, Apr 23, 2026 at 03:54:29PM +0100, Dan Scally wrote:\n> Hi Jacopo\n>\n> On 01/04/2026 17:25, Jacopo Mondi wrote:\n> > In order to prepare to support memory input cameras, split the handling of\n> > the TPG and Inline camera cases.\n> >\n> > The Mali C55 pipeline handler uses the entity and subdevice stored in the\n> > CameraData to support both the handling of the TPG and of the Inline (CSI-2\n> > + sensor) use cases. Adding support for memory cameras by using the CRU unit\n> > would add yet-another special case making the code harder to follow and\n> > more prone to errors.\n> >\n> > Split the handling of the TPG and Inline cameras by introducing an\n> > std::variant<> variable and to deflect the functions called on the\n> > camera data to the correct type by using overloaded std::visit<>().\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n> > Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>\n> > ---\n>\n> Yeah I like this. TIL of std::visit which is quite neat, but even just the explicit variance is cleaner.\n>\n> One question below rather than a comment, but:\n>\n> Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>\n>\n>\n> >   src/libcamera/pipeline/mali-c55/mali-c55.cpp | 278 ++++++++++++++++-----------\n> >   1 file changed, 162 insertions(+), 116 deletions(-)\n> >\n> > diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > index c209b0b070b1..26dfd0aef73c 100644\n> > --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n> > @@ -11,12 +11,14 @@\n> >   #include <memory>\n> >   #include <set>\n> >   #include <string>\n> > +#include <variant>\n> >   #include <linux/mali-c55-config.h>\n> >   #include <linux/media-bus-format.h>\n> >   #include <linux/media.h>\n> >   #include <libcamera/base/log.h>\n> > +#include <libcamera/base/utils.h>\n> >   #include <libcamera/camera.h>\n> >   #include <libcamera/formats.h>\n> > @@ -92,17 +94,77 @@ struct MaliC55FrameInfo {\n> >   class MaliC55CameraData : public Camera::Private\n> >   {\n> >   public:\n> > -\tMaliC55CameraData(PipelineHandler *pipe, MediaEntity *entity)\n> > -\t\t: Camera::Private(pipe), entity_(entity)\n> > +\tstruct Tpg {\n> > +\t\tstd::vector<Size> sizes(unsigned int mbusCode) const;\n> > +\n> > +\t\tSize resolution_;\n> > +\t\tstd::unique_ptr<V4L2Subdevice> sd_;\n> > +\t};\n> > +\n> > +\tstruct Inline {\n> > +\t\tstd::unique_ptr<V4L2Subdevice> csi2_;\n> > +\t\tstd::unique_ptr<CameraSensor> sensor_;\n> > +\t};\n> > +\tusing CameraType = std::variant<Tpg, Inline>;\n> > +\n> > +\tMaliC55CameraData(PipelineHandler *pipe)\n> > +\t\t: Camera::Private(pipe)\n> >   \t{\n> >   \t}\n> > -\tint init();\n> >   \tint loadIPA();\n> > -\t/* Deflect these functionalities to either TPG or CameraSensor. */\n> > -\tstd::vector<Size> sizes(unsigned int mbusCode) const;\n> > -\tSize resolution() const;\n> > +\tTpg *initTpg(MediaEntity *entity);\n> > +\tInline *initInline(MediaEntity *entity);\n> > +\n> > +\tstd::vector<Size> sizes(unsigned int mbusCode) const\n> > +\t{\n> > +\t\treturn std::visit(utils::overloaded{\n> > +\t\t\t[&](const Tpg &tpg) -> std::vector<Size> {\n> > +\t\t\t\treturn tpg.sizes(mbusCode);\n> > +\t\t\t},\n> > +\t\t\t[&](const Inline &in) -> std::vector<Size> {\n> > +\t\t\t\treturn in.sensor_->sizes(mbusCode);\n> > +\t\t\t}\n> > +\t\t}, input_);\n> > +\t}\n> > +\n> > +\tV4L2Subdevice *subdev() const\n> > +\t{\n> > +\t\treturn std::visit(utils::overloaded{\n> > +\t\t\t[&](const Tpg &tpg) -> V4L2Subdevice * {\n> > +\t\t\t\treturn tpg.sd_.get();\n> > +\t\t\t},\n> > +\t\t\t[&](const Inline &in) -> V4L2Subdevice * {\n> > +\t\t\t\treturn in.sensor_->device();\n> > +\t\t\t},\n> > +\t\t}, input_);\n> > +\t}\n> > +\n> > +\tCameraSensor *sensor() const\n> > +\t{\n> > +\t\treturn std::visit(utils::overloaded{\n> > +\t\t\t[&](auto &) -> CameraSensor * {\n>\n> Can this act like a wildcard, in the sense of rather than specifying a const\n> Tpg & this would just be \"anything else\"?\n\nI think this is intentional, as it will also match on the coming\nMemory overload.\n\n>\n> Thanks\n> Dan\n>\n> > +\t\t\t\tASSERT(false);\n> > +\t\t\t\treturn nullptr;\n> > +\t\t\t},\n> > +\t\t\t[&](const Inline &in) -> CameraSensor * {\n> > +\t\t\t\treturn in.sensor_.get();\n> > +\t\t\t},\n> > +\t\t}, input_);\n> > +\t}\n> > +\n> > +\tSize resolution() const\n> > +\t{\n> > +\t\treturn std::visit(utils::overloaded{\n> > +\t\t\t[&](const Tpg &tpg) -> Size {\n> > +\t\t\t\treturn tpg.resolution_;\n> > +\t\t\t},\n> > +\t\t\t[&](const Inline &in) -> Size {\n> > +\t\t\t\treturn in.sensor_->resolution();\n> > +\t\t\t},\n> > +\t\t}, input_);\n> > +\t}\n> >   \tint pixfmtToMbusCode(const PixelFormat &pixFmt) const;\n> >   \tconst PixelFormat &bestRawFormat() const;\n> > @@ -112,11 +174,6 @@ public:\n> >   \tPixelFormat adjustRawFormat(const PixelFormat &pixFmt) const;\n> >   \tSize adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const;\n> > -\tstd::unique_ptr<CameraSensor> sensor_;\n> > -\n> > -\tMediaEntity *entity_;\n> > -\tstd::unique_ptr<V4L2Subdevice> csi_;\n> > -\tstd::unique_ptr<V4L2Subdevice> sd_;\n> >   \tStream frStream_;\n> >   \tStream dsStream_;\n> > @@ -126,58 +183,28 @@ public:\n> >   \tstd::unique_ptr<DelayedControls> delayedCtrls_;\n> > +\tCameraType input_;\n> > +\n> >   private:\n> > -\tvoid initTPGData();\n> >   \tvoid setSensorControls(const ControlList &sensorControls);\n> > -\n> >   \tstd::string id_;\n> > -\tSize tpgResolution_;\n> >   };\n> > -int MaliC55CameraData::init()\n> > +MaliC55CameraData::Tpg *MaliC55CameraData::initTpg(MediaEntity *entity)\n> >   {\n> > -\tint ret;\n> > +\tTpg tpg;\n> > -\tsd_ = std::make_unique<V4L2Subdevice>(entity_);\n> > -\tret = sd_->open();\n> > +\ttpg.sd_ = std::make_unique<V4L2Subdevice>(entity);\n> > +\tint ret = tpg.sd_->open();\n> >   \tif (ret) {\n> > -\t\tLOG(MaliC55, Error) << \"Failed to open sensor subdevice\";\n> > -\t\treturn ret;\n> > -\t}\n> > -\n> > -\t/* If this camera is created from TPG, we return here. */\n> > -\tif (entity_->name() == \"mali-c55 tpg\") {\n> > -\t\tinitTPGData();\n> > -\t\treturn 0;\n> > -\t}\n> > -\n> > -\t/*\n> > -\t * Register a CameraSensor if we connect to a sensor and create\n> > -\t * an entity for the connected CSI-2 receiver.\n> > -\t */\n> > -\tsensor_ = CameraSensorFactoryBase::create(entity_);\n> > -\tif (!sensor_)\n> > -\t\treturn -ENODEV;\n> > -\n> > -\tconst MediaPad *sourcePad = entity_->getPadByIndex(0);\n> > -\tMediaEntity *csiEntity = sourcePad->links()[0]->sink()->entity();\n> > -\n> > -\tcsi_ = std::make_unique<V4L2Subdevice>(csiEntity);\n> > -\tret = csi_->open();\n> > -\tif (ret) {\n> > -\t\tLOG(MaliC55, Error) << \"Failed to open CSI-2 subdevice\";\n> > -\t\treturn ret;\n> > +\t\tLOG(MaliC55, Error) << \"Failed to open TPG subdevice\";\n> > +\t\treturn nullptr;\n> >   \t}\n> > -\treturn 0;\n> > -}\n> > -\n> > -void MaliC55CameraData::initTPGData()\n> > -{\n> >   \t/* Replicate the CameraSensor implementation for TPG. */\n> > -\tV4L2Subdevice::Formats formats = sd_->formats(0);\n> > +\tV4L2Subdevice::Formats formats = tpg.sd_->formats(0);\n> >   \tif (formats.empty())\n> > -\t\treturn;\n> > +\t\treturn nullptr;\n> >   \tstd::vector<Size> tpgSizes;\n> > @@ -187,19 +214,35 @@ void MaliC55CameraData::initTPGData()\n> >   \t\t\t       [](const SizeRange &range) { return range.max; });\n> >   \t}\n> > -\ttpgResolution_ = tpgSizes.back();\n> > +\ttpg.resolution_ = tpgSizes.back();\n> > +\n> > +\treturn &input_.emplace<Tpg>(std::move(tpg));\n> >   }\n> > -void MaliC55CameraData::setSensorControls(const ControlList &sensorControls)\n> > +MaliC55CameraData::Inline *MaliC55CameraData::initInline(MediaEntity *sensor)\n> >   {\n> > -\tdelayedCtrls_->push(sensorControls);\n> > +\tInline in;\n> > +\n> > +\t/* Register a CameraSensor and create an entity for the CSI-2 receiver. */\n> > +\tin.sensor_ = CameraSensorFactoryBase::create(sensor);\n> > +\tif (!in.sensor_)\n> > +\t\treturn nullptr;\n> > +\n> > +\tconst MediaPad *sourcePad = sensor->getPadByIndex(0);\n> > +\tMediaEntity *csiEntity = sourcePad->links()[0]->sink()->entity();\n> > +\n> > +\tin.csi2_ = std::make_unique<V4L2Subdevice>(csiEntity);\n> > +\tint ret = in.csi2_->open();\n> > +\tif (ret) {\n> > +\t\tLOG(MaliC55, Error) << \"Failed to open CSI-2 subdevice\";\n> > +\t\treturn nullptr;\n> > +\t}\n> > +\n> > +\treturn &input_.emplace<Inline>(std::move(in));\n> >   }\n> > -std::vector<Size> MaliC55CameraData::sizes(unsigned int mbusCode) const\n> > +std::vector<Size> MaliC55CameraData::Tpg::sizes(unsigned int mbusCode) const\n> >   {\n> > -\tif (sensor_)\n> > -\t\treturn sensor_->sizes(mbusCode);\n> > -\n> >   \tV4L2Subdevice::Formats formats = sd_->formats(0);\n> >   \tif (formats.empty())\n> >   \t\treturn {};\n> > @@ -218,12 +261,9 @@ std::vector<Size> MaliC55CameraData::sizes(unsigned int mbusCode) const\n> >   \treturn sizes;\n> >   }\n> > -Size MaliC55CameraData::resolution() const\n> > +void MaliC55CameraData::setSensorControls(const ControlList &sensorControls)\n> >   {\n> > -\tif (sensor_)\n> > -\t\treturn sensor_->resolution();\n> > -\n> > -\treturn tpgResolution_;\n> > +\tdelayedCtrls_->push(sensorControls);\n> >   }\n> >   /*\n> > @@ -242,7 +282,7 @@ int MaliC55CameraData::pixfmtToMbusCode(const PixelFormat &pixFmt) const\n> >   \tif (!bayerFormat.isValid())\n> >   \t\treturn -EINVAL;\n> > -\tV4L2Subdevice::Formats formats = sd_->formats(0);\n> > +\tV4L2Subdevice::Formats formats = subdev()->formats(0);\n> >   \tunsigned int sensorMbusCode = 0;\n> >   \tunsigned int bitDepth = 0;\n> > @@ -280,7 +320,7 @@ const PixelFormat &MaliC55CameraData::bestRawFormat() const\n> >   {\n> >   \tstatic const PixelFormat invalidPixFmt = {};\n> > -\tfor (const auto &fmt : sd_->formats(0)) {\n> > +\tfor (const auto &fmt : subdev()->formats(0)) {\n> >   \t\tBayerFormat sensorBayer = BayerFormat::fromMbusCode(fmt.first);\n> >   \t\tif (!sensorBayer.isValid())\n> > @@ -302,11 +342,11 @@ const PixelFormat &MaliC55CameraData::bestRawFormat() const\n> >   void MaliC55CameraData::updateControls(const ControlInfoMap &ipaControls)\n> >   {\n> > -\tif (!sensor_)\n> > +\tif (std::holds_alternative<Tpg>(input_))\n> >   \t\treturn;\n> >   \tIPACameraSensorInfo sensorInfo;\n> > -\tint ret = sensor_->sensorInfo(&sensorInfo);\n> > +\tint ret = sensor()->sensorInfo(&sensorInfo);\n> >   \tif (ret) {\n> >   \t\tLOG(MaliC55, Error) << \"Failed to retrieve sensor info\";\n> >   \t\treturn;\n> > @@ -379,7 +419,7 @@ int MaliC55CameraData::loadIPA()\n> >   \tint ret;\n> >   \t/* Do not initialize IPA for TPG. */\n> > -\tif (!sensor_)\n> > +\tif (std::holds_alternative<Tpg>(input_))\n> >   \t\treturn 0;\n> >   \tipa_ = IPAManager::createIPA<ipa::mali_c55::IPAProxyMaliC55>(pipe(), 1, 1);\n> > @@ -388,20 +428,20 @@ int MaliC55CameraData::loadIPA()\n> >   \tipa_->setSensorControls.connect(this, &MaliC55CameraData::setSensorControls);\n> > -\tstd::string ipaTuningFile = ipa_->configurationFile(sensor_->model() + \".yaml\",\n> > +\tstd::string ipaTuningFile = ipa_->configurationFile(sensor()->model() + \".yaml\",\n> >   \t\t\t\t\t\t\t    \"uncalibrated.yaml\");\n> >   \t/* We need to inform the IPA of the sensor configuration */\n> >   \tipa::mali_c55::IPAConfigInfo ipaConfig{};\n> > -\tret = sensor_->sensorInfo(&ipaConfig.sensorInfo);\n> > +\tret = sensor()->sensorInfo(&ipaConfig.sensorInfo);\n> >   \tif (ret)\n> >   \t\treturn ret;\n> > -\tipaConfig.sensorControls = sensor_->controls();\n> > +\tipaConfig.sensorControls = sensor()->controls();\n> >   \tControlInfoMap ipaControls;\n> > -\tret = ipa_->init({ ipaTuningFile, sensor_->model() }, ipaConfig,\n> > +\tret = ipa_->init({ ipaTuningFile, sensor()->model() }, ipaConfig,\n> >   \t\t\t &ipaControls);\n> >   \tif (ret) {\n> >   \t\tLOG(MaliC55, Error) << \"Failed to initialise the Mali-C55 IPA\";\n> > @@ -444,13 +484,13 @@ CameraConfiguration::Status MaliC55CameraConfiguration::validate()\n> >   \t * The TPG doesn't support flips, so we only need to calculate a\n> >   \t * transform if we have a sensor.\n> >   \t */\n> > -\tif (data_->sensor_) {\n> > +\tif (std::holds_alternative<MaliC55CameraData::Tpg>(data_->input_)) {\n> > +\t\tcombinedTransform_ = Transform::Rot0;\n> > +\t} else {\n> >   \t\tOrientation requestedOrientation = orientation;\n> > -\t\tcombinedTransform_ = data_->sensor_->computeTransform(&orientation);\n> > +\t\tcombinedTransform_ = data_->sensor()->computeTransform(&orientation);\n> >   \t\tif (orientation != requestedOrientation)\n> >   \t\t\tstatus = Adjusted;\n> > -\t} else {\n> > -\t\tcombinedTransform_ = Transform::Rot0;\n> >   \t}\n> >   \t/* Only 2 streams available. */\n> > @@ -927,39 +967,44 @@ int PipelineHandlerMaliC55::configure(Camera *camera,\n> >   \t/* Link the graph depending if we are operating the TPG or a sensor. */\n> >   \tMaliC55CameraData *data = cameraData(camera);\n> > -\tif (data->csi_) {\n> > -\t\tconst MediaEntity *csiEntity = data->csi_->entity();\n> > -\t\tret = csiEntity->getPadByIndex(1)->links()[0]->setEnabled(true);\n> > -\t} else {\n> > -\t\tret = data->entity_->getPadByIndex(0)->links()[0]->setEnabled(true);\n> > -\t}\n> > +\tret = std::visit(utils::overloaded{\n> > +\t\t[](MaliC55CameraData::Tpg &tpg) {\n> > +\t\t\tconst MediaEntity *tpgEntity = tpg.sd_->entity();\n> > +\t\t\treturn tpgEntity->getPadByIndex(0)->links()[0]->setEnabled(true);\n> > +\t\t},\n> > +\t\t[](MaliC55CameraData::Inline &in) {\n> > +\t\t\tconst MediaEntity *csi2Entity = in.csi2_->entity();\n> > +\t\t\treturn csi2Entity->getPadByIndex(1)->links()[0]->setEnabled(true);\n> > +\t\t},\n> > +\t}, data->input_);\n> >   \tif (ret)\n> >   \t\treturn ret;\n> >   \tMaliC55CameraConfiguration *maliConfig =\n> >   \t\tstatic_cast<MaliC55CameraConfiguration *>(config);\n> >   \tV4L2SubdeviceFormat subdevFormat = maliConfig->sensorFormat_;\n> > -\tret = data->sd_->getFormat(0, &subdevFormat);\n> > +\n> > +\t/* Apply format to the origin of the pipeline and propagate it. */\n> > +\tret = std::visit(utils::overloaded{\n> > +\t\t[&](MaliC55CameraData::Tpg &tpg) {\n> > +\t\t\treturn tpg.sd_->setFormat(0, &subdevFormat);\n> > +\t\t},\n> > +\t\t[&](MaliC55CameraData::Inline &in) {\n> > +\t\t\tint r = in.sensor_->setFormat(&subdevFormat,\n> > +\t\t\t\t\t\t      maliConfig->combinedTransform());\n> > +\t\t\tif (r)\n> > +\t\t\t\treturn r;\n> > +\n> > +\t\t\tr = in.csi2_->setFormat(0, &subdevFormat);\n> > +\t\t\tif (r)\n> > +\t\t\t\treturn r;\n> > +\n> > +\t\t\treturn in.csi2_->getFormat(1, &subdevFormat);\n> > +\t\t},\n> > +\t}, data->input_);\n> >   \tif (ret)\n> >   \t\treturn ret;\n> > -\tif (data->sensor_) {\n> > -\t\tret = data->sensor_->setFormat(&subdevFormat,\n> > -\t\t\t\t\t       maliConfig->combinedTransform());\n> > -\t\tif (ret)\n> > -\t\t\treturn ret;\n> > -\t}\n> > -\n> > -\tif (data->csi_) {\n> > -\t\tret = data->csi_->setFormat(0, &subdevFormat);\n> > -\t\tif (ret)\n> > -\t\t\treturn ret;\n> > -\n> > -\t\tret = data->csi_->getFormat(1, &subdevFormat);\n> > -\t\tif (ret)\n> > -\t\t\treturn ret;\n> > -\t}\n> > -\n> >   \tV4L2DeviceFormat statsFormat;\n> >   \tret = stats_->getFormat(&statsFormat);\n> >   \tif (ret)\n> > @@ -973,8 +1018,6 @@ int PipelineHandlerMaliC55::configure(Camera *camera,\n> >   \t/*\n> >   \t * Propagate the format to the ISP sink pad and configure the input\n> >   \t * crop rectangle (no crop at the moment).\n> > -\t *\n> > -\t * \\todo Configure the CSI-2 receiver.\n> >   \t */\n> >   \tret = isp_->setFormat(0, &subdevFormat);\n> >   \tif (ret)\n> > @@ -1058,18 +1101,18 @@ int PipelineHandlerMaliC55::configure(Camera *camera,\n> >   \t/* We need to inform the IPA of the sensor configuration */\n> >   \tipa::mali_c55::IPAConfigInfo ipaConfig{};\n> > -\tret = data->sensor_->sensorInfo(&ipaConfig.sensorInfo);\n> > +\tret = data->sensor()->sensorInfo(&ipaConfig.sensorInfo);\n> >   \tif (ret)\n> >   \t\treturn ret;\n> > -\tipaConfig.sensorControls = data->sensor_->controls();\n> > +\tipaConfig.sensorControls = data->sensor()->controls();\n> >   \t/*\n> >   \t * And we also need to tell the IPA the bayerOrder of the data (as\n> >   \t * affected by any flips that we've configured)\n> >   \t */\n> >   \tconst Transform &combinedTransform = maliConfig->combinedTransform();\n> > -\tBayerFormat::Order bayerOrder = data->sensor_->bayerOrder(combinedTransform);\n> > +\tBayerFormat::Order bayerOrder = data->sensor()->bayerOrder(combinedTransform);\n> >   \tControlInfoMap ipaControls;\n> >   \tret = data->ipa_->configure(ipaConfig, utils::to_underlying(bayerOrder),\n> > @@ -1283,7 +1326,7 @@ void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera,\n> >   \tif (!scalerCrop)\n> >   \t\treturn;\n> > -\tif (!data->sensor_) {\n> > +\tif (std::holds_alternative<MaliC55CameraData::Tpg>(data->input_)) {\n> >   \t\tLOG(MaliC55, Error) << \"ScalerCrop not supported for TPG\";\n> >   \t\treturn;\n> >   \t}\n> > @@ -1291,7 +1334,7 @@ void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera,\n> >   \tRectangle nativeCrop = *scalerCrop;\n> >   \tIPACameraSensorInfo sensorInfo;\n> > -\tint ret = data->sensor_->sensorInfo(&sensorInfo);\n> > +\tint ret = data->sensor()->sensorInfo(&sensorInfo);\n> >   \tif (ret) {\n> >   \t\tLOG(MaliC55, Error) << \"Failed to retrieve sensor info\";\n> >   \t\treturn;\n> > @@ -1573,9 +1616,9 @@ bool PipelineHandlerMaliC55::registerTPGCamera(MediaLink *link)\n> >   \t}\n> >   \tstd::unique_ptr<MaliC55CameraData> data =\n> > -\t\tstd::make_unique<MaliC55CameraData>(this, link->source()->entity());\n> > +\t\tstd::make_unique<MaliC55CameraData>(this);\n> > -\tif (data->init())\n> > +\tif (!data->initTpg(link->source()->entity()))\n> >   \t\treturn false;\n> >   \treturn registerMaliCamera(std::move(data), name);\n> > @@ -1600,21 +1643,24 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink)\n> >   \t\t\tcontinue;\n> >   \t\tstd::unique_ptr<MaliC55CameraData> data =\n> > -\t\t\tstd::make_unique<MaliC55CameraData>(this, sensor);\n> > -\t\tif (data->init())\n> > +\t\t\tstd::make_unique<MaliC55CameraData>(this);\n> > +\n> > +\t\tauto *in = data->initInline(sensor);\n> > +\t\tif (!in)\n> >   \t\t\treturn false;\n> > -\t\tdata->properties_ = data->sensor_->properties();\n> > +\t\tdata->properties_ = in->sensor_->properties();\n> > -\t\tconst CameraSensorProperties::SensorDelays &delays = data->sensor_->sensorDelays();\n> > +\t\tconst CameraSensorProperties::SensorDelays &delays =\n> > +\t\t\tin->sensor_->sensorDelays();\n> >   \t\tstd::unordered_map<uint32_t, DelayedControls::ControlParams> params = {\n> >   \t\t\t{ V4L2_CID_ANALOGUE_GAIN, { delays.gainDelay, false } },\n> >   \t\t\t{ V4L2_CID_EXPOSURE, { delays.exposureDelay, false } },\n> >   \t\t};\n> > -\t\tdata->delayedCtrls_ =\n> > -\t\t\tstd::make_unique<DelayedControls>(data->sensor_->device(),\n> > -\t\t\t\t\t\t\t  params);\n> > +\t\tV4L2Subdevice *sensorSubdev = in->sensor_->device();\n> > +\t\tdata->delayedCtrls_ = std::make_unique<DelayedControls>(sensorSubdev,\n> > +\t\t\t\t\t\t\t\t\tparams);\n> >   \t\tisp_->frameStart.connect(data->delayedCtrls_.get(),\n> >   \t\t\t\t\t &DelayedControls::applyControls);\n> >\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 8B341BDCB5\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 23 Apr 2026 18:02:23 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4E71562F55;\n\tThu, 23 Apr 2026 20:02:22 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id AA96A62010\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 23 Apr 2026 20:02:20 +0200 (CEST)","from ideasonboard.com (net-93-65-100-155.cust.vodafonedsl.it\n\t[93.65.100.155])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EA687802;\n\tThu, 23 Apr 2026 20:00:40 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"MO/SC0wX\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1776967241;\n\tbh=C6poJdyecQrLQ69dCpvkJTxfyQgqcakydD8l7HXyYs4=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=MO/SC0wXvQVZz/RSjSTX271hb1m/gvVkwiM10REftX3X97460PJKMh6S+TbFi4KIg\n\tZIM/YJoqrQHNWbnClo7uRSeNslzc/9uGRwANxlj2wlELN8uTQ+7/nFIEtvwMxx9J8Q\n\todJMMIJJc50XSGZ2uW5lx2MeNneWAFbykBGU4JH4=","Date":"Thu, 23 Apr 2026 20:02:16 +0200","From":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","To":"Dan Scally <dan.scally@ideasonboard.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tlibcamera-devel@lists.libcamera.org, =?utf-8?b?QmFybmFiw6FzIFDFkWN6?=\n\t=?utf-8?q?e?= <barnabas.pocze@ideasonboard.com>","Subject":"Re: [PATCH v8 3/8] libcamera: mali-c55: Split TPG and Inline camera\n\thandling","Message-ID":"<aepehzQC1IlaKrkv@zed>","References":"<20260401-mali-cru-v8-0-44c48f990e28@ideasonboard.com>\n\t<20260401-mali-cru-v8-3-44c48f990e28@ideasonboard.com>\n\t<f25ba659-9297-4065-93cf-860b1c26ed2e@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<f25ba659-9297-4065-93cf-860b1c26ed2e@ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]