dpll: Allow associating dpll pin with a firmware node

Extend the DPLL core to support associating a DPLL pin with a firmware
node. This association is required to allow other subsystems (such as
network drivers) to locate and request specific DPLL pins defined in
the Device Tree or ACPI.

* Add a .fwnode field to the struct dpll_pin
* Introduce dpll_pin_fwnode_set() helper to allow the provider driver
  to associate a pin with a fwnode after the pin has been allocated
* Introduce fwnode_dpll_pin_find() helper to allow consumers to search
  for a registered DPLL pin using its associated fwnode handle
* Ensure the fwnode reference is properly released in dpll_pin_put()

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Link: https://patch.msgid.link/20260203174002.705176-2-ivecera@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Ivan Vecera 2026-02-03 18:39:54 +01:00 committed by Paolo Abeni
parent 0e6c95c988
commit d0f4771e2b
3 changed files with 62 additions and 0 deletions

View file

@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/string.h>
@ -595,12 +596,60 @@ void dpll_pin_put(struct dpll_pin *pin)
xa_destroy(&pin->parent_refs);
xa_destroy(&pin->ref_sync_pins);
dpll_pin_prop_free(&pin->prop);
fwnode_handle_put(pin->fwnode);
kfree_rcu(pin, rcu);
}
mutex_unlock(&dpll_lock);
}
EXPORT_SYMBOL_GPL(dpll_pin_put);
/**
* dpll_pin_fwnode_set - set dpll pin firmware node reference
* @pin: pointer to a dpll pin
* @fwnode: firmware node handle
*
* Set firmware node handle for the given dpll pin.
*/
void dpll_pin_fwnode_set(struct dpll_pin *pin, struct fwnode_handle *fwnode)
{
mutex_lock(&dpll_lock);
fwnode_handle_put(pin->fwnode); /* Drop fwnode previously set */
pin->fwnode = fwnode_handle_get(fwnode);
mutex_unlock(&dpll_lock);
}
EXPORT_SYMBOL_GPL(dpll_pin_fwnode_set);
/**
* fwnode_dpll_pin_find - find dpll pin by firmware node reference
* @fwnode: reference to firmware node
*
* Get existing object of a pin that is associated with given firmware node
* reference.
*
* Context: Acquires a lock (dpll_lock)
* Return:
* * valid dpll_pin pointer on success
* * NULL when no such pin exists
*/
struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode)
{
struct dpll_pin *pin, *ret = NULL;
unsigned long index;
mutex_lock(&dpll_lock);
xa_for_each(&dpll_pin_xa, index, pin) {
if (pin->fwnode == fwnode) {
ret = pin;
refcount_inc(&ret->refcount);
break;
}
}
mutex_unlock(&dpll_lock);
return ret;
}
EXPORT_SYMBOL_GPL(fwnode_dpll_pin_find);
static int
__dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
const struct dpll_pin_ops *ops, void *priv, void *cookie)

View file

@ -42,6 +42,7 @@ struct dpll_device {
* @pin_idx: index of a pin given by dev driver
* @clock_id: clock_id of creator
* @module: module of creator
* @fwnode: optional reference to firmware node
* @dpll_refs: hold referencees to dplls pin was registered with
* @parent_refs: hold references to parent pins pin was registered with
* @ref_sync_pins: hold references to pins for Reference SYNC feature
@ -54,6 +55,7 @@ struct dpll_pin {
u32 pin_idx;
u64 clock_id;
struct module *module;
struct fwnode_handle *fwnode;
struct xarray dpll_refs;
struct xarray parent_refs;
struct xarray ref_sync_pins;

View file

@ -16,6 +16,7 @@
struct dpll_device;
struct dpll_pin;
struct dpll_pin_esync;
struct fwnode_handle;
struct dpll_device_ops {
int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv,
@ -178,6 +179,8 @@ void dpll_netdev_pin_clear(struct net_device *dev);
size_t dpll_netdev_pin_handle_size(const struct net_device *dev);
int dpll_netdev_add_pin_handle(struct sk_buff *msg,
const struct net_device *dev);
struct dpll_pin *fwnode_dpll_pin_find(struct fwnode_handle *fwnode);
#else
static inline void
dpll_netdev_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin) { }
@ -193,6 +196,12 @@ dpll_netdev_add_pin_handle(struct sk_buff *msg, const struct net_device *dev)
{
return 0;
}
static inline struct dpll_pin *
fwnode_dpll_pin_find(struct fwnode_handle *fwnode)
{
return NULL;
}
#endif
struct dpll_device *
@ -218,6 +227,8 @@ void dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
void dpll_pin_put(struct dpll_pin *pin);
void dpll_pin_fwnode_set(struct dpll_pin *pin, struct fwnode_handle *fwnode);
int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
const struct dpll_pin_ops *ops, void *priv);