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:
Hugo Villeneuve 2026-04-17 10:53:32 -04:00 committed by Greg Kroah-Hartman
parent ffc3414d15
commit d0001adcd1

View File

@ -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;
}