media: v4l: async: Support fwnode endpoint list matching for subdevs
Support matching V4L2 async sub-devices based on particular fwnode endpoint. This makes it possible to instantiate multiple V4L2 sub-devices based on given fwnode endpoints from a single device, based on driver needs. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Tested-by: Philipp Zabel <p.zabel@pengutronix.de> # imx6qp Tested-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> # rcar + adv746x Tested-by: Aishwarya Kothari <aishwarya.kothari@toradex.com> # Apalis i.MX6Q with TC358743 Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> # Renesas RZ/G2L SMARC Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
765f60568f
commit
e74f7a9678
@ -134,6 +134,30 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
|
||||
"v4l2-async: matching for notifier %pfw, sd fwnode %pfw\n",
|
||||
dev_fwnode(notifier_dev(notifier)), sd->fwnode);
|
||||
|
||||
if (!list_empty(&sd->async_subdev_endpoint_list)) {
|
||||
struct v4l2_async_subdev_endpoint *ase;
|
||||
|
||||
dev_dbg(sd->dev,
|
||||
"v4l2-async: endpoint fwnode list available, looking for %pfw\n",
|
||||
match->fwnode);
|
||||
|
||||
list_for_each_entry(ase, &sd->async_subdev_endpoint_list,
|
||||
async_subdev_endpoint_entry) {
|
||||
bool matched = ase->endpoint == match->fwnode;
|
||||
|
||||
dev_dbg(sd->dev,
|
||||
"v4l2-async: endpoint-endpoint match %sfound with %pfw\n",
|
||||
matched ? "" : "not ", ase->endpoint);
|
||||
|
||||
if (matched)
|
||||
return true;
|
||||
}
|
||||
|
||||
dev_dbg(sd->dev, "async: no endpoint matched\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (match_fwnode_one(notifier, sd, sd->fwnode, match))
|
||||
return true;
|
||||
|
||||
@ -745,6 +769,23 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier, int adapter_id,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__v4l2_async_nf_add_i2c);
|
||||
|
||||
int v4l2_async_subdev_endpoint_add(struct v4l2_subdev *sd,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct v4l2_async_subdev_endpoint *ase;
|
||||
|
||||
ase = kmalloc(sizeof(*ase), GFP_KERNEL);
|
||||
if (!ase)
|
||||
return -ENOMEM;
|
||||
|
||||
ase->endpoint = fwnode;
|
||||
list_add(&ase->async_subdev_endpoint_entry,
|
||||
&sd->async_subdev_endpoint_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_async_subdev_endpoint_add);
|
||||
|
||||
struct v4l2_async_connection *
|
||||
v4l2_async_connection_unique(struct v4l2_subdev *sd)
|
||||
{
|
||||
|
@ -1467,8 +1467,20 @@ EXPORT_SYMBOL_GPL(__v4l2_subdev_init_finalize);
|
||||
|
||||
void v4l2_subdev_cleanup(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct v4l2_async_subdev_endpoint *ase, *ase_tmp;
|
||||
|
||||
__v4l2_subdev_state_free(sd->active_state);
|
||||
sd->active_state = NULL;
|
||||
|
||||
if (list_empty(&sd->async_subdev_endpoint_list))
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(ase, ase_tmp, &sd->async_subdev_endpoint_list,
|
||||
async_subdev_endpoint_entry) {
|
||||
list_del(&ase->async_subdev_endpoint_entry);
|
||||
|
||||
kfree(ase);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup);
|
||||
|
||||
@ -2182,6 +2194,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
|
||||
sd->dev_priv = NULL;
|
||||
sd->host_priv = NULL;
|
||||
sd->privacy_led = NULL;
|
||||
INIT_LIST_HEAD(&sd->async_subdev_endpoint_list);
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
sd->entity.name = sd->name;
|
||||
sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
|
||||
|
@ -125,6 +125,18 @@ struct v4l2_async_notifier {
|
||||
struct list_head notifier_entry;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct v4l2_async_subdev_endpoint - Entry in sub-device's fwnode list
|
||||
*
|
||||
* @async_subdev_endpoint_entry: An entry in async_subdev_endpoint_list of
|
||||
* &struct v4l2_subdev
|
||||
* @endpoint: Endpoint fwnode agains which to match the sub-device
|
||||
*/
|
||||
struct v4l2_async_subdev_endpoint {
|
||||
struct list_head async_subdev_endpoint_entry;
|
||||
struct fwnode_handle *endpoint;
|
||||
};
|
||||
|
||||
/**
|
||||
* v4l2_async_debug_init - Initialize debugging tools.
|
||||
*
|
||||
@ -215,6 +227,24 @@ __v4l2_async_nf_add_i2c(struct v4l2_async_notifier *notifier,
|
||||
((type *)__v4l2_async_nf_add_i2c(notifier, adapter, address, \
|
||||
sizeof(type)))
|
||||
|
||||
/**
|
||||
* v4l2_async_subdev_endpoint_add - Add an endpoint fwnode to async sub-device
|
||||
* matching list
|
||||
*
|
||||
* @sd: the sub-device
|
||||
* @fwnode: the endpoint fwnode to match
|
||||
*
|
||||
* Add a fwnode to the async sub-device's matching list. This allows registering
|
||||
* multiple async sub-devices from a single device.
|
||||
*
|
||||
* Note that calling v4l2_subdev_cleanup() as part of the sub-device's cleanup
|
||||
* if endpoints have been added to the sub-device's fwnode matching list.
|
||||
*
|
||||
* Returns an error on failure, 0 on success.
|
||||
*/
|
||||
int v4l2_async_subdev_endpoint_add(struct v4l2_subdev *sd,
|
||||
struct fwnode_handle *fwnode);
|
||||
|
||||
/**
|
||||
* v4l2_async_connection_unique - return a unique &struct v4l2_async_connection
|
||||
* for a sub-device
|
||||
|
@ -1022,6 +1022,8 @@ struct v4l2_subdev_platform_data {
|
||||
* either dev->of_node->fwnode or dev->fwnode (whichever is non-NULL).
|
||||
* @async_list: Links this subdev to a global subdev_list or
|
||||
* @notifier->done_list list.
|
||||
* @async_subdev_endpoint_list: List entry in async_subdev_endpoint_entry of
|
||||
* &struct v4l2_async_subdev_endpoint.
|
||||
* @subdev_notifier: A sub-device notifier implicitly registered for the sub-
|
||||
* device using v4l2_async_register_subdev_sensor().
|
||||
* @asc_list: Async connection list, of &struct
|
||||
@ -1065,6 +1067,7 @@ struct v4l2_subdev {
|
||||
struct device *dev;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct list_head async_list;
|
||||
struct list_head async_subdev_endpoint_list;
|
||||
struct v4l2_async_notifier *subdev_notifier;
|
||||
struct list_head asc_list;
|
||||
struct v4l2_subdev_platform_data *pdata;
|
||||
@ -1382,8 +1385,9 @@ int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
|
||||
* v4l2_subdev_cleanup() - Releases the resources allocated by the subdevice
|
||||
* @sd: The subdevice
|
||||
*
|
||||
* This function will release the resources allocated in
|
||||
* v4l2_subdev_init_finalize.
|
||||
* Clean up a V4L2 async sub-device. Must be called for a sub-device as part of
|
||||
* its release if resources have been associated with it using
|
||||
* v4l2_async_subdev_endpoint_add() or v4l2_subdev_init_finalize().
|
||||
*/
|
||||
void v4l2_subdev_cleanup(struct v4l2_subdev *sd);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user