@@ -529,6 +529,207 @@ static int v4l2_fwnode_reference_parse(
529529 return ret ;
530530}
531531
532+ /*
533+ * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
534+ * arguments
535+ * @dev: struct device pointer
536+ * @notifier: notifier for @dev
537+ * @prop: the name of the property
538+ * @index: the index of the reference to get
539+ * @props: the array of integer property names
540+ * @nprops: the number of integer property names in @nprops
541+ *
542+ * Find fwnodes referred to by a property @prop, then under that
543+ * iteratively, @nprops times, follow each child node which has a
544+ * property in @props array at a given child index the value of which
545+ * matches the integer argument at an index.
546+ *
547+ * For example, if this function was called with arguments and values
548+ * @dev corresponding to device "SEN", @prop == "flash-leds", @index
549+ * == 1, @props == { "led" }, @nprops == 1, with the ASL snippet below
550+ * it would return the node marked with THISONE. The @dev argument in
551+ * the ASL below.
552+ *
553+ * Device (LED)
554+ * {
555+ * Name (_DSD, Package () {
556+ * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
557+ * Package () {
558+ * Package () { "led0", "LED0" },
559+ * Package () { "led1", "LED1" },
560+ * }
561+ * })
562+ * Name (LED0, Package () {
563+ * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
564+ * Package () {
565+ * Package () { "led", 0 },
566+ * }
567+ * })
568+ * Name (LED1, Package () {
569+ * // THISONE
570+ * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
571+ * Package () {
572+ * Package () { "led", 1 },
573+ * }
574+ * })
575+ * }
576+ *
577+ * Device (SEN)
578+ * {
579+ * Name (_DSD, Package () {
580+ * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
581+ * Package () {
582+ * Package () {
583+ * "flash-leds",
584+ * Package () { ^LED, 0, ^LED, 1 },
585+ * }
586+ * }
587+ * })
588+ * }
589+ *
590+ * where
591+ *
592+ * LED LED driver device
593+ * LED0 First LED
594+ * LED1 Second LED
595+ * SEN Camera sensor device (or another device the LED is
596+ * related to)
597+ *
598+ * Return: 0 on success
599+ * -ENOENT if no entries (or the property itself) were found
600+ * -EINVAL if property parsing otherwise failed
601+ * -ENOMEM if memory allocation failed
602+ */
603+ static struct fwnode_handle * v4l2_fwnode_reference_get_int_prop (
604+ struct fwnode_handle * fwnode , const char * prop , unsigned int index ,
605+ const char * * props , unsigned int nprops )
606+ {
607+ struct fwnode_reference_args fwnode_args ;
608+ unsigned int * args = fwnode_args .args ;
609+ struct fwnode_handle * child ;
610+ int ret ;
611+
612+ /*
613+ * Obtain remote fwnode as well as the integer arguments.
614+ *
615+ * Note that right now both -ENODATA and -ENOENT may signal
616+ * out-of-bounds access. Return -ENOENT in that case.
617+ */
618+ ret = fwnode_property_get_reference_args (fwnode , prop , NULL , nprops ,
619+ index , & fwnode_args );
620+ if (ret )
621+ return ERR_PTR (ret == - ENODATA ? - ENOENT : ret );
622+
623+ /*
624+ * Find a node in the tree under the referred fwnode corresponding the
625+ * integer arguments.
626+ */
627+ fwnode = fwnode_args .fwnode ;
628+ while (nprops -- ) {
629+ u32 val ;
630+
631+ /* Loop over all child nodes under fwnode. */
632+ fwnode_for_each_child_node (fwnode , child ) {
633+ if (fwnode_property_read_u32 (child , * props , & val ))
634+ continue ;
635+
636+ /* Found property, see if its value matches. */
637+ if (val == * args )
638+ break ;
639+ }
640+
641+ fwnode_handle_put (fwnode );
642+
643+ /* No property found; return an error here. */
644+ if (!child ) {
645+ fwnode = ERR_PTR (- ENOENT );
646+ break ;
647+ }
648+
649+ props ++ ;
650+ args ++ ;
651+ fwnode = child ;
652+ }
653+
654+ return fwnode ;
655+ }
656+
657+ /*
658+ * v4l2_fwnode_reference_parse_int_props - parse references for async sub-devices
659+ * @dev: struct device pointer
660+ * @notifier: notifier for @dev
661+ * @prop: the name of the property
662+ * @props: the array of integer property names
663+ * @nprops: the number of integer properties
664+ *
665+ * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
666+ * property @prop with integer arguments with child nodes matching in properties
667+ * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
668+ * accordingly.
669+ *
670+ * While it is technically possible to use this function on DT, it is only
671+ * meaningful on ACPI. On Device tree you can refer to any node in the tree but
672+ * on ACPI the references are limited to devices.
673+ *
674+ * Return: 0 on success
675+ * -ENOENT if no entries (or the property itself) were found
676+ * -EINVAL if property parsing otherwisefailed
677+ * -ENOMEM if memory allocation failed
678+ */
679+ static int v4l2_fwnode_reference_parse_int_props (
680+ struct device * dev , struct v4l2_async_notifier * notifier ,
681+ const char * prop , const char * * props , unsigned int nprops )
682+ {
683+ struct fwnode_handle * fwnode ;
684+ unsigned int index ;
685+ int ret ;
686+
687+ for (index = 0 ; !IS_ERR ((fwnode = v4l2_fwnode_reference_get_int_prop (
688+ dev_fwnode (dev ), prop , index , props ,
689+ nprops ))); index ++ )
690+ fwnode_handle_put (fwnode );
691+
692+ /*
693+ * Note that right now both -ENODATA and -ENOENT may signal
694+ * out-of-bounds access. Return the error in cases other than that.
695+ */
696+ if (PTR_ERR (fwnode ) != - ENOENT && PTR_ERR (fwnode ) != - ENODATA )
697+ return PTR_ERR (fwnode );
698+
699+ ret = v4l2_async_notifier_realloc (notifier ,
700+ notifier -> num_subdevs + index );
701+ if (ret )
702+ return - ENOMEM ;
703+
704+ for (index = 0 ; !IS_ERR ((fwnode = v4l2_fwnode_reference_get_int_prop (
705+ dev_fwnode (dev ), prop , index , props ,
706+ nprops ))); index ++ ) {
707+ struct v4l2_async_subdev * asd ;
708+
709+ if (WARN_ON (notifier -> num_subdevs >= notifier -> max_subdevs )) {
710+ ret = - EINVAL ;
711+ goto error ;
712+ }
713+
714+ asd = kzalloc (sizeof (struct v4l2_async_subdev ), GFP_KERNEL );
715+ if (!asd ) {
716+ ret = - ENOMEM ;
717+ goto error ;
718+ }
719+
720+ notifier -> subdevs [notifier -> num_subdevs ] = asd ;
721+ asd -> match .fwnode .fwnode = fwnode ;
722+ asd -> match_type = V4L2_ASYNC_MATCH_FWNODE ;
723+ notifier -> num_subdevs ++ ;
724+ }
725+
726+ return PTR_ERR (fwnode ) == - ENOENT ? 0 : PTR_ERR (fwnode );
727+
728+ error :
729+ fwnode_handle_put (fwnode );
730+ return ret ;
731+ }
732+
532733MODULE_LICENSE ("GPL" );
533734MODULE_AUTHOR ("Sakari Ailus <sakari.ailus@linux.intel.com>" );
534735MODULE_AUTHOR ("Sylwester Nawrocki <s.nawrocki@samsung.com>" );
0 commit comments