Add ability to set DPLL device operating mode (automatic/manual) through "dpll device set id ID mode MODE" command. In automatic mode, the DPLL autonomously selects the best input source based on priority and quality. In manual mode, the input source must be explicitly configured. The implementation adds dpll_mode_map for string-to-enum conversion, str_to_dpll_mode() and dpll_parse_mode() functions, and refactors dpll_mode_name() to use str_map_lookup_uint() for consistency. Man page and bash completion updated accordingly. Signed-off-by: Petr Oros --- bash-completion/dpll | 6 ++++- dpll/dpll.c | 52 +++++++++++++++++++++++++++++++++++--------- man/man8/dpll.8 | 18 ++++++++++++++- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/bash-completion/dpll b/bash-completion/dpll index 6e4d39a5b5b6bb..caf86a36f2adf3 100644 --- a/bash-completion/dpll +++ b/bash-completion/dpll @@ -73,6 +73,10 @@ _dpll_device() "$(_dpll_direct_complete device_id)" -- "$cur" ) ) return 0 ;; + mode) + COMPREPLY=( $( compgen -W "automatic manual" -- "$cur" ) ) + return 0 + ;; phase-offset-monitor) COMPREPLY=( $( compgen -W "enable disable true false 0 1" -- "$cur" ) ) return 0 @@ -82,7 +86,7 @@ _dpll_device() return 0 ;; *) - COMPREPLY=( $( compgen -W "id phase-offset-monitor \ + COMPREPLY=( $( compgen -W "id mode phase-offset-monitor \ phase-offset-avg-factor" -- "$cur" ) ) return 0 ;; diff --git a/dpll/dpll.c b/dpll/dpll.c index 846ad4b04c63d2..9dc3f8db373d28 100644 --- a/dpll/dpll.c +++ b/dpll/dpll.c @@ -42,6 +42,14 @@ static const char *str_enable_disable(bool v) return v ? "enable" : "disable"; } +static struct str_num_map dpll_mode_map[] = { + { .str = "automatic", .num = DPLL_MODE_AUTOMATIC }, + { .str = "manual", .num = DPLL_MODE_MANUAL }, + { + .str = NULL, + }, +}; + static struct str_num_map pin_state_map[] = { { .str = "connected", .num = DPLL_PIN_STATE_CONNECTED }, { .str = "disconnected", .num = DPLL_PIN_STATE_DISCONNECTED }, @@ -132,6 +140,17 @@ static bool dpll_no_arg(struct dpll *dpll) return dpll_argc(dpll) == 0; } +static int str_to_dpll_mode(const char *mode_str, __u32 *mode) +{ + int num; + + num = str_map_lookup_str(dpll_mode_map, mode_str); + if (num < 0) + return num; + *mode = num; + return 0; +} + static int str_to_dpll_pin_state(const char *state_str, __u32 *state) { int num; @@ -154,6 +173,18 @@ static int str_to_dpll_pin_type(const char *type_str, __u32 *type) return 0; } +static int dpll_parse_mode(struct dpll *dpll, __u32 *mode) +{ + const char *str = dpll_argv(dpll); + + if (str_to_dpll_mode(str, mode)) { + pr_err("invalid state: %s (use automatic/manual)\n", str); + return -EINVAL; + } + dpll_arg_inc(dpll); + return 0; +} + static int dpll_parse_state(struct dpll *dpll, __u32 *state) { const char *str = dpll_argv(dpll); @@ -585,21 +616,18 @@ dpll_free: static void cmd_device_help(void) { pr_err("Usage: dpll device show [ id DEVICE_ID ]\n"); - pr_err(" dpll device set id DEVICE_ID [ phase-offset-monitor { enable | disable } ]\n"); - pr_err(" [ phase-offset-avg-factor NUM ]\n"); + pr_err(" dpll device set id DEVICE_ID [ mode { automatic | manual } ]\n"); + pr_err(" [ phase-offset-monitor { enable | disable } ]\n"); + pr_err(" [ phase-offset-avg-factor NUM ]\n"); pr_err(" dpll device id-get [ module-name NAME ] [ clock-id ID ] [ type TYPE ]\n"); } static const char *dpll_mode_name(__u32 mode) { - switch (mode) { - case DPLL_MODE_MANUAL: - return "manual"; - case DPLL_MODE_AUTOMATIC: - return "automatic"; - default: - return "unknown"; - } + const char *str; + + str = str_map_lookup_uint(dpll_mode_map, mode); + return str ? str : "unknown"; } static const char *dpll_lock_status_name(__u32 status) @@ -839,6 +867,10 @@ static int cmd_device_set(struct dpll *dpll) return -EINVAL; mnl_attr_put_u32(nlh, DPLL_A_ID, id); has_id = true; + } else if (dpll_argv_match_inc(dpll, "mode")) { + if (dpll_parse_attr_enum(dpll, nlh, "mode", DPLL_A_MODE, + dpll_parse_mode)) + return -EINVAL; } else if (dpll_argv_match(dpll, "phase-offset-monitor")) { const char *str = dpll_argv_next(dpll); bool val; diff --git a/man/man8/dpll.8 b/man/man8/dpll.8 index fcc1c4a67af5d9..e82f083feac64b 100644 --- a/man/man8/dpll.8 +++ b/man/man8/dpll.8 @@ -88,7 +88,7 @@ Temperature (if supported) Type (PPS or EEC) .RE -.SS dpll device set id ID [ phase-offset-monitor { enable | disable } ] [ phase-offset-avg-factor FACTOR ] +.SS dpll device set id ID [ mode { automatic | manual } ] [ phase-offset-monitor { enable | disable } ] [ phase-offset-avg-factor FACTOR ] Configure DPLL device parameters. @@ -96,6 +96,17 @@ Configure DPLL device parameters. .BI id " ID" Specifies which device to configure (required). +.TP +.BI mode " { automatic | manual }" +Set the operating mode of the DPLL device. +In +.B automatic +mode, the DPLL autonomously selects the best available input source +based on priority and quality. In +.B manual +mode, the input source must be explicitly configured and the DPLL +will not automatically switch sources. + .TP .BI phase-offset-monitor " { enable | disable | true | false | 0 | 1 }" Enable or disable phase offset monitoring between the device and its pins. @@ -283,6 +294,11 @@ Press Ctrl+C to stop monitoring. .B dpll -j device show id 0 .fi +.SS Set device 0 to manual mode +.nf +.B dpll device set id 0 mode manual +.fi + .SS Enable phase offset monitoring on device 0 .nf .B dpll device set id 0 phase-offset-monitor enable -- 2.52.0