1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for NEC VR4100 series Serial Interface Unit.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2004-2008 Yoichi Yuasa <yuasa@linux-mips.org>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Based on drivers/serial/8250.c, by Russell King.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/console.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/interrupt.h>
14*4882a593Smuzhiyun #include <linux/ioport.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/serial.h>
18*4882a593Smuzhiyun #include <linux/serial_core.h>
19*4882a593Smuzhiyun #include <linux/serial_reg.h>
20*4882a593Smuzhiyun #include <linux/tty.h>
21*4882a593Smuzhiyun #include <linux/tty_flip.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <asm/io.h>
24*4882a593Smuzhiyun #include <asm/vr41xx/siu.h>
25*4882a593Smuzhiyun #include <asm/vr41xx/vr41xx.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define SIU_BAUD_BASE 1152000
28*4882a593Smuzhiyun #define SIU_MAJOR 204
29*4882a593Smuzhiyun #define SIU_MINOR_BASE 82
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define RX_MAX_COUNT 256
32*4882a593Smuzhiyun #define TX_MAX_COUNT 15
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #define SIUIRSEL 0x08
35*4882a593Smuzhiyun #define TMICMODE 0x20
36*4882a593Smuzhiyun #define TMICTX 0x10
37*4882a593Smuzhiyun #define IRMSEL 0x0c
38*4882a593Smuzhiyun #define IRMSEL_HP 0x08
39*4882a593Smuzhiyun #define IRMSEL_TEMIC 0x04
40*4882a593Smuzhiyun #define IRMSEL_SHARP 0x00
41*4882a593Smuzhiyun #define IRUSESEL 0x02
42*4882a593Smuzhiyun #define SIRSEL 0x01
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
45*4882a593Smuzhiyun [0 ... SIU_PORTS_MAX-1] = {
46*4882a593Smuzhiyun .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
47*4882a593Smuzhiyun .irq = 0,
48*4882a593Smuzhiyun },
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_VR41XX_CONSOLE
52*4882a593Smuzhiyun static uint8_t lsr_break_flag[SIU_PORTS_MAX];
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #define siu_read(port, offset) readb((port)->membase + (offset))
56*4882a593Smuzhiyun #define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
57*4882a593Smuzhiyun
vr41xx_select_siu_interface(siu_interface_t interface)58*4882a593Smuzhiyun void vr41xx_select_siu_interface(siu_interface_t interface)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun struct uart_port *port;
61*4882a593Smuzhiyun unsigned long flags;
62*4882a593Smuzhiyun uint8_t irsel;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun port = &siu_uart_ports[0];
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun irsel = siu_read(port, SIUIRSEL);
69*4882a593Smuzhiyun if (interface == SIU_INTERFACE_IRDA)
70*4882a593Smuzhiyun irsel |= SIRSEL;
71*4882a593Smuzhiyun else
72*4882a593Smuzhiyun irsel &= ~SIRSEL;
73*4882a593Smuzhiyun siu_write(port, SIUIRSEL, irsel);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
78*4882a593Smuzhiyun
vr41xx_use_irda(irda_use_t use)79*4882a593Smuzhiyun void vr41xx_use_irda(irda_use_t use)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun struct uart_port *port;
82*4882a593Smuzhiyun unsigned long flags;
83*4882a593Smuzhiyun uint8_t irsel;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun port = &siu_uart_ports[0];
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun irsel = siu_read(port, SIUIRSEL);
90*4882a593Smuzhiyun if (use == FIR_USE_IRDA)
91*4882a593Smuzhiyun irsel |= IRUSESEL;
92*4882a593Smuzhiyun else
93*4882a593Smuzhiyun irsel &= ~IRUSESEL;
94*4882a593Smuzhiyun siu_write(port, SIUIRSEL, irsel);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(vr41xx_use_irda);
99*4882a593Smuzhiyun
vr41xx_select_irda_module(irda_module_t module,irda_speed_t speed)100*4882a593Smuzhiyun void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun struct uart_port *port;
103*4882a593Smuzhiyun unsigned long flags;
104*4882a593Smuzhiyun uint8_t irsel;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun port = &siu_uart_ports[0];
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun irsel = siu_read(port, SIUIRSEL);
111*4882a593Smuzhiyun irsel &= ~(IRMSEL | TMICTX | TMICMODE);
112*4882a593Smuzhiyun switch (module) {
113*4882a593Smuzhiyun case SHARP_IRDA:
114*4882a593Smuzhiyun irsel |= IRMSEL_SHARP;
115*4882a593Smuzhiyun break;
116*4882a593Smuzhiyun case TEMIC_IRDA:
117*4882a593Smuzhiyun irsel |= IRMSEL_TEMIC | TMICMODE;
118*4882a593Smuzhiyun if (speed == IRDA_TX_4MBPS)
119*4882a593Smuzhiyun irsel |= TMICTX;
120*4882a593Smuzhiyun break;
121*4882a593Smuzhiyun case HP_IRDA:
122*4882a593Smuzhiyun irsel |= IRMSEL_HP;
123*4882a593Smuzhiyun break;
124*4882a593Smuzhiyun default:
125*4882a593Smuzhiyun break;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun siu_write(port, SIUIRSEL, irsel);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
132*4882a593Smuzhiyun
siu_clear_fifo(struct uart_port * port)133*4882a593Smuzhiyun static inline void siu_clear_fifo(struct uart_port *port)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO);
136*4882a593Smuzhiyun siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
137*4882a593Smuzhiyun UART_FCR_CLEAR_XMIT);
138*4882a593Smuzhiyun siu_write(port, UART_FCR, 0);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
siu_port_size(struct uart_port * port)141*4882a593Smuzhiyun static inline unsigned long siu_port_size(struct uart_port *port)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun switch (port->type) {
144*4882a593Smuzhiyun case PORT_VR41XX_SIU:
145*4882a593Smuzhiyun return 11UL;
146*4882a593Smuzhiyun case PORT_VR41XX_DSIU:
147*4882a593Smuzhiyun return 8UL;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return 0;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
siu_check_type(struct uart_port * port)153*4882a593Smuzhiyun static inline unsigned int siu_check_type(struct uart_port *port)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun if (port->line == 0)
156*4882a593Smuzhiyun return PORT_VR41XX_SIU;
157*4882a593Smuzhiyun if (port->line == 1 && port->irq)
158*4882a593Smuzhiyun return PORT_VR41XX_DSIU;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return PORT_UNKNOWN;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
siu_type_name(struct uart_port * port)163*4882a593Smuzhiyun static inline const char *siu_type_name(struct uart_port *port)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun switch (port->type) {
166*4882a593Smuzhiyun case PORT_VR41XX_SIU:
167*4882a593Smuzhiyun return "SIU";
168*4882a593Smuzhiyun case PORT_VR41XX_DSIU:
169*4882a593Smuzhiyun return "DSIU";
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return NULL;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
siu_tx_empty(struct uart_port * port)175*4882a593Smuzhiyun static unsigned int siu_tx_empty(struct uart_port *port)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun uint8_t lsr;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun lsr = siu_read(port, UART_LSR);
180*4882a593Smuzhiyun if (lsr & UART_LSR_TEMT)
181*4882a593Smuzhiyun return TIOCSER_TEMT;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun return 0;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
siu_set_mctrl(struct uart_port * port,unsigned int mctrl)186*4882a593Smuzhiyun static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun uint8_t mcr = 0;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun if (mctrl & TIOCM_DTR)
191*4882a593Smuzhiyun mcr |= UART_MCR_DTR;
192*4882a593Smuzhiyun if (mctrl & TIOCM_RTS)
193*4882a593Smuzhiyun mcr |= UART_MCR_RTS;
194*4882a593Smuzhiyun if (mctrl & TIOCM_OUT1)
195*4882a593Smuzhiyun mcr |= UART_MCR_OUT1;
196*4882a593Smuzhiyun if (mctrl & TIOCM_OUT2)
197*4882a593Smuzhiyun mcr |= UART_MCR_OUT2;
198*4882a593Smuzhiyun if (mctrl & TIOCM_LOOP)
199*4882a593Smuzhiyun mcr |= UART_MCR_LOOP;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun siu_write(port, UART_MCR, mcr);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
siu_get_mctrl(struct uart_port * port)204*4882a593Smuzhiyun static unsigned int siu_get_mctrl(struct uart_port *port)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun uint8_t msr;
207*4882a593Smuzhiyun unsigned int mctrl = 0;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun msr = siu_read(port, UART_MSR);
210*4882a593Smuzhiyun if (msr & UART_MSR_DCD)
211*4882a593Smuzhiyun mctrl |= TIOCM_CAR;
212*4882a593Smuzhiyun if (msr & UART_MSR_RI)
213*4882a593Smuzhiyun mctrl |= TIOCM_RNG;
214*4882a593Smuzhiyun if (msr & UART_MSR_DSR)
215*4882a593Smuzhiyun mctrl |= TIOCM_DSR;
216*4882a593Smuzhiyun if (msr & UART_MSR_CTS)
217*4882a593Smuzhiyun mctrl |= TIOCM_CTS;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun return mctrl;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
siu_stop_tx(struct uart_port * port)222*4882a593Smuzhiyun static void siu_stop_tx(struct uart_port *port)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun unsigned long flags;
225*4882a593Smuzhiyun uint8_t ier;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun ier = siu_read(port, UART_IER);
230*4882a593Smuzhiyun ier &= ~UART_IER_THRI;
231*4882a593Smuzhiyun siu_write(port, UART_IER, ier);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
siu_start_tx(struct uart_port * port)236*4882a593Smuzhiyun static void siu_start_tx(struct uart_port *port)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun unsigned long flags;
239*4882a593Smuzhiyun uint8_t ier;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun ier = siu_read(port, UART_IER);
244*4882a593Smuzhiyun ier |= UART_IER_THRI;
245*4882a593Smuzhiyun siu_write(port, UART_IER, ier);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
siu_stop_rx(struct uart_port * port)250*4882a593Smuzhiyun static void siu_stop_rx(struct uart_port *port)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun unsigned long flags;
253*4882a593Smuzhiyun uint8_t ier;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun ier = siu_read(port, UART_IER);
258*4882a593Smuzhiyun ier &= ~UART_IER_RLSI;
259*4882a593Smuzhiyun siu_write(port, UART_IER, ier);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun port->read_status_mask &= ~UART_LSR_DR;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
siu_enable_ms(struct uart_port * port)266*4882a593Smuzhiyun static void siu_enable_ms(struct uart_port *port)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun unsigned long flags;
269*4882a593Smuzhiyun uint8_t ier;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun ier = siu_read(port, UART_IER);
274*4882a593Smuzhiyun ier |= UART_IER_MSI;
275*4882a593Smuzhiyun siu_write(port, UART_IER, ier);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
siu_break_ctl(struct uart_port * port,int ctl)280*4882a593Smuzhiyun static void siu_break_ctl(struct uart_port *port, int ctl)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun unsigned long flags;
283*4882a593Smuzhiyun uint8_t lcr;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun lcr = siu_read(port, UART_LCR);
288*4882a593Smuzhiyun if (ctl == -1)
289*4882a593Smuzhiyun lcr |= UART_LCR_SBC;
290*4882a593Smuzhiyun else
291*4882a593Smuzhiyun lcr &= ~UART_LCR_SBC;
292*4882a593Smuzhiyun siu_write(port, UART_LCR, lcr);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
receive_chars(struct uart_port * port,uint8_t * status)297*4882a593Smuzhiyun static inline void receive_chars(struct uart_port *port, uint8_t *status)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun uint8_t lsr, ch;
300*4882a593Smuzhiyun char flag;
301*4882a593Smuzhiyun int max_count = RX_MAX_COUNT;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun lsr = *status;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun do {
306*4882a593Smuzhiyun ch = siu_read(port, UART_RX);
307*4882a593Smuzhiyun port->icount.rx++;
308*4882a593Smuzhiyun flag = TTY_NORMAL;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_VR41XX_CONSOLE
311*4882a593Smuzhiyun lsr |= lsr_break_flag[port->line];
312*4882a593Smuzhiyun lsr_break_flag[port->line] = 0;
313*4882a593Smuzhiyun #endif
314*4882a593Smuzhiyun if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE |
315*4882a593Smuzhiyun UART_LSR_PE | UART_LSR_OE))) {
316*4882a593Smuzhiyun if (lsr & UART_LSR_BI) {
317*4882a593Smuzhiyun lsr &= ~(UART_LSR_FE | UART_LSR_PE);
318*4882a593Smuzhiyun port->icount.brk++;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (uart_handle_break(port))
321*4882a593Smuzhiyun goto ignore_char;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun if (lsr & UART_LSR_FE)
325*4882a593Smuzhiyun port->icount.frame++;
326*4882a593Smuzhiyun if (lsr & UART_LSR_PE)
327*4882a593Smuzhiyun port->icount.parity++;
328*4882a593Smuzhiyun if (lsr & UART_LSR_OE)
329*4882a593Smuzhiyun port->icount.overrun++;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun lsr &= port->read_status_mask;
332*4882a593Smuzhiyun if (lsr & UART_LSR_BI)
333*4882a593Smuzhiyun flag = TTY_BREAK;
334*4882a593Smuzhiyun if (lsr & UART_LSR_FE)
335*4882a593Smuzhiyun flag = TTY_FRAME;
336*4882a593Smuzhiyun if (lsr & UART_LSR_PE)
337*4882a593Smuzhiyun flag = TTY_PARITY;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (uart_handle_sysrq_char(port, ch))
341*4882a593Smuzhiyun goto ignore_char;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun ignore_char:
346*4882a593Smuzhiyun lsr = siu_read(port, UART_LSR);
347*4882a593Smuzhiyun } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun tty_flip_buffer_push(&port->state->port);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun *status = lsr;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
check_modem_status(struct uart_port * port)354*4882a593Smuzhiyun static inline void check_modem_status(struct uart_port *port)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun uint8_t msr;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun msr = siu_read(port, UART_MSR);
359*4882a593Smuzhiyun if ((msr & UART_MSR_ANY_DELTA) == 0)
360*4882a593Smuzhiyun return;
361*4882a593Smuzhiyun if (msr & UART_MSR_DDCD)
362*4882a593Smuzhiyun uart_handle_dcd_change(port, msr & UART_MSR_DCD);
363*4882a593Smuzhiyun if (msr & UART_MSR_TERI)
364*4882a593Smuzhiyun port->icount.rng++;
365*4882a593Smuzhiyun if (msr & UART_MSR_DDSR)
366*4882a593Smuzhiyun port->icount.dsr++;
367*4882a593Smuzhiyun if (msr & UART_MSR_DCTS)
368*4882a593Smuzhiyun uart_handle_cts_change(port, msr & UART_MSR_CTS);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun wake_up_interruptible(&port->state->port.delta_msr_wait);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
transmit_chars(struct uart_port * port)373*4882a593Smuzhiyun static inline void transmit_chars(struct uart_port *port)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun struct circ_buf *xmit;
376*4882a593Smuzhiyun int max_count = TX_MAX_COUNT;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun xmit = &port->state->xmit;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (port->x_char) {
381*4882a593Smuzhiyun siu_write(port, UART_TX, port->x_char);
382*4882a593Smuzhiyun port->icount.tx++;
383*4882a593Smuzhiyun port->x_char = 0;
384*4882a593Smuzhiyun return;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
388*4882a593Smuzhiyun siu_stop_tx(port);
389*4882a593Smuzhiyun return;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun do {
393*4882a593Smuzhiyun siu_write(port, UART_TX, xmit->buf[xmit->tail]);
394*4882a593Smuzhiyun xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
395*4882a593Smuzhiyun port->icount.tx++;
396*4882a593Smuzhiyun if (uart_circ_empty(xmit))
397*4882a593Smuzhiyun break;
398*4882a593Smuzhiyun } while (max_count-- > 0);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
401*4882a593Smuzhiyun uart_write_wakeup(port);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun if (uart_circ_empty(xmit))
404*4882a593Smuzhiyun siu_stop_tx(port);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
siu_interrupt(int irq,void * dev_id)407*4882a593Smuzhiyun static irqreturn_t siu_interrupt(int irq, void *dev_id)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun struct uart_port *port;
410*4882a593Smuzhiyun uint8_t iir, lsr;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun port = (struct uart_port *)dev_id;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun iir = siu_read(port, UART_IIR);
415*4882a593Smuzhiyun if (iir & UART_IIR_NO_INT)
416*4882a593Smuzhiyun return IRQ_NONE;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun lsr = siu_read(port, UART_LSR);
419*4882a593Smuzhiyun if (lsr & UART_LSR_DR)
420*4882a593Smuzhiyun receive_chars(port, &lsr);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun check_modem_status(port);
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun if (lsr & UART_LSR_THRE)
425*4882a593Smuzhiyun transmit_chars(port);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun return IRQ_HANDLED;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
siu_startup(struct uart_port * port)430*4882a593Smuzhiyun static int siu_startup(struct uart_port *port)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun int retval;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun if (port->membase == NULL)
435*4882a593Smuzhiyun return -ENODEV;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun siu_clear_fifo(port);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun (void)siu_read(port, UART_LSR);
440*4882a593Smuzhiyun (void)siu_read(port, UART_RX);
441*4882a593Smuzhiyun (void)siu_read(port, UART_IIR);
442*4882a593Smuzhiyun (void)siu_read(port, UART_MSR);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (siu_read(port, UART_LSR) == 0xff)
445*4882a593Smuzhiyun return -ENODEV;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port);
448*4882a593Smuzhiyun if (retval)
449*4882a593Smuzhiyun return retval;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (port->type == PORT_VR41XX_DSIU)
452*4882a593Smuzhiyun vr41xx_enable_dsiuint(DSIUINT_ALL);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun siu_write(port, UART_LCR, UART_LCR_WLEN8);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun spin_lock_irq(&port->lock);
457*4882a593Smuzhiyun siu_set_mctrl(port, port->mctrl);
458*4882a593Smuzhiyun spin_unlock_irq(&port->lock);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun (void)siu_read(port, UART_LSR);
463*4882a593Smuzhiyun (void)siu_read(port, UART_RX);
464*4882a593Smuzhiyun (void)siu_read(port, UART_IIR);
465*4882a593Smuzhiyun (void)siu_read(port, UART_MSR);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun return 0;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
siu_shutdown(struct uart_port * port)470*4882a593Smuzhiyun static void siu_shutdown(struct uart_port *port)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun unsigned long flags;
473*4882a593Smuzhiyun uint8_t lcr;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun siu_write(port, UART_IER, 0);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun port->mctrl &= ~TIOCM_OUT2;
480*4882a593Smuzhiyun siu_set_mctrl(port, port->mctrl);
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun lcr = siu_read(port, UART_LCR);
485*4882a593Smuzhiyun lcr &= ~UART_LCR_SBC;
486*4882a593Smuzhiyun siu_write(port, UART_LCR, lcr);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun siu_clear_fifo(port);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun (void)siu_read(port, UART_RX);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun if (port->type == PORT_VR41XX_DSIU)
493*4882a593Smuzhiyun vr41xx_disable_dsiuint(DSIUINT_ALL);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun free_irq(port->irq, port);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
siu_set_termios(struct uart_port * port,struct ktermios * new,struct ktermios * old)498*4882a593Smuzhiyun static void siu_set_termios(struct uart_port *port, struct ktermios *new,
499*4882a593Smuzhiyun struct ktermios *old)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun tcflag_t c_cflag, c_iflag;
502*4882a593Smuzhiyun uint8_t lcr, fcr, ier;
503*4882a593Smuzhiyun unsigned int baud, quot;
504*4882a593Smuzhiyun unsigned long flags;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun c_cflag = new->c_cflag;
507*4882a593Smuzhiyun switch (c_cflag & CSIZE) {
508*4882a593Smuzhiyun case CS5:
509*4882a593Smuzhiyun lcr = UART_LCR_WLEN5;
510*4882a593Smuzhiyun break;
511*4882a593Smuzhiyun case CS6:
512*4882a593Smuzhiyun lcr = UART_LCR_WLEN6;
513*4882a593Smuzhiyun break;
514*4882a593Smuzhiyun case CS7:
515*4882a593Smuzhiyun lcr = UART_LCR_WLEN7;
516*4882a593Smuzhiyun break;
517*4882a593Smuzhiyun default:
518*4882a593Smuzhiyun lcr = UART_LCR_WLEN8;
519*4882a593Smuzhiyun break;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun if (c_cflag & CSTOPB)
523*4882a593Smuzhiyun lcr |= UART_LCR_STOP;
524*4882a593Smuzhiyun if (c_cflag & PARENB)
525*4882a593Smuzhiyun lcr |= UART_LCR_PARITY;
526*4882a593Smuzhiyun if ((c_cflag & PARODD) != PARODD)
527*4882a593Smuzhiyun lcr |= UART_LCR_EPAR;
528*4882a593Smuzhiyun if (c_cflag & CMSPAR)
529*4882a593Smuzhiyun lcr |= UART_LCR_SPAR;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
532*4882a593Smuzhiyun quot = uart_get_divisor(port, baud);
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun uart_update_timeout(port, c_cflag, baud);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun c_iflag = new->c_iflag;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
543*4882a593Smuzhiyun if (c_iflag & INPCK)
544*4882a593Smuzhiyun port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
545*4882a593Smuzhiyun if (c_iflag & (IGNBRK | BRKINT | PARMRK))
546*4882a593Smuzhiyun port->read_status_mask |= UART_LSR_BI;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun port->ignore_status_mask = 0;
549*4882a593Smuzhiyun if (c_iflag & IGNPAR)
550*4882a593Smuzhiyun port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
551*4882a593Smuzhiyun if (c_iflag & IGNBRK) {
552*4882a593Smuzhiyun port->ignore_status_mask |= UART_LSR_BI;
553*4882a593Smuzhiyun if (c_iflag & IGNPAR)
554*4882a593Smuzhiyun port->ignore_status_mask |= UART_LSR_OE;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun if ((c_cflag & CREAD) == 0)
558*4882a593Smuzhiyun port->ignore_status_mask |= UART_LSR_DR;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun ier = siu_read(port, UART_IER);
561*4882a593Smuzhiyun ier &= ~UART_IER_MSI;
562*4882a593Smuzhiyun if (UART_ENABLE_MS(port, c_cflag))
563*4882a593Smuzhiyun ier |= UART_IER_MSI;
564*4882a593Smuzhiyun siu_write(port, UART_IER, ier);
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun siu_write(port, UART_DLL, (uint8_t)quot);
569*4882a593Smuzhiyun siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun siu_write(port, UART_LCR, lcr);
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun siu_write(port, UART_FCR, fcr);
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun siu_set_mctrl(port, port->mctrl);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
siu_pm(struct uart_port * port,unsigned int state,unsigned int oldstate)580*4882a593Smuzhiyun static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun switch (state) {
583*4882a593Smuzhiyun case 0:
584*4882a593Smuzhiyun switch (port->type) {
585*4882a593Smuzhiyun case PORT_VR41XX_SIU:
586*4882a593Smuzhiyun vr41xx_supply_clock(SIU_CLOCK);
587*4882a593Smuzhiyun break;
588*4882a593Smuzhiyun case PORT_VR41XX_DSIU:
589*4882a593Smuzhiyun vr41xx_supply_clock(DSIU_CLOCK);
590*4882a593Smuzhiyun break;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun break;
593*4882a593Smuzhiyun case 3:
594*4882a593Smuzhiyun switch (port->type) {
595*4882a593Smuzhiyun case PORT_VR41XX_SIU:
596*4882a593Smuzhiyun vr41xx_mask_clock(SIU_CLOCK);
597*4882a593Smuzhiyun break;
598*4882a593Smuzhiyun case PORT_VR41XX_DSIU:
599*4882a593Smuzhiyun vr41xx_mask_clock(DSIU_CLOCK);
600*4882a593Smuzhiyun break;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun break;
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun
siu_type(struct uart_port * port)606*4882a593Smuzhiyun static const char *siu_type(struct uart_port *port)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun return siu_type_name(port);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
siu_release_port(struct uart_port * port)611*4882a593Smuzhiyun static void siu_release_port(struct uart_port *port)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun unsigned long size;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun if (port->flags & UPF_IOREMAP) {
616*4882a593Smuzhiyun iounmap(port->membase);
617*4882a593Smuzhiyun port->membase = NULL;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun size = siu_port_size(port);
621*4882a593Smuzhiyun release_mem_region(port->mapbase, size);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
siu_request_port(struct uart_port * port)624*4882a593Smuzhiyun static int siu_request_port(struct uart_port *port)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun unsigned long size;
627*4882a593Smuzhiyun struct resource *res;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun size = siu_port_size(port);
630*4882a593Smuzhiyun res = request_mem_region(port->mapbase, size, siu_type_name(port));
631*4882a593Smuzhiyun if (res == NULL)
632*4882a593Smuzhiyun return -EBUSY;
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun if (port->flags & UPF_IOREMAP) {
635*4882a593Smuzhiyun port->membase = ioremap(port->mapbase, size);
636*4882a593Smuzhiyun if (port->membase == NULL) {
637*4882a593Smuzhiyun release_resource(res);
638*4882a593Smuzhiyun return -ENOMEM;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun return 0;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
siu_config_port(struct uart_port * port,int flags)645*4882a593Smuzhiyun static void siu_config_port(struct uart_port *port, int flags)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun if (flags & UART_CONFIG_TYPE) {
648*4882a593Smuzhiyun port->type = siu_check_type(port);
649*4882a593Smuzhiyun (void)siu_request_port(port);
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
siu_verify_port(struct uart_port * port,struct serial_struct * serial)653*4882a593Smuzhiyun static int siu_verify_port(struct uart_port *port, struct serial_struct *serial)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)
656*4882a593Smuzhiyun return -EINVAL;
657*4882a593Smuzhiyun if (port->irq != serial->irq)
658*4882a593Smuzhiyun return -EINVAL;
659*4882a593Smuzhiyun if (port->iotype != serial->io_type)
660*4882a593Smuzhiyun return -EINVAL;
661*4882a593Smuzhiyun if (port->mapbase != (unsigned long)serial->iomem_base)
662*4882a593Smuzhiyun return -EINVAL;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun return 0;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun static const struct uart_ops siu_uart_ops = {
668*4882a593Smuzhiyun .tx_empty = siu_tx_empty,
669*4882a593Smuzhiyun .set_mctrl = siu_set_mctrl,
670*4882a593Smuzhiyun .get_mctrl = siu_get_mctrl,
671*4882a593Smuzhiyun .stop_tx = siu_stop_tx,
672*4882a593Smuzhiyun .start_tx = siu_start_tx,
673*4882a593Smuzhiyun .stop_rx = siu_stop_rx,
674*4882a593Smuzhiyun .enable_ms = siu_enable_ms,
675*4882a593Smuzhiyun .break_ctl = siu_break_ctl,
676*4882a593Smuzhiyun .startup = siu_startup,
677*4882a593Smuzhiyun .shutdown = siu_shutdown,
678*4882a593Smuzhiyun .set_termios = siu_set_termios,
679*4882a593Smuzhiyun .pm = siu_pm,
680*4882a593Smuzhiyun .type = siu_type,
681*4882a593Smuzhiyun .release_port = siu_release_port,
682*4882a593Smuzhiyun .request_port = siu_request_port,
683*4882a593Smuzhiyun .config_port = siu_config_port,
684*4882a593Smuzhiyun .verify_port = siu_verify_port,
685*4882a593Smuzhiyun };
686*4882a593Smuzhiyun
siu_init_ports(struct platform_device * pdev)687*4882a593Smuzhiyun static int siu_init_ports(struct platform_device *pdev)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun struct uart_port *port;
690*4882a593Smuzhiyun struct resource *res;
691*4882a593Smuzhiyun int *type = dev_get_platdata(&pdev->dev);
692*4882a593Smuzhiyun int i;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun if (!type)
695*4882a593Smuzhiyun return 0;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun port = siu_uart_ports;
698*4882a593Smuzhiyun for (i = 0; i < SIU_PORTS_MAX; i++) {
699*4882a593Smuzhiyun port->type = type[i];
700*4882a593Smuzhiyun if (port->type == PORT_UNKNOWN)
701*4882a593Smuzhiyun continue;
702*4882a593Smuzhiyun port->irq = platform_get_irq(pdev, i);
703*4882a593Smuzhiyun port->uartclk = SIU_BAUD_BASE * 16;
704*4882a593Smuzhiyun port->fifosize = 16;
705*4882a593Smuzhiyun port->regshift = 0;
706*4882a593Smuzhiyun port->iotype = UPIO_MEM;
707*4882a593Smuzhiyun port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
708*4882a593Smuzhiyun port->line = i;
709*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, i);
710*4882a593Smuzhiyun port->mapbase = res->start;
711*4882a593Smuzhiyun port++;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun return i;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_VR41XX_CONSOLE
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
720*4882a593Smuzhiyun
wait_for_xmitr(struct uart_port * port)721*4882a593Smuzhiyun static void wait_for_xmitr(struct uart_port *port)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun int timeout = 10000;
724*4882a593Smuzhiyun uint8_t lsr, msr;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun do {
727*4882a593Smuzhiyun lsr = siu_read(port, UART_LSR);
728*4882a593Smuzhiyun if (lsr & UART_LSR_BI)
729*4882a593Smuzhiyun lsr_break_flag[port->line] = UART_LSR_BI;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)
732*4882a593Smuzhiyun break;
733*4882a593Smuzhiyun } while (timeout-- > 0);
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun if (port->flags & UPF_CONS_FLOW) {
736*4882a593Smuzhiyun timeout = 1000000;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun do {
739*4882a593Smuzhiyun msr = siu_read(port, UART_MSR);
740*4882a593Smuzhiyun if ((msr & UART_MSR_CTS) != 0)
741*4882a593Smuzhiyun break;
742*4882a593Smuzhiyun } while (timeout-- > 0);
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
siu_console_putchar(struct uart_port * port,int ch)746*4882a593Smuzhiyun static void siu_console_putchar(struct uart_port *port, int ch)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun wait_for_xmitr(port);
749*4882a593Smuzhiyun siu_write(port, UART_TX, ch);
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun
siu_console_write(struct console * con,const char * s,unsigned count)752*4882a593Smuzhiyun static void siu_console_write(struct console *con, const char *s, unsigned count)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun struct uart_port *port;
755*4882a593Smuzhiyun uint8_t ier;
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun port = &siu_uart_ports[con->index];
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun ier = siu_read(port, UART_IER);
760*4882a593Smuzhiyun siu_write(port, UART_IER, 0);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun uart_console_write(port, s, count, siu_console_putchar);
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun wait_for_xmitr(port);
765*4882a593Smuzhiyun siu_write(port, UART_IER, ier);
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
siu_console_setup(struct console * con,char * options)768*4882a593Smuzhiyun static int __init siu_console_setup(struct console *con, char *options)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun struct uart_port *port;
771*4882a593Smuzhiyun int baud = 9600;
772*4882a593Smuzhiyun int parity = 'n';
773*4882a593Smuzhiyun int bits = 8;
774*4882a593Smuzhiyun int flow = 'n';
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun if (con->index >= SIU_PORTS_MAX)
777*4882a593Smuzhiyun con->index = 0;
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun port = &siu_uart_ports[con->index];
780*4882a593Smuzhiyun if (port->membase == NULL) {
781*4882a593Smuzhiyun if (port->mapbase == 0)
782*4882a593Smuzhiyun return -ENODEV;
783*4882a593Smuzhiyun port->membase = ioremap(port->mapbase, siu_port_size(port));
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun if (port->type == PORT_VR41XX_SIU)
787*4882a593Smuzhiyun vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun if (options != NULL)
790*4882a593Smuzhiyun uart_parse_options(options, &baud, &parity, &bits, &flow);
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun return uart_set_options(port, con, baud, parity, bits, flow);
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun static struct uart_driver siu_uart_driver;
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun static struct console siu_console = {
798*4882a593Smuzhiyun .name = "ttyVR",
799*4882a593Smuzhiyun .write = siu_console_write,
800*4882a593Smuzhiyun .device = uart_console_device,
801*4882a593Smuzhiyun .setup = siu_console_setup,
802*4882a593Smuzhiyun .flags = CON_PRINTBUFFER,
803*4882a593Smuzhiyun .index = -1,
804*4882a593Smuzhiyun .data = &siu_uart_driver,
805*4882a593Smuzhiyun };
806*4882a593Smuzhiyun
siu_console_init(void)807*4882a593Smuzhiyun static int siu_console_init(void)
808*4882a593Smuzhiyun {
809*4882a593Smuzhiyun struct uart_port *port;
810*4882a593Smuzhiyun int i;
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun for (i = 0; i < SIU_PORTS_MAX; i++) {
813*4882a593Smuzhiyun port = &siu_uart_ports[i];
814*4882a593Smuzhiyun port->ops = &siu_uart_ops;
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun register_console(&siu_console);
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun return 0;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun console_initcall(siu_console_init);
823*4882a593Smuzhiyun
vr41xx_siu_early_setup(struct uart_port * port)824*4882a593Smuzhiyun void __init vr41xx_siu_early_setup(struct uart_port *port)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun if (port->type == PORT_UNKNOWN)
827*4882a593Smuzhiyun return;
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun siu_uart_ports[port->line].line = port->line;
830*4882a593Smuzhiyun siu_uart_ports[port->line].type = port->type;
831*4882a593Smuzhiyun siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
832*4882a593Smuzhiyun siu_uart_ports[port->line].mapbase = port->mapbase;
833*4882a593Smuzhiyun siu_uart_ports[port->line].ops = &siu_uart_ops;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun #define SERIAL_VR41XX_CONSOLE &siu_console
837*4882a593Smuzhiyun #else
838*4882a593Smuzhiyun #define SERIAL_VR41XX_CONSOLE NULL
839*4882a593Smuzhiyun #endif
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun static struct uart_driver siu_uart_driver = {
842*4882a593Smuzhiyun .owner = THIS_MODULE,
843*4882a593Smuzhiyun .driver_name = "SIU",
844*4882a593Smuzhiyun .dev_name = "ttyVR",
845*4882a593Smuzhiyun .major = SIU_MAJOR,
846*4882a593Smuzhiyun .minor = SIU_MINOR_BASE,
847*4882a593Smuzhiyun .cons = SERIAL_VR41XX_CONSOLE,
848*4882a593Smuzhiyun };
849*4882a593Smuzhiyun
siu_probe(struct platform_device * dev)850*4882a593Smuzhiyun static int siu_probe(struct platform_device *dev)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun struct uart_port *port;
853*4882a593Smuzhiyun int num, i, retval;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun num = siu_init_ports(dev);
856*4882a593Smuzhiyun if (num <= 0)
857*4882a593Smuzhiyun return -ENODEV;
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun siu_uart_driver.nr = num;
860*4882a593Smuzhiyun retval = uart_register_driver(&siu_uart_driver);
861*4882a593Smuzhiyun if (retval)
862*4882a593Smuzhiyun return retval;
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun for (i = 0; i < num; i++) {
865*4882a593Smuzhiyun port = &siu_uart_ports[i];
866*4882a593Smuzhiyun port->ops = &siu_uart_ops;
867*4882a593Smuzhiyun port->dev = &dev->dev;
868*4882a593Smuzhiyun port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_VR41XX_CONSOLE);
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun retval = uart_add_one_port(&siu_uart_driver, port);
871*4882a593Smuzhiyun if (retval < 0) {
872*4882a593Smuzhiyun port->dev = NULL;
873*4882a593Smuzhiyun break;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun if (i == 0 && retval < 0) {
878*4882a593Smuzhiyun uart_unregister_driver(&siu_uart_driver);
879*4882a593Smuzhiyun return retval;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun return 0;
883*4882a593Smuzhiyun }
884*4882a593Smuzhiyun
siu_remove(struct platform_device * dev)885*4882a593Smuzhiyun static int siu_remove(struct platform_device *dev)
886*4882a593Smuzhiyun {
887*4882a593Smuzhiyun struct uart_port *port;
888*4882a593Smuzhiyun int i;
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun for (i = 0; i < siu_uart_driver.nr; i++) {
891*4882a593Smuzhiyun port = &siu_uart_ports[i];
892*4882a593Smuzhiyun if (port->dev == &dev->dev) {
893*4882a593Smuzhiyun uart_remove_one_port(&siu_uart_driver, port);
894*4882a593Smuzhiyun port->dev = NULL;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun uart_unregister_driver(&siu_uart_driver);
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun return 0;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun
siu_suspend(struct platform_device * dev,pm_message_t state)903*4882a593Smuzhiyun static int siu_suspend(struct platform_device *dev, pm_message_t state)
904*4882a593Smuzhiyun {
905*4882a593Smuzhiyun struct uart_port *port;
906*4882a593Smuzhiyun int i;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun for (i = 0; i < siu_uart_driver.nr; i++) {
909*4882a593Smuzhiyun port = &siu_uart_ports[i];
910*4882a593Smuzhiyun if ((port->type == PORT_VR41XX_SIU ||
911*4882a593Smuzhiyun port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
912*4882a593Smuzhiyun uart_suspend_port(&siu_uart_driver, port);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun return 0;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
siu_resume(struct platform_device * dev)919*4882a593Smuzhiyun static int siu_resume(struct platform_device *dev)
920*4882a593Smuzhiyun {
921*4882a593Smuzhiyun struct uart_port *port;
922*4882a593Smuzhiyun int i;
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun for (i = 0; i < siu_uart_driver.nr; i++) {
925*4882a593Smuzhiyun port = &siu_uart_ports[i];
926*4882a593Smuzhiyun if ((port->type == PORT_VR41XX_SIU ||
927*4882a593Smuzhiyun port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
928*4882a593Smuzhiyun uart_resume_port(&siu_uart_driver, port);
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun return 0;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun static struct platform_driver siu_device_driver = {
935*4882a593Smuzhiyun .probe = siu_probe,
936*4882a593Smuzhiyun .remove = siu_remove,
937*4882a593Smuzhiyun .suspend = siu_suspend,
938*4882a593Smuzhiyun .resume = siu_resume,
939*4882a593Smuzhiyun .driver = {
940*4882a593Smuzhiyun .name = "SIU",
941*4882a593Smuzhiyun },
942*4882a593Smuzhiyun };
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun module_platform_driver(siu_device_driver);
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun MODULE_LICENSE("GPL");
947*4882a593Smuzhiyun MODULE_ALIAS("platform:SIU");
948