diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 64944f601ee5..d6a0e272d703 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -128,18 +128,29 @@ dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll, struct netlink_ext_ack *extack) { const struct dpll_device_ops *ops = dpll_device_ops(dpll); + DECLARE_BITMAP(modes, DPLL_MODE_MAX + 1) = { 0 }; enum dpll_mode mode; int ret; - /* No mode change is supported now, so the only supported mode is the - * one obtained by mode_get(). - */ + if (ops->supported_modes_get) { + ret = ops->supported_modes_get(dpll, dpll_priv(dpll), modes, + extack); + if (ret) + return ret; + } else { + /* If the supported modes are not reported by the driver, the + * only supported mode is the one obtained by mode_get(). + */ + ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack); + if (ret) + return ret; - ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack); - if (ret) - return ret; - if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode)) - return -EMSGSIZE; + __set_bit(mode, modes); + } + + for_each_set_bit(mode, modes, DPLL_MODE_MAX + 1) + if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode)) + return -EMSGSIZE; return 0; } diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 562f520b23c2..912a2ca3e0ee 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -20,6 +20,9 @@ struct dpll_pin_esync; struct dpll_device_ops { int (*mode_get)(const struct dpll_device *dpll, void *dpll_priv, enum dpll_mode *mode, struct netlink_ext_ack *extack); + int (*supported_modes_get)(const struct dpll_device *dpll, + void *dpll_priv, unsigned long *modes, + struct netlink_ext_ack *extack); int (*lock_status_get)(const struct dpll_device *dpll, void *dpll_priv, enum dpll_lock_status *status, enum dpll_lock_status_error *status_error,