1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Based on drivers/char/serial.c
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/tty.h>
9*4882a593Smuzhiyun #include <linux/ioport.h>
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/console.h>
12*4882a593Smuzhiyun #include <linux/device.h>
13*4882a593Smuzhiyun #include <linux/tty_flip.h>
14*4882a593Smuzhiyun #include <linux/serial_core.h>
15*4882a593Smuzhiyun #include <linux/serial.h>
16*4882a593Smuzhiyun #include <linux/io.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <asm/irq.h>
19*4882a593Smuzhiyun #include <asm/mach-types.h>
20*4882a593Smuzhiyun #include <asm/system_info.h>
21*4882a593Smuzhiyun #include <asm/hardware/dec21285.h>
22*4882a593Smuzhiyun #include <mach/hardware.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define BAUD_BASE (mem_fclk_21285/64)
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define SERIAL_21285_NAME "ttyFB"
27*4882a593Smuzhiyun #define SERIAL_21285_MAJOR 204
28*4882a593Smuzhiyun #define SERIAL_21285_MINOR 4
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define RXSTAT_DUMMY_READ 0x80000000
31*4882a593Smuzhiyun #define RXSTAT_FRAME (1 << 0)
32*4882a593Smuzhiyun #define RXSTAT_PARITY (1 << 1)
33*4882a593Smuzhiyun #define RXSTAT_OVERRUN (1 << 2)
34*4882a593Smuzhiyun #define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define H_UBRLCR_BREAK (1 << 0)
37*4882a593Smuzhiyun #define H_UBRLCR_PARENB (1 << 1)
38*4882a593Smuzhiyun #define H_UBRLCR_PAREVN (1 << 2)
39*4882a593Smuzhiyun #define H_UBRLCR_STOPB (1 << 3)
40*4882a593Smuzhiyun #define H_UBRLCR_FIFO (1 << 4)
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static const char serial21285_name[] = "Footbridge UART";
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun * We only need 2 bits of data, so instead of creating a whole structure for
46*4882a593Smuzhiyun * this, use bits of the private_data pointer of the uart port structure.
47*4882a593Smuzhiyun */
48*4882a593Smuzhiyun #define tx_enabled_bit 0
49*4882a593Smuzhiyun #define rx_enabled_bit 1
50*4882a593Smuzhiyun
is_enabled(struct uart_port * port,int bit)51*4882a593Smuzhiyun static bool is_enabled(struct uart_port *port, int bit)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun unsigned long *private_data = (unsigned long *)&port->private_data;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun if (test_bit(bit, private_data))
56*4882a593Smuzhiyun return true;
57*4882a593Smuzhiyun return false;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
enable(struct uart_port * port,int bit)60*4882a593Smuzhiyun static void enable(struct uart_port *port, int bit)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun unsigned long *private_data = (unsigned long *)&port->private_data;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun set_bit(bit, private_data);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
disable(struct uart_port * port,int bit)67*4882a593Smuzhiyun static void disable(struct uart_port *port, int bit)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun unsigned long *private_data = (unsigned long *)&port->private_data;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun clear_bit(bit, private_data);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun #define is_tx_enabled(port) is_enabled(port, tx_enabled_bit)
75*4882a593Smuzhiyun #define tx_enable(port) enable(port, tx_enabled_bit)
76*4882a593Smuzhiyun #define tx_disable(port) disable(port, tx_enabled_bit)
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun #define is_rx_enabled(port) is_enabled(port, rx_enabled_bit)
79*4882a593Smuzhiyun #define rx_enable(port) enable(port, rx_enabled_bit)
80*4882a593Smuzhiyun #define rx_disable(port) disable(port, rx_enabled_bit)
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /*
83*4882a593Smuzhiyun * The documented expression for selecting the divisor is:
84*4882a593Smuzhiyun * BAUD_BASE / baud - 1
85*4882a593Smuzhiyun * However, typically BAUD_BASE is not divisible by baud, so
86*4882a593Smuzhiyun * we want to select the divisor that gives us the minimum
87*4882a593Smuzhiyun * error. Therefore, we want:
88*4882a593Smuzhiyun * int(BAUD_BASE / baud - 0.5) ->
89*4882a593Smuzhiyun * int(BAUD_BASE / baud - (baud >> 1) / baud) ->
90*4882a593Smuzhiyun * int((BAUD_BASE - (baud >> 1)) / baud)
91*4882a593Smuzhiyun */
92*4882a593Smuzhiyun
serial21285_stop_tx(struct uart_port * port)93*4882a593Smuzhiyun static void serial21285_stop_tx(struct uart_port *port)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun if (is_tx_enabled(port)) {
96*4882a593Smuzhiyun disable_irq_nosync(IRQ_CONTX);
97*4882a593Smuzhiyun tx_disable(port);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
serial21285_start_tx(struct uart_port * port)101*4882a593Smuzhiyun static void serial21285_start_tx(struct uart_port *port)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun if (!is_tx_enabled(port)) {
104*4882a593Smuzhiyun enable_irq(IRQ_CONTX);
105*4882a593Smuzhiyun tx_enable(port);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
serial21285_stop_rx(struct uart_port * port)109*4882a593Smuzhiyun static void serial21285_stop_rx(struct uart_port *port)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun if (is_rx_enabled(port)) {
112*4882a593Smuzhiyun disable_irq_nosync(IRQ_CONRX);
113*4882a593Smuzhiyun rx_disable(port);
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
serial21285_rx_chars(int irq,void * dev_id)117*4882a593Smuzhiyun static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun struct uart_port *port = dev_id;
120*4882a593Smuzhiyun unsigned int status, ch, flag, rxs, max_count = 256;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun status = *CSR_UARTFLG;
123*4882a593Smuzhiyun while (!(status & 0x10) && max_count--) {
124*4882a593Smuzhiyun ch = *CSR_UARTDR;
125*4882a593Smuzhiyun flag = TTY_NORMAL;
126*4882a593Smuzhiyun port->icount.rx++;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
129*4882a593Smuzhiyun if (unlikely(rxs & RXSTAT_ANYERR)) {
130*4882a593Smuzhiyun if (rxs & RXSTAT_PARITY)
131*4882a593Smuzhiyun port->icount.parity++;
132*4882a593Smuzhiyun else if (rxs & RXSTAT_FRAME)
133*4882a593Smuzhiyun port->icount.frame++;
134*4882a593Smuzhiyun if (rxs & RXSTAT_OVERRUN)
135*4882a593Smuzhiyun port->icount.overrun++;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun rxs &= port->read_status_mask;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (rxs & RXSTAT_PARITY)
140*4882a593Smuzhiyun flag = TTY_PARITY;
141*4882a593Smuzhiyun else if (rxs & RXSTAT_FRAME)
142*4882a593Smuzhiyun flag = TTY_FRAME;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun status = *CSR_UARTFLG;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun tty_flip_buffer_push(&port->state->port);
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return IRQ_HANDLED;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
serial21285_tx_chars(int irq,void * dev_id)154*4882a593Smuzhiyun static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun struct uart_port *port = dev_id;
157*4882a593Smuzhiyun struct circ_buf *xmit = &port->state->xmit;
158*4882a593Smuzhiyun int count = 256;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (port->x_char) {
161*4882a593Smuzhiyun *CSR_UARTDR = port->x_char;
162*4882a593Smuzhiyun port->icount.tx++;
163*4882a593Smuzhiyun port->x_char = 0;
164*4882a593Smuzhiyun goto out;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
167*4882a593Smuzhiyun serial21285_stop_tx(port);
168*4882a593Smuzhiyun goto out;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun do {
172*4882a593Smuzhiyun *CSR_UARTDR = xmit->buf[xmit->tail];
173*4882a593Smuzhiyun xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
174*4882a593Smuzhiyun port->icount.tx++;
175*4882a593Smuzhiyun if (uart_circ_empty(xmit))
176*4882a593Smuzhiyun break;
177*4882a593Smuzhiyun } while (--count > 0 && !(*CSR_UARTFLG & 0x20));
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
180*4882a593Smuzhiyun uart_write_wakeup(port);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (uart_circ_empty(xmit))
183*4882a593Smuzhiyun serial21285_stop_tx(port);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun out:
186*4882a593Smuzhiyun return IRQ_HANDLED;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
serial21285_tx_empty(struct uart_port * port)189*4882a593Smuzhiyun static unsigned int serial21285_tx_empty(struct uart_port *port)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* no modem control lines */
serial21285_get_mctrl(struct uart_port * port)195*4882a593Smuzhiyun static unsigned int serial21285_get_mctrl(struct uart_port *port)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
serial21285_set_mctrl(struct uart_port * port,unsigned int mctrl)200*4882a593Smuzhiyun static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
serial21285_break_ctl(struct uart_port * port,int break_state)204*4882a593Smuzhiyun static void serial21285_break_ctl(struct uart_port *port, int break_state)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun unsigned long flags;
207*4882a593Smuzhiyun unsigned int h_lcr;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
210*4882a593Smuzhiyun h_lcr = *CSR_H_UBRLCR;
211*4882a593Smuzhiyun if (break_state)
212*4882a593Smuzhiyun h_lcr |= H_UBRLCR_BREAK;
213*4882a593Smuzhiyun else
214*4882a593Smuzhiyun h_lcr &= ~H_UBRLCR_BREAK;
215*4882a593Smuzhiyun *CSR_H_UBRLCR = h_lcr;
216*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
serial21285_startup(struct uart_port * port)219*4882a593Smuzhiyun static int serial21285_startup(struct uart_port *port)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun int ret;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun tx_enable(port);
224*4882a593Smuzhiyun rx_enable(port);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
227*4882a593Smuzhiyun serial21285_name, port);
228*4882a593Smuzhiyun if (ret == 0) {
229*4882a593Smuzhiyun ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
230*4882a593Smuzhiyun serial21285_name, port);
231*4882a593Smuzhiyun if (ret)
232*4882a593Smuzhiyun free_irq(IRQ_CONRX, port);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return ret;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
serial21285_shutdown(struct uart_port * port)238*4882a593Smuzhiyun static void serial21285_shutdown(struct uart_port *port)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun free_irq(IRQ_CONTX, port);
241*4882a593Smuzhiyun free_irq(IRQ_CONRX, port);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun static void
serial21285_set_termios(struct uart_port * port,struct ktermios * termios,struct ktermios * old)245*4882a593Smuzhiyun serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
246*4882a593Smuzhiyun struct ktermios *old)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun unsigned long flags;
249*4882a593Smuzhiyun unsigned int baud, quot, h_lcr, b;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /*
252*4882a593Smuzhiyun * We don't support modem control lines.
253*4882a593Smuzhiyun */
254*4882a593Smuzhiyun termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
255*4882a593Smuzhiyun termios->c_cflag |= CLOCAL;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /*
258*4882a593Smuzhiyun * We don't support BREAK character recognition.
259*4882a593Smuzhiyun */
260*4882a593Smuzhiyun termios->c_iflag &= ~(IGNBRK | BRKINT);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * Ask the core to calculate the divisor for us.
264*4882a593Smuzhiyun */
265*4882a593Smuzhiyun baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
266*4882a593Smuzhiyun quot = uart_get_divisor(port, baud);
267*4882a593Smuzhiyun b = port->uartclk / (16 * quot);
268*4882a593Smuzhiyun tty_termios_encode_baud_rate(termios, b, b);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun switch (termios->c_cflag & CSIZE) {
271*4882a593Smuzhiyun case CS5:
272*4882a593Smuzhiyun h_lcr = 0x00;
273*4882a593Smuzhiyun break;
274*4882a593Smuzhiyun case CS6:
275*4882a593Smuzhiyun h_lcr = 0x20;
276*4882a593Smuzhiyun break;
277*4882a593Smuzhiyun case CS7:
278*4882a593Smuzhiyun h_lcr = 0x40;
279*4882a593Smuzhiyun break;
280*4882a593Smuzhiyun default: /* CS8 */
281*4882a593Smuzhiyun h_lcr = 0x60;
282*4882a593Smuzhiyun break;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (termios->c_cflag & CSTOPB)
286*4882a593Smuzhiyun h_lcr |= H_UBRLCR_STOPB;
287*4882a593Smuzhiyun if (termios->c_cflag & PARENB) {
288*4882a593Smuzhiyun h_lcr |= H_UBRLCR_PARENB;
289*4882a593Smuzhiyun if (!(termios->c_cflag & PARODD))
290*4882a593Smuzhiyun h_lcr |= H_UBRLCR_PAREVN;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun if (port->fifosize)
294*4882a593Smuzhiyun h_lcr |= H_UBRLCR_FIFO;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /*
299*4882a593Smuzhiyun * Update the per-port timeout.
300*4882a593Smuzhiyun */
301*4882a593Smuzhiyun uart_update_timeout(port, termios->c_cflag, baud);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /*
304*4882a593Smuzhiyun * Which character status flags are we interested in?
305*4882a593Smuzhiyun */
306*4882a593Smuzhiyun port->read_status_mask = RXSTAT_OVERRUN;
307*4882a593Smuzhiyun if (termios->c_iflag & INPCK)
308*4882a593Smuzhiyun port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /*
311*4882a593Smuzhiyun * Which character status flags should we ignore?
312*4882a593Smuzhiyun */
313*4882a593Smuzhiyun port->ignore_status_mask = 0;
314*4882a593Smuzhiyun if (termios->c_iflag & IGNPAR)
315*4882a593Smuzhiyun port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
316*4882a593Smuzhiyun if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
317*4882a593Smuzhiyun port->ignore_status_mask |= RXSTAT_OVERRUN;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /*
320*4882a593Smuzhiyun * Ignore all characters if CREAD is not set.
321*4882a593Smuzhiyun */
322*4882a593Smuzhiyun if ((termios->c_cflag & CREAD) == 0)
323*4882a593Smuzhiyun port->ignore_status_mask |= RXSTAT_DUMMY_READ;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun quot -= 1;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun *CSR_UARTCON = 0;
328*4882a593Smuzhiyun *CSR_L_UBRLCR = quot & 0xff;
329*4882a593Smuzhiyun *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
330*4882a593Smuzhiyun *CSR_H_UBRLCR = h_lcr;
331*4882a593Smuzhiyun *CSR_UARTCON = 1;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
serial21285_type(struct uart_port * port)336*4882a593Smuzhiyun static const char *serial21285_type(struct uart_port *port)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun return port->type == PORT_21285 ? "DC21285" : NULL;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
serial21285_release_port(struct uart_port * port)341*4882a593Smuzhiyun static void serial21285_release_port(struct uart_port *port)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun release_mem_region(port->mapbase, 32);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
serial21285_request_port(struct uart_port * port)346*4882a593Smuzhiyun static int serial21285_request_port(struct uart_port *port)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun return request_mem_region(port->mapbase, 32, serial21285_name)
349*4882a593Smuzhiyun != NULL ? 0 : -EBUSY;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
serial21285_config_port(struct uart_port * port,int flags)352*4882a593Smuzhiyun static void serial21285_config_port(struct uart_port *port, int flags)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
355*4882a593Smuzhiyun port->type = PORT_21285;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun /*
359*4882a593Smuzhiyun * verify the new serial_struct (for TIOCSSERIAL).
360*4882a593Smuzhiyun */
serial21285_verify_port(struct uart_port * port,struct serial_struct * ser)361*4882a593Smuzhiyun static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun int ret = 0;
364*4882a593Smuzhiyun if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
365*4882a593Smuzhiyun ret = -EINVAL;
366*4882a593Smuzhiyun if (ser->irq <= 0)
367*4882a593Smuzhiyun ret = -EINVAL;
368*4882a593Smuzhiyun if (ser->baud_base != port->uartclk / 16)
369*4882a593Smuzhiyun ret = -EINVAL;
370*4882a593Smuzhiyun return ret;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun static const struct uart_ops serial21285_ops = {
374*4882a593Smuzhiyun .tx_empty = serial21285_tx_empty,
375*4882a593Smuzhiyun .get_mctrl = serial21285_get_mctrl,
376*4882a593Smuzhiyun .set_mctrl = serial21285_set_mctrl,
377*4882a593Smuzhiyun .stop_tx = serial21285_stop_tx,
378*4882a593Smuzhiyun .start_tx = serial21285_start_tx,
379*4882a593Smuzhiyun .stop_rx = serial21285_stop_rx,
380*4882a593Smuzhiyun .break_ctl = serial21285_break_ctl,
381*4882a593Smuzhiyun .startup = serial21285_startup,
382*4882a593Smuzhiyun .shutdown = serial21285_shutdown,
383*4882a593Smuzhiyun .set_termios = serial21285_set_termios,
384*4882a593Smuzhiyun .type = serial21285_type,
385*4882a593Smuzhiyun .release_port = serial21285_release_port,
386*4882a593Smuzhiyun .request_port = serial21285_request_port,
387*4882a593Smuzhiyun .config_port = serial21285_config_port,
388*4882a593Smuzhiyun .verify_port = serial21285_verify_port,
389*4882a593Smuzhiyun };
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun static struct uart_port serial21285_port = {
392*4882a593Smuzhiyun .mapbase = 0x42000160,
393*4882a593Smuzhiyun .iotype = UPIO_MEM,
394*4882a593Smuzhiyun .irq = 0,
395*4882a593Smuzhiyun .fifosize = 16,
396*4882a593Smuzhiyun .ops = &serial21285_ops,
397*4882a593Smuzhiyun .flags = UPF_BOOT_AUTOCONF,
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun
serial21285_setup_ports(void)400*4882a593Smuzhiyun static void serial21285_setup_ports(void)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun serial21285_port.uartclk = mem_fclk_21285 / 4;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_21285_CONSOLE
serial21285_console_putchar(struct uart_port * port,int ch)406*4882a593Smuzhiyun static void serial21285_console_putchar(struct uart_port *port, int ch)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun while (*CSR_UARTFLG & 0x20)
409*4882a593Smuzhiyun barrier();
410*4882a593Smuzhiyun *CSR_UARTDR = ch;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun static void
serial21285_console_write(struct console * co,const char * s,unsigned int count)414*4882a593Smuzhiyun serial21285_console_write(struct console *co, const char *s,
415*4882a593Smuzhiyun unsigned int count)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun uart_console_write(&serial21285_port, s, count, serial21285_console_putchar);
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun static void __init
serial21285_get_options(struct uart_port * port,int * baud,int * parity,int * bits)421*4882a593Smuzhiyun serial21285_get_options(struct uart_port *port, int *baud,
422*4882a593Smuzhiyun int *parity, int *bits)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun if (*CSR_UARTCON == 1) {
425*4882a593Smuzhiyun unsigned int tmp;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun tmp = *CSR_H_UBRLCR;
428*4882a593Smuzhiyun switch (tmp & 0x60) {
429*4882a593Smuzhiyun case 0x00:
430*4882a593Smuzhiyun *bits = 5;
431*4882a593Smuzhiyun break;
432*4882a593Smuzhiyun case 0x20:
433*4882a593Smuzhiyun *bits = 6;
434*4882a593Smuzhiyun break;
435*4882a593Smuzhiyun case 0x40:
436*4882a593Smuzhiyun *bits = 7;
437*4882a593Smuzhiyun break;
438*4882a593Smuzhiyun default:
439*4882a593Smuzhiyun case 0x60:
440*4882a593Smuzhiyun *bits = 8;
441*4882a593Smuzhiyun break;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (tmp & H_UBRLCR_PARENB) {
445*4882a593Smuzhiyun *parity = 'o';
446*4882a593Smuzhiyun if (tmp & H_UBRLCR_PAREVN)
447*4882a593Smuzhiyun *parity = 'e';
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun *baud = port->uartclk / (16 * (tmp + 1));
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
serial21285_console_setup(struct console * co,char * options)456*4882a593Smuzhiyun static int __init serial21285_console_setup(struct console *co, char *options)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun struct uart_port *port = &serial21285_port;
459*4882a593Smuzhiyun int baud = 9600;
460*4882a593Smuzhiyun int bits = 8;
461*4882a593Smuzhiyun int parity = 'n';
462*4882a593Smuzhiyun int flow = 'n';
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if (machine_is_personal_server())
465*4882a593Smuzhiyun baud = 57600;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /*
468*4882a593Smuzhiyun * Check whether an invalid uart number has been specified, and
469*4882a593Smuzhiyun * if so, search for the first available port that does have
470*4882a593Smuzhiyun * console support.
471*4882a593Smuzhiyun */
472*4882a593Smuzhiyun if (options)
473*4882a593Smuzhiyun uart_parse_options(options, &baud, &parity, &bits, &flow);
474*4882a593Smuzhiyun else
475*4882a593Smuzhiyun serial21285_get_options(port, &baud, &parity, &bits);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun return uart_set_options(port, co, baud, parity, bits, flow);
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun static struct uart_driver serial21285_reg;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun static struct console serial21285_console =
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun .name = SERIAL_21285_NAME,
485*4882a593Smuzhiyun .write = serial21285_console_write,
486*4882a593Smuzhiyun .device = uart_console_device,
487*4882a593Smuzhiyun .setup = serial21285_console_setup,
488*4882a593Smuzhiyun .flags = CON_PRINTBUFFER,
489*4882a593Smuzhiyun .index = -1,
490*4882a593Smuzhiyun .data = &serial21285_reg,
491*4882a593Smuzhiyun };
492*4882a593Smuzhiyun
rs285_console_init(void)493*4882a593Smuzhiyun static int __init rs285_console_init(void)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun serial21285_setup_ports();
496*4882a593Smuzhiyun register_console(&serial21285_console);
497*4882a593Smuzhiyun return 0;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun console_initcall(rs285_console_init);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun #define SERIAL_21285_CONSOLE &serial21285_console
502*4882a593Smuzhiyun #else
503*4882a593Smuzhiyun #define SERIAL_21285_CONSOLE NULL
504*4882a593Smuzhiyun #endif
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun static struct uart_driver serial21285_reg = {
507*4882a593Smuzhiyun .owner = THIS_MODULE,
508*4882a593Smuzhiyun .driver_name = "ttyFB",
509*4882a593Smuzhiyun .dev_name = "ttyFB",
510*4882a593Smuzhiyun .major = SERIAL_21285_MAJOR,
511*4882a593Smuzhiyun .minor = SERIAL_21285_MINOR,
512*4882a593Smuzhiyun .nr = 1,
513*4882a593Smuzhiyun .cons = SERIAL_21285_CONSOLE,
514*4882a593Smuzhiyun };
515*4882a593Smuzhiyun
serial21285_init(void)516*4882a593Smuzhiyun static int __init serial21285_init(void)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun int ret;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun printk(KERN_INFO "Serial: 21285 driver\n");
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun serial21285_setup_ports();
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun ret = uart_register_driver(&serial21285_reg);
525*4882a593Smuzhiyun if (ret == 0)
526*4882a593Smuzhiyun uart_add_one_port(&serial21285_reg, &serial21285_port);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun return ret;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
serial21285_exit(void)531*4882a593Smuzhiyun static void __exit serial21285_exit(void)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun uart_remove_one_port(&serial21285_reg, &serial21285_port);
534*4882a593Smuzhiyun uart_unregister_driver(&serial21285_reg);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun module_init(serial21285_init);
538*4882a593Smuzhiyun module_exit(serial21285_exit);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun MODULE_LICENSE("GPL");
541*4882a593Smuzhiyun MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
542*4882a593Smuzhiyun MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
543