/* * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com * * SPDX-License-Identifier: BSD-3-Clause */ /* * TI Clock Divider API Header * * This header defines the data structures and interfaces for programmable * clock dividers. It provides divider data structures, driver interfaces, * and APIs for divider value get/set operations supporting both power-of-2 * and arbitrary integer division ratios. */ #ifndef TI_CLK_DIV_H #define TI_CLK_DIV_H #include /* * Base divider clock data structure * * This structure contains the fundamental divider configuration including * the maximum divider value and default divider ratio. */ struct ti_clk_data_div { /* Base driver data structure */ struct ti_clk_drv_data data; /* Maximum divider value (divider range is 1 to max_div) */ uint16_t max_div; /* Default divider value at initialization */ uint16_t default_div; }; /* * Register-based divider clock data structure * * This structure defines a divider implemented via a hardware register field. * The divider value is stored in a bit field within the specified register. */ struct ti_clk_data_div_reg { /* Register address containing divider field */ uint32_t reg; /* Base divider data */ struct ti_clk_data_div data_div; /* Starting bit position of divider field */ uint8_t bit; /* If true, divider values start at 1 (not 0) */ uint8_t start_at_1; }; /* * Register-based divider with GO bit for change propagation * * This structure extends the basic register divider with a GO bit mechanism. * After modifying the divider value, the GO bit must be set to propagate * the change through the clock tree. */ struct ti_clk_data_div_reg_go { /* Register address containing divider field */ uint32_t reg; /* Base divider data */ struct ti_clk_data_div data_div; /* Starting bit position of divider field */ uint8_t bit; /* If true, divider values start at 1 (not 0) */ uint8_t start_at_1; /* GO bit number to trigger divider change */ uint8_t go; }; /* * Divider clock driver operations structure * * This structure extends the base clock driver with divider-specific operations * for getting, setting, and validating divider values. */ struct ti_clk_drv_div { /* Base clock driver operations */ struct ti_clk_drv drv; /* * Set the divider value for a clock */ bool (*set_div)(struct ti_clk *clkp, uint32_t div); /* * Get the current divider value for a clock */ uint32_t (*get_div)(struct ti_clk *clkp); /* * Validate if a divider value is supported */ bool (*valid_div)(struct ti_clk *clkp, uint32_t div); }; /* Divider driver for read-write register-based dividers */ extern const struct ti_clk_drv_div ti_clk_drv_div_reg; /* Divider driver for read-only register-based dividers */ extern const struct ti_clk_drv_div ti_clk_drv_div_reg_ro; /* Divider driver for register-based dividers with GO bit propagation */ extern const struct ti_clk_drv_div ti_clk_drv_div_reg_go; /* Divider driver for fixed (non-programmable) dividers */ extern const struct ti_clk_drv_div ti_clk_drv_div_fixed; /** * ti_clk_div_set_freq() - Sets the frequency of a divider clock * @clkp: The divider clock to configure * @target_hz: Target frequency in Hz * @min_hz: Minimum acceptable frequency in Hz * @max_hz: Maximum acceptable frequency in Hz * @changed: Output parameter set to true if frequency changed * * This function adjusts the divider value to achieve the target frequency. * It can also propagate frequency changes to the parent if allowed. * * Return: Best achievable frequency in Hz, 0 on failure */ uint32_t ti_clk_div_set_freq(struct ti_clk *clkp, uint32_t target_hz, uint32_t min_hz, uint32_t max_hz, bool *changed); /** * ti_clk_div_get_freq() - Gets the current frequency of a divider clock * @clkp: The divider clock to query * * Return: Current frequency in Hz */ uint32_t ti_clk_div_get_freq(struct ti_clk *clkp); /** * ti_clk_div_set_freq_static_parent() - Sets frequency for dividers with fixed parent frequency * @clkp: The divider clock to configure * @target_hz: Target frequency in Hz * @min_hz: Minimum acceptable frequency in Hz * @max_hz: Maximum acceptable frequency in Hz * @changed: Output parameter set to true if frequency changed * * This variant is optimized for dividers whose parent frequency cannot * be changed. It only adjusts the divider value itself. * * Return: Best achievable frequency in Hz, 0 on failure */ uint32_t ti_clk_div_set_freq_static_parent(struct ti_clk *clkp, uint32_t target_hz, uint32_t min_hz, uint32_t max_hz, bool *changed); /** * ti_clk_div_reg_go_get_div() - Gets divider value for GO-bit register divider * @clkp: The divider clock to query * * Return: Current divider value */ uint32_t ti_clk_div_reg_go_get_div(struct ti_clk *clkp); /** * ti_clk_div_reg_go_set_div() - Sets divider value for GO-bit register divider * @clkp: The divider clock to modify * @div: The divider value to set * * Sets the divider value and triggers the GO bit to propagate the change. * * Return: True if successful */ bool ti_clk_div_reg_go_set_div(struct ti_clk *clkp, uint32_t div); /** * ti_clk_div_reg_get_div() - Gets divider value from register-based divider * @clkp: The divider clock to query * * Return: Current divider value */ uint32_t ti_clk_div_reg_get_div(struct ti_clk *clkp); /** * ti_clk_div_reg_set_div() - Sets divider value for register-based divider * @clkp: The divider clock to modify * @div: The divider value to set * * Return: True if successful */ bool ti_clk_div_reg_set_div(struct ti_clk *clkp, uint32_t div); /** * ti_clk_get_div() - Generic divider value getter * @clkp: The divider clock to query * * Dispatches to the appropriate driver-specific get_div function. * * Return: Current divider value */ uint32_t ti_clk_get_div(struct ti_clk *clkp); /** * ti_clk_div_init() - Initializes a divider clock * @clkp: The divider clock to initialize * * Performs initialization including setting default divider value and * configuring hardware registers. * * Return: 0 on success, error code otherwise */ int32_t ti_clk_div_init(struct ti_clk *clkp); #endif /* TI_CLK_DIV_H */