mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
serial: max310x: improve max310x_set_ref_clk() efficiency
The same basic code is duplicated for each of the four PLL multiplier values, so simplify and streamline it. Doing so allows us to avoid some unnecessary (fdiv * factor) multiplications for some fdiv values and replace the second "if" statement with an "else if" and avoid a useless comparison. Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com> Link: https://patch.msgid.link/20260417-max310x-2-v1-5-b424e105ecac@dimonoff.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ffc3414d15
commit
d0001adcd1
|
|
@ -258,6 +258,17 @@
|
|||
#define MAX14830_BRGCFG_CLKDIS_BIT (1 << 6) /* Clock Disable */
|
||||
#define MAX14830_REV_ID (0xb0)
|
||||
|
||||
struct max310x_clk_config_t {
|
||||
u8 prediv; /* Predivider */
|
||||
u8 pll_mult; /* PLL multiplier */
|
||||
unsigned int fref; /*
|
||||
* Reference clock for fractional baud rate generator:
|
||||
* PLL enabled: (freq / prediv) x pll_mult
|
||||
* PLL disabled: freq
|
||||
*/
|
||||
unsigned int err; /* Computed error for selected parameters */
|
||||
};
|
||||
|
||||
struct max310x_if_cfg {
|
||||
int (*extended_reg_enable)(struct device *dev, bool enable);
|
||||
u8 rev_id_offset;
|
||||
|
|
@ -545,70 +556,72 @@ static int max310x_set_baud(struct uart_port *port, int baud)
|
|||
return (16*port->uartclk) / (c*(16*div + frac));
|
||||
}
|
||||
|
||||
static int max310x_update_best_err(unsigned int f, unsigned int *besterr)
|
||||
static void max310x_try_cfg(unsigned int fdiv, u8 div, u8 pll_mult,
|
||||
struct max310x_clk_config_t *cfg)
|
||||
{
|
||||
unsigned int fmul = fdiv * pll_mult;
|
||||
unsigned int err;
|
||||
|
||||
/* Use high-enough baudrate to calculate error */
|
||||
unsigned int err = f % (460800 * 16);
|
||||
err = fmul % (460800 * 16);
|
||||
|
||||
if (*besterr > err) {
|
||||
*besterr = err;
|
||||
return 0;
|
||||
if (cfg->err > err) {
|
||||
cfg->err = err;
|
||||
cfg->pll_mult = pll_mult;
|
||||
cfg->prediv = div;
|
||||
cfg->fref = fmul;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
static u8 max310x_pll_mult_to_id(u8 pll_mult)
|
||||
{
|
||||
switch (pll_mult) {
|
||||
case 144: return 3;
|
||||
case 96: return 2;
|
||||
case 48: return 1;
|
||||
case 6:
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
|
||||
unsigned int freq, unsigned int *fref, bool xtal)
|
||||
{
|
||||
unsigned int div, clksrc, pllcfg = 0;
|
||||
unsigned int besterr = UINT_MAX;
|
||||
unsigned int fdiv, fmul, bestfreq = freq;
|
||||
unsigned int div, fdiv, clksrc;
|
||||
struct max310x_clk_config_t cfg;
|
||||
|
||||
cfg.err = UINT_MAX;
|
||||
cfg.prediv = 0;
|
||||
cfg.fref = freq;
|
||||
|
||||
/* First, update error without PLL */
|
||||
max310x_update_best_err(freq, &besterr);
|
||||
max310x_try_cfg(freq, 1, 1, &cfg);
|
||||
|
||||
/* Try all possible PLL dividers */
|
||||
for (div = 1; (div <= 63) && besterr; div++) {
|
||||
for (div = 1; (div <= 63) && cfg.err; div++) {
|
||||
fdiv = DIV_ROUND_CLOSEST(freq, div);
|
||||
|
||||
/* Try multiplier 6 */
|
||||
fmul = fdiv * 6;
|
||||
if ((fdiv >= 500000) && (fdiv <= 800000))
|
||||
if (!max310x_update_best_err(fmul, &besterr)) {
|
||||
pllcfg = (0 << 6) | div;
|
||||
bestfreq = fmul;
|
||||
}
|
||||
/* Try multiplier 48 */
|
||||
fmul = fdiv * 48;
|
||||
if ((fdiv >= 850000) && (fdiv <= 1200000))
|
||||
if (!max310x_update_best_err(fmul, &besterr)) {
|
||||
pllcfg = (1 << 6) | div;
|
||||
bestfreq = fmul;
|
||||
}
|
||||
/* Try multiplier 96 */
|
||||
fmul = fdiv * 96;
|
||||
max310x_try_cfg(fdiv, div, 6, &cfg); /* PLL x6 */
|
||||
else if ((fdiv >= 850000) && (fdiv <= 1200000))
|
||||
max310x_try_cfg(fdiv, div, 48, &cfg); /* PLL x48 */
|
||||
|
||||
if ((fdiv >= 425000) && (fdiv <= 1000000))
|
||||
if (!max310x_update_best_err(fmul, &besterr)) {
|
||||
pllcfg = (2 << 6) | div;
|
||||
bestfreq = fmul;
|
||||
}
|
||||
/* Try multiplier 144 */
|
||||
fmul = fdiv * 144;
|
||||
max310x_try_cfg(fdiv, div, 96, &cfg); /* PLL x96 */
|
||||
|
||||
if ((fdiv >= 390000) && (fdiv <= 667000))
|
||||
if (!max310x_update_best_err(fmul, &besterr)) {
|
||||
pllcfg = (3 << 6) | div;
|
||||
bestfreq = fmul;
|
||||
}
|
||||
max310x_try_cfg(fdiv, div, 144, &cfg); /* PLL x144 */
|
||||
}
|
||||
|
||||
/* Configure clock source */
|
||||
clksrc = MAX310X_CLKSRC_EXTCLK_BIT | (xtal ? MAX310X_CLKSRC_CRYST_BIT : 0);
|
||||
|
||||
/* Configure PLL */
|
||||
if (pllcfg) {
|
||||
if (cfg.prediv) {
|
||||
u8 pll_id = max310x_pll_mult_to_id(cfg.pll_mult);
|
||||
|
||||
clksrc |= MAX310X_CLKSRC_PLL_BIT;
|
||||
regmap_write(s->regmap, MAX310X_PLLCFG_REG, pllcfg);
|
||||
regmap_write(s->regmap, MAX310X_PLLCFG_REG, (pll_id << 6) | cfg.prediv);
|
||||
} else
|
||||
clksrc |= MAX310X_CLKSRC_PLLBYP_BIT;
|
||||
|
||||
|
|
@ -632,7 +645,7 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
|
|||
"clock is not stable\n");
|
||||
}
|
||||
|
||||
*fref = bestfreq;
|
||||
*fref = cfg.fref;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user