Hi Andy, On 03/11/2015 04:19 PM, Andy Shevchenko wrote: > The fractional divider is used to provide different frequencies from one > source. The following formulas are used to show the relations between Fref, > Fuart, prescaler, nominator, and denominator values: > > Fuart = Fref * m / n > baud = Fuart / (prescaler * DLAB) > > where prescaler value is in range 1..16. > > The helper function returns prescaler, nominator, and denominator values. It > also sets port UART clock to the corresponding value. Since serial core > considers base Fuart = baud * 16, the given value of Fuart will be in > proportion to that: > > Port UART clock = Fuart * 16 / prescaler > > Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> > --- > drivers/tty/serial/8250/8250.h | 4 +++ > drivers/tty/serial/8250/8250_core.c | 54 +++++++++++++++++++++++++++++++++++++ > 2 files changed, 58 insertions(+) > > diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h > index 656ecc6..feed6a3 100644 > --- a/drivers/tty/serial/8250/8250.h > +++ b/drivers/tty/serial/8250/8250.h > @@ -198,3 +198,7 @@ static inline int serial8250_request_dma(struct uart_8250_port *p) > } > static inline void serial8250_release_dma(struct uart_8250_port *p) { } > #endif > + > +unsigned short serial8250_get_ps(struct uart_port *port, unsigned int baud, > + unsigned int fref, unsigned short width, > + unsigned int *m, unsigned int *n); > diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c > index 7b502c0..09803f5 100644 > --- a/drivers/tty/serial/8250/8250_core.c > +++ b/drivers/tty/serial/8250/8250_core.c > @@ -27,6 +27,7 @@ > #include <linux/console.h> > #include <linux/sysrq.h> > #include <linux/delay.h> > +#include <linux/gcd.h> > #include <linux/platform_device.h> > #include <linux/tty.h> > #include <linux/ratelimit.h> > @@ -2412,6 +2413,59 @@ static void serial8250_shutdown(struct uart_port *port) > serial8250_do_shutdown(port); > } > > +/** > + * serial8250_get_ps - calculates prescaler, nominator, and denominator values > + * @port: pointer to struct uart_port object > + * @baud: baud rate > + * @fref: reference frequency in Hz > + * @width: maximum width of @m and @n in bits > + * @m: nominator of fractional divider > + * @n: denominator of fractional divider > + * > + * The fractional divider is used to provide different frequencies from one > + * source. The following formulas are used to show the relations between Fref, > + * Fuart, prescaler, nominator, and denominator values: > + * > + * Fuart = Fref * m / n, where m <= n > + * > + * baud = Fuart / (prescaler * DLAB) > + * > + * Return: > + * Prescaler value from 16 to 1, and sets port UART clock to the corresponding > + * value. Since serial core considers base Fuart = baud * 16, the given value > + * of Fuart will be in proportion to that: > + * > + * Port UART clock = Fuart * 16 / prescaler > + */ > +unsigned short serial8250_get_ps(struct uart_port *port, unsigned int baud, > + unsigned int fref, unsigned short width, > + unsigned int *m, unsigned int *n) I don't think this belongs in the 8250 core; this should be a static helper function to those 2 Intel parts. Unless you think this is applicable to any other designs? Regards, Peter Hurley > +{ > + unsigned int fuart; > + unsigned int ps = 16, divisor, denominator; > + > + /* Find prescaler value that satisfies Fuart < Fref */ > + do { > + fuart = baud * ps; > + } while ((fuart > fref) && (--ps > 1)); > + > + /* Get Fuart closer to Fref */ > + fuart *= rounddown_pow_of_two(fref / fuart); > + > + /* Get a greatest common divisor */ > + divisor = gcd(fref, fuart); > + > + denominator = fref / divisor; > + while (denominator > BIT(width)) { > + divisor <<= 1; > + denominator >>= 1; > + } > + *n = denominator; > + *m = fuart / divisor; > + port->uartclk = fuart * 16 / ps; > + return ps; > +} > + > /* > * XR17V35x UARTs have an extra fractional divisor register (DLD) > * Calculate divisor with extra 4-bit fractional portion > -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html