]> git.ipfire.org Git - thirdparty/openembedded/openembedded-core-contrib.git/blob
b513ba1466dd7012418ee48889fe8cd8092ca23c
[thirdparty/openembedded/openembedded-core-contrib.git] /
1
2 From: Petr Vandrovec <vandrove@vc.cvut.cz>
3
4 Patch below adds support for using different prescaler than 16 for 16c950
5 chips. This is needed for using Fujitsu-Siemens Connect2Air compact-flash
6 card, which comes (apparently) with 806kHz clocks, and so you have to
7 program prescaler for division by 7, and DLAB to 1, to get 115200Bd.
8
9 To get card properly running you also have to add lines below to
10 /etc/pcmcia/serial.opts so kernel knows that base speed is not 115200 but
11 50400 (50400 * 16 = 806400; 806400 / 7 = 115200). As I've found no code
12 specifying baud_rate in serial_cs, I assume that specifying it in
13 serial.opts is right way to do this type of things.
14
15 Patch also fixes problem that for UPF_MAGIC_MULTIPLIER maximum possible
16 baud rate passed to uart code was uartclk / 16 while correct value for
17 these devices (and for 16c950) is uartclk / 4.
18
19 Patch also fixes problem that for UPF_MAGIC_MULTIPLIER devices with
20 baud_rate 19200 or 9600 spd_cust did not work correctly. Not that such
21 devices exist, but we should not ignore spd_cust, user probably knows why
22 he asked for spd_cust.
23
24 serial.opts:
25
26 case "$MANFID-$FUNCID-$PRODID_1-$PRODID_2-$PRODID_3-$PRODID_4" in
27 '0279,950b-2-GPRS Modem---')
28 SERIAL_OPTS="baud_base 50400"
29 ;;
30 esac
31
32 Cc: David Woodhouse <dwmw2@infradead.org>
33 Signed-off-by: Andrew Morton <akpm@osdl.org>
34 ---
35
36 drivers/serial/8250.c | 82 +++++++++++++++++++++++++++++++++++++++-----------
37 1 file changed, 64 insertions(+), 18 deletions(-)
38
39 Index: linux-2.6.21/drivers/serial/8250.c
40 ===================================================================
41 --- linux-2.6.21.orig/drivers/serial/8250.c 2007-07-01 16:59:52.000000000 +0100
42 +++ linux-2.6.21/drivers/serial/8250.c 2007-07-01 17:01:21.000000000 +0100
43 @@ -1964,24 +1964,58 @@ static void serial8250_shutdown(struct u
44 serial_unlink_irq_chain(up);
45 }
46
47 -static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
48 +static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud,
49 + unsigned int *prescaler)
50 {
51 - unsigned int quot;
52 -
53 - /*
54 - * Handle magic divisors for baud rates above baud_base on
55 - * SMSC SuperIO chips.
56 + /*
57 + * Use special handling only if user did not supply its own divider.
58 + * spd_cust is defined in terms of baud_base, so always use default
59 + * prescaler when spd_cust is requested.
60 */
61 - if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
62 - baud == (port->uartclk/4))
63 - quot = 0x8001;
64 - else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
65 - baud == (port->uartclk/8))
66 - quot = 0x8002;
67 - else
68 - quot = uart_get_divisor(port, baud);
69
70 - return quot;
71 + *prescaler = 16;
72 + if (baud != 38400 || (port->flags & UPF_SPD_MASK) != UPF_SPD_CUST) {
73 + unsigned int quot = port->uartclk / baud;
74 +
75 + /*
76 + * Handle magic divisors for baud rates above baud_base on
77 + * SMSC SuperIO chips.
78 + */
79 + if (port->flags & UPF_MAGIC_MULTIPLIER) {
80 + if (quot == 4) {
81 + return 0x8001;
82 + } else if (quot == 8) {
83 + return 0x8002;
84 + }
85 + }
86 + if (port->type == PORT_16C950) {
87 + /*
88 + * This computes TCR value (4 to 16), not CPR value (which can
89 + * be between 1.000 and 31.875) - chip I have uses XTAL of
90 + * 806400Hz, and so a division by 7 is required to get 115200Bd.
91 + * I'm leaving CPR disabled for now, until someone will
92 + * hit even more exotic XTAL (it is needed to get 500kbps
93 + * or 1000kbps from 18.432MHz XTAL, but I have no device
94 + * which would benefit from doing that).
95 + *
96 + * If we can use divide by 16, use it. Otherwise look for
97 + * better prescaler, from 15 to 4. If quotient cannot
98 + * be divided by any integer value between 4 and 15, use 4.
99 + */
100 + if (quot & 0x0F) {
101 + unsigned int div;
102 +
103 + for (div = 15; div > 4; div--) {
104 + if (quot % div == 0) {
105 + break;
106 + }
107 + }
108 + *prescaler = div;
109 + return quot / div;
110 + }
111 + }
112 + }
113 + return uart_get_divisor(port, baud);
114 }
115
116 static void
117 @@ -1991,7 +2025,7 @@ serial8250_set_termios(struct uart_port
118 struct uart_8250_port *up = (struct uart_8250_port *)port;
119 unsigned char cval, fcr = 0;
120 unsigned long flags;
121 - unsigned int baud, quot;
122 + unsigned int baud, quot, prescaler;
123
124 switch (termios->c_cflag & CSIZE) {
125 case CS5:
126 @@ -2023,8 +2057,13 @@ serial8250_set_termios(struct uart_port
127 /*
128 * Ask the core to calculate the divisor for us.
129 */
130 - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
131 - quot = serial8250_get_divisor(port, baud);
132 + if (port->type == PORT_16C950 || (port->flags & UPF_MAGIC_MULTIPLIER)) {
133 + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/4);
134 + } else {
135 + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
136 + }
137 + quot = serial8250_get_divisor(port, baud, &prescaler);
138 +
139
140 /*
141 * Oxford Semi 952 rev B workaround
142 @@ -2139,6 +2178,13 @@ serial8250_set_termios(struct uart_port
143 serial_dl_write(up, quot);
144
145 /*
146 + * Program prescaler for 16C950 chips.
147 + */
148 + if (up->port.type == PORT_16C950) {
149 + serial_icr_write(up, UART_TCR, prescaler == 16 ? 0 : prescaler);
150 + }
151 +
152 + /*
153 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
154 * is written without DLAB set, this mode will be disabled.
155 */