[PATCH v1 1/3] serial: 8250: introduce helper to configure prescaler

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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)
+{
+	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
-- 
2.1.4

--
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




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux