162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2018-2019 SiFive, Inc. 462306a36Sopenharmony_ci * Wesley Terpstra 562306a36Sopenharmony_ci * Paul Walmsley 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This library supports configuration parsing and reprogramming of 862306a36Sopenharmony_ci * the CLN28HPC variant of the Analog Bits Wide Range PLL. The 962306a36Sopenharmony_ci * intention is for this library to be reusable for any device that 1062306a36Sopenharmony_ci * integrates this PLL; thus the register structure and programming 1162306a36Sopenharmony_ci * details are expected to be provided by a separate IP block driver. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The bulk of this code is primarily useful for clock configurations 1462306a36Sopenharmony_ci * that must operate at arbitrary rates, as opposed to clock configurations 1562306a36Sopenharmony_ci * that are restricted by software or manufacturer guidance to a small, 1662306a36Sopenharmony_ci * pre-determined set of performance points. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * References: 1962306a36Sopenharmony_ci * - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01 2062306a36Sopenharmony_ci * - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset" 2162306a36Sopenharmony_ci * https://static.dev.sifive.com/FU540-C000-v1.0.pdf 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/bug.h> 2562306a36Sopenharmony_ci#include <linux/err.h> 2662306a36Sopenharmony_ci#include <linux/limits.h> 2762306a36Sopenharmony_ci#include <linux/log2.h> 2862306a36Sopenharmony_ci#include <linux/math64.h> 2962306a36Sopenharmony_ci#include <linux/math.h> 3062306a36Sopenharmony_ci#include <linux/minmax.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <linux/clk/analogbits-wrpll-cln28hpc.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */ 3562306a36Sopenharmony_ci#define MIN_INPUT_FREQ 7000000 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* MAX_INPUT_FREQ: maximum input clock frequency, in Hz (Fref_max) */ 3862306a36Sopenharmony_ci#define MAX_INPUT_FREQ 600000000 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* MIN_POST_DIVIDE_REF_FREQ: minimum post-divider reference frequency, in Hz */ 4162306a36Sopenharmony_ci#define MIN_POST_DIVR_FREQ 7000000 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* MAX_POST_DIVIDE_REF_FREQ: maximum post-divider reference frequency, in Hz */ 4462306a36Sopenharmony_ci#define MAX_POST_DIVR_FREQ 200000000 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* MIN_VCO_FREQ: minimum VCO frequency, in Hz (Fvco_min) */ 4762306a36Sopenharmony_ci#define MIN_VCO_FREQ 2400000000UL 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* MAX_VCO_FREQ: maximum VCO frequency, in Hz (Fvco_max) */ 5062306a36Sopenharmony_ci#define MAX_VCO_FREQ 4800000000ULL 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* MAX_DIVQ_DIVISOR: maximum output divisor. Selected by DIVQ = 6 */ 5362306a36Sopenharmony_ci#define MAX_DIVQ_DIVISOR 64 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* MAX_DIVR_DIVISOR: maximum reference divisor. Selected by DIVR = 63 */ 5662306a36Sopenharmony_ci#define MAX_DIVR_DIVISOR 64 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* MAX_LOCK_US: maximum PLL lock time, in microseconds (tLOCK_max) */ 5962306a36Sopenharmony_ci#define MAX_LOCK_US 70 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * ROUND_SHIFT: number of bits to shift to avoid precision loss in the rounding 6362306a36Sopenharmony_ci * algorithm 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci#define ROUND_SHIFT 20 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * Private functions 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/** 7262306a36Sopenharmony_ci * __wrpll_calc_filter_range() - determine PLL loop filter bandwidth 7362306a36Sopenharmony_ci * @post_divr_freq: input clock rate after the R divider 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * Select the value to be presented to the PLL RANGE input signals, based 7662306a36Sopenharmony_ci * on the input clock frequency after the post-R-divider @post_divr_freq. 7762306a36Sopenharmony_ci * This code follows the recommendations in the PLL datasheet for filter 7862306a36Sopenharmony_ci * range selection. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * Return: The RANGE value to be presented to the PLL configuration inputs, 8162306a36Sopenharmony_ci * or a negative return code upon error. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistatic int __wrpll_calc_filter_range(unsigned long post_divr_freq) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci if (post_divr_freq < MIN_POST_DIVR_FREQ || 8662306a36Sopenharmony_ci post_divr_freq > MAX_POST_DIVR_FREQ) { 8762306a36Sopenharmony_ci WARN(1, "%s: post-divider reference freq out of range: %lu", 8862306a36Sopenharmony_ci __func__, post_divr_freq); 8962306a36Sopenharmony_ci return -ERANGE; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci switch (post_divr_freq) { 9362306a36Sopenharmony_ci case 0 ... 10999999: 9462306a36Sopenharmony_ci return 1; 9562306a36Sopenharmony_ci case 11000000 ... 17999999: 9662306a36Sopenharmony_ci return 2; 9762306a36Sopenharmony_ci case 18000000 ... 29999999: 9862306a36Sopenharmony_ci return 3; 9962306a36Sopenharmony_ci case 30000000 ... 49999999: 10062306a36Sopenharmony_ci return 4; 10162306a36Sopenharmony_ci case 50000000 ... 79999999: 10262306a36Sopenharmony_ci return 5; 10362306a36Sopenharmony_ci case 80000000 ... 129999999: 10462306a36Sopenharmony_ci return 6; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return 7; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/** 11162306a36Sopenharmony_ci * __wrpll_calc_fbdiv() - return feedback fixed divide value 11262306a36Sopenharmony_ci * @c: ptr to a struct wrpll_cfg record to read from 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * The internal feedback path includes a fixed by-two divider; the 11562306a36Sopenharmony_ci * external feedback path does not. Return the appropriate divider 11662306a36Sopenharmony_ci * value (2 or 1) depending on whether internal or external feedback 11762306a36Sopenharmony_ci * is enabled. This code doesn't test for invalid configurations 11862306a36Sopenharmony_ci * (e.g. both or neither of WRPLL_FLAGS_*_FEEDBACK are set); it relies 11962306a36Sopenharmony_ci * on the caller to do so. 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Context: Any context. Caller must protect the memory pointed to by 12262306a36Sopenharmony_ci * @c from simultaneous modification. 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * Return: 2 if internal feedback is enabled or 1 if external feedback 12562306a36Sopenharmony_ci * is enabled. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cistatic u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * __wrpll_calc_divq() - determine DIVQ based on target PLL output clock rate 13462306a36Sopenharmony_ci * @target_rate: target PLL output clock rate 13562306a36Sopenharmony_ci * @vco_rate: pointer to a u64 to store the computed VCO rate into 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * Determine a reasonable value for the PLL Q post-divider, based on the 13862306a36Sopenharmony_ci * target output rate @target_rate for the PLL. Along with returning the 13962306a36Sopenharmony_ci * computed Q divider value as the return value, this function stores the 14062306a36Sopenharmony_ci * desired target VCO rate into the variable pointed to by @vco_rate. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * Context: Any context. Caller must protect the memory pointed to by 14362306a36Sopenharmony_ci * @vco_rate from simultaneous access or modification. 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci * Return: a positive integer DIVQ value to be programmed into the hardware 14662306a36Sopenharmony_ci * upon success, or 0 upon error (since 0 is an invalid DIVQ value) 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci u64 s; 15162306a36Sopenharmony_ci u8 divq = 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (!vco_rate) { 15462306a36Sopenharmony_ci WARN_ON(1); 15562306a36Sopenharmony_ci goto wcd_out; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci s = div_u64(MAX_VCO_FREQ, target_rate); 15962306a36Sopenharmony_ci if (s <= 1) { 16062306a36Sopenharmony_ci divq = 1; 16162306a36Sopenharmony_ci *vco_rate = MAX_VCO_FREQ; 16262306a36Sopenharmony_ci } else if (s > MAX_DIVQ_DIVISOR) { 16362306a36Sopenharmony_ci divq = ilog2(MAX_DIVQ_DIVISOR); 16462306a36Sopenharmony_ci *vco_rate = MIN_VCO_FREQ; 16562306a36Sopenharmony_ci } else { 16662306a36Sopenharmony_ci divq = ilog2(s); 16762306a36Sopenharmony_ci *vco_rate = (u64)target_rate << divq; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciwcd_out: 17162306a36Sopenharmony_ci return divq; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/** 17562306a36Sopenharmony_ci * __wrpll_update_parent_rate() - update PLL data when parent rate changes 17662306a36Sopenharmony_ci * @c: ptr to a struct wrpll_cfg record to write PLL data to 17762306a36Sopenharmony_ci * @parent_rate: PLL input refclk rate (pre-R-divider) 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * Pre-compute some data used by the PLL configuration algorithm when 18062306a36Sopenharmony_ci * the PLL's reference clock rate changes. The intention is to avoid 18162306a36Sopenharmony_ci * computation when the parent rate remains constant - expected to be 18262306a36Sopenharmony_ci * the common case. 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * Returns: 0 upon success or -ERANGE if the reference clock rate is 18562306a36Sopenharmony_ci * out of range. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_cistatic int __wrpll_update_parent_rate(struct wrpll_cfg *c, 18862306a36Sopenharmony_ci unsigned long parent_rate) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci u8 max_r_for_parent; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ) 19362306a36Sopenharmony_ci return -ERANGE; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci c->parent_rate = parent_rate; 19662306a36Sopenharmony_ci max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ); 19762306a36Sopenharmony_ci c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/** 20562306a36Sopenharmony_ci * wrpll_configure_for_rate() - compute PLL configuration for a target rate 20662306a36Sopenharmony_ci * @c: ptr to a struct wrpll_cfg record to write into 20762306a36Sopenharmony_ci * @target_rate: target PLL output clock rate (post-Q-divider) 20862306a36Sopenharmony_ci * @parent_rate: PLL input refclk rate (pre-R-divider) 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Compute the appropriate PLL signal configuration values and store 21162306a36Sopenharmony_ci * in PLL context @c. PLL reprogramming is not glitchless, so the 21262306a36Sopenharmony_ci * caller should switch any downstream logic to a different clock 21362306a36Sopenharmony_ci * source or clock-gate it before presenting these values to the PLL 21462306a36Sopenharmony_ci * configuration signals. 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * The caller must pass this function a pre-initialized struct 21762306a36Sopenharmony_ci * wrpll_cfg record: either initialized to zero (with the 21862306a36Sopenharmony_ci * exception of the .name and .flags fields) or read from the PLL. 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * Context: Any context. Caller must protect the memory pointed to by @c 22162306a36Sopenharmony_ci * from simultaneous access or modification. 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * Return: 0 upon success; anything else upon failure. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ciint wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate, 22662306a36Sopenharmony_ci unsigned long parent_rate) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci unsigned long ratio; 22962306a36Sopenharmony_ci u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre; 23062306a36Sopenharmony_ci u32 best_f, f, post_divr_freq; 23162306a36Sopenharmony_ci u8 fbdiv, divq, best_r, r; 23262306a36Sopenharmony_ci int range; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (c->flags == 0) { 23562306a36Sopenharmony_ci WARN(1, "%s called with uninitialized PLL config", __func__); 23662306a36Sopenharmony_ci return -EINVAL; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Initialize rounding data if it hasn't been initialized already */ 24062306a36Sopenharmony_ci if (parent_rate != c->parent_rate) { 24162306a36Sopenharmony_ci if (__wrpll_update_parent_rate(c, parent_rate)) { 24262306a36Sopenharmony_ci pr_err("%s: PLL input rate is out of range\n", 24362306a36Sopenharmony_ci __func__); 24462306a36Sopenharmony_ci return -ERANGE; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci c->flags &= ~WRPLL_FLAGS_RESET_MASK; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Put the PLL into bypass if the user requests the parent clock rate */ 25162306a36Sopenharmony_ci if (target_rate == parent_rate) { 25262306a36Sopenharmony_ci c->flags |= WRPLL_FLAGS_BYPASS_MASK; 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci c->flags &= ~WRPLL_FLAGS_BYPASS_MASK; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Calculate the Q shift and target VCO rate */ 25962306a36Sopenharmony_ci divq = __wrpll_calc_divq(target_rate, &target_vco_rate); 26062306a36Sopenharmony_ci if (!divq) 26162306a36Sopenharmony_ci return -1; 26262306a36Sopenharmony_ci c->divq = divq; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Precalculate the pre-Q divider target ratio */ 26562306a36Sopenharmony_ci ratio = div64_u64((target_vco_rate << ROUND_SHIFT), parent_rate); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci fbdiv = __wrpll_calc_fbdiv(c); 26862306a36Sopenharmony_ci best_r = 0; 26962306a36Sopenharmony_ci best_f = 0; 27062306a36Sopenharmony_ci best_delta = MAX_VCO_FREQ; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * Consider all values for R which land within 27462306a36Sopenharmony_ci * [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci for (r = c->init_r; r <= c->max_r; ++r) { 27762306a36Sopenharmony_ci f_pre_div = ratio * r; 27862306a36Sopenharmony_ci f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT; 27962306a36Sopenharmony_ci f >>= (fbdiv - 1); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci post_divr_freq = div_u64(parent_rate, r); 28262306a36Sopenharmony_ci vco_pre = fbdiv * post_divr_freq; 28362306a36Sopenharmony_ci vco = vco_pre * f; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* Ensure rounding didn't take us out of range */ 28662306a36Sopenharmony_ci if (vco > target_vco_rate) { 28762306a36Sopenharmony_ci --f; 28862306a36Sopenharmony_ci vco = vco_pre * f; 28962306a36Sopenharmony_ci } else if (vco < MIN_VCO_FREQ) { 29062306a36Sopenharmony_ci ++f; 29162306a36Sopenharmony_ci vco = vco_pre * f; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci delta = abs(target_rate - vco); 29562306a36Sopenharmony_ci if (delta < best_delta) { 29662306a36Sopenharmony_ci best_delta = delta; 29762306a36Sopenharmony_ci best_r = r; 29862306a36Sopenharmony_ci best_f = f; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci c->divr = best_r - 1; 30362306a36Sopenharmony_ci c->divf = best_f - 1; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci post_divr_freq = div_u64(parent_rate, best_r); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Pick the best PLL jitter filter */ 30862306a36Sopenharmony_ci range = __wrpll_calc_filter_range(post_divr_freq); 30962306a36Sopenharmony_ci if (range < 0) 31062306a36Sopenharmony_ci return range; 31162306a36Sopenharmony_ci c->range = range; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/** 31762306a36Sopenharmony_ci * wrpll_calc_output_rate() - calculate the PLL's target output rate 31862306a36Sopenharmony_ci * @c: ptr to a struct wrpll_cfg record to read from 31962306a36Sopenharmony_ci * @parent_rate: PLL refclk rate 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * Given a pointer to the PLL's current input configuration @c and the 32262306a36Sopenharmony_ci * PLL's input reference clock rate @parent_rate (before the R 32362306a36Sopenharmony_ci * pre-divider), calculate the PLL's output clock rate (after the Q 32462306a36Sopenharmony_ci * post-divider). 32562306a36Sopenharmony_ci * 32662306a36Sopenharmony_ci * Context: Any context. Caller must protect the memory pointed to by @c 32762306a36Sopenharmony_ci * from simultaneous modification. 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * Return: the PLL's output clock rate, in Hz. The return value from 33062306a36Sopenharmony_ci * this function is intended to be convenient to pass directly 33162306a36Sopenharmony_ci * to the Linux clock framework; thus there is no explicit 33262306a36Sopenharmony_ci * error return value. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ciunsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c, 33562306a36Sopenharmony_ci unsigned long parent_rate) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci u8 fbdiv; 33862306a36Sopenharmony_ci u64 n; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) { 34162306a36Sopenharmony_ci WARN(1, "external feedback mode not yet supported"); 34262306a36Sopenharmony_ci return ULONG_MAX; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci fbdiv = __wrpll_calc_fbdiv(c); 34662306a36Sopenharmony_ci n = parent_rate * fbdiv * (c->divf + 1); 34762306a36Sopenharmony_ci n = div_u64(n, c->divr + 1); 34862306a36Sopenharmony_ci n >>= c->divq; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return n; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/** 35462306a36Sopenharmony_ci * wrpll_calc_max_lock_us() - return the time for the PLL to lock 35562306a36Sopenharmony_ci * @c: ptr to a struct wrpll_cfg record to read from 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * Return the minimum amount of time (in microseconds) that the caller 35862306a36Sopenharmony_ci * must wait after reprogramming the PLL to ensure that it is locked 35962306a36Sopenharmony_ci * to the input frequency and stable. This is likely to depend on the DIVR 36062306a36Sopenharmony_ci * value; this is under discussion with the manufacturer. 36162306a36Sopenharmony_ci * 36262306a36Sopenharmony_ci * Return: the minimum amount of time the caller must wait for the PLL 36362306a36Sopenharmony_ci * to lock (in microseconds) 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ciunsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci return MAX_LOCK_US; 36862306a36Sopenharmony_ci} 369