Skip to content

Commit 4cea477

Browse files
Sakari Ailusrkhuangtao
authored andcommitted
FROMLIST: v4l: fwnode: Add a helper function to obtain device / integer references
v4l2_fwnode_reference_parse_int_prop() will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> (cherry picked from commit 804b867e30fe9855d9d7810a363a2b8388c2a9aa) https://git.linuxtv.org/sailus/media_tree.git/log/?h=010f7f4393fd http://www.spinics.net/lists/linux-media/msg122688.html Signed-off-by: Marc Herbert <marc.herbert@intel.com> BUG=b:64133998 TEST=media device topology shows subdevs registered successfully TEST=no camera regression Change-Id: I18727c371e64be7e0a3cfa5da4e23274187c0b5a Reviewed-on: https://chromium-review.googlesource.com/693698 Commit-Ready: Tomasz Figa <tfiga@chromium.org> Tested-by: Hyungwoo Yang <hyungwoo.yang@intel.com> Reviewed-by: Tomasz Figa <tfiga@chromium.org> Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
1 parent d2209eb commit 4cea477

1 file changed

Lines changed: 201 additions & 0 deletions

File tree

drivers/media/v4l2-core/v4l2-fwnode.c

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
532733
MODULE_LICENSE("GPL");
533734
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
534735
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");

0 commit comments

Comments
 (0)