12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f397c8d8SUlf Hansson /*
3f397c8d8SUlf Hansson * SDIO UART/GPS driver
4f397c8d8SUlf Hansson *
5f397c8d8SUlf Hansson * Based on drivers/serial/8250.c and drivers/serial/serial_core.c
6f397c8d8SUlf Hansson * by Russell King.
7f397c8d8SUlf Hansson *
8f397c8d8SUlf Hansson * Author: Nicolas Pitre
9f397c8d8SUlf Hansson * Created: June 15, 2007
10f397c8d8SUlf Hansson * Copyright: MontaVista Software, Inc.
11f397c8d8SUlf Hansson */
12f397c8d8SUlf Hansson
13f397c8d8SUlf Hansson /*
14f397c8d8SUlf Hansson * Note: Although this driver assumes a 16550A-like UART implementation,
15f397c8d8SUlf Hansson * it is not possible to leverage the common 8250/16550 driver, nor the
16f397c8d8SUlf Hansson * core UART infrastructure, as they assumes direct access to the hardware
17f397c8d8SUlf Hansson * registers, often under a spinlock. This is not possible in the SDIO
18f397c8d8SUlf Hansson * context as SDIO access functions must be able to sleep.
19f397c8d8SUlf Hansson *
20f397c8d8SUlf Hansson * Because we need to lock the SDIO host to ensure an exclusive access to
21f397c8d8SUlf Hansson * the card, we simply rely on that lock to also prevent and serialize
22f397c8d8SUlf Hansson * concurrent access to the same port.
23f397c8d8SUlf Hansson */
24f397c8d8SUlf Hansson
25f397c8d8SUlf Hansson #include <linux/module.h>
26f397c8d8SUlf Hansson #include <linux/init.h>
27f397c8d8SUlf Hansson #include <linux/kernel.h>
28f397c8d8SUlf Hansson #include <linux/sched.h>
29f397c8d8SUlf Hansson #include <linux/mutex.h>
30f397c8d8SUlf Hansson #include <linux/seq_file.h>
31834119f5SJiri Slaby #include <linux/serial.h>
32f397c8d8SUlf Hansson #include <linux/serial_reg.h>
33f397c8d8SUlf Hansson #include <linux/circ_buf.h>
34f397c8d8SUlf Hansson #include <linux/tty.h>
35f397c8d8SUlf Hansson #include <linux/tty_flip.h>
36f397c8d8SUlf Hansson #include <linux/kfifo.h>
37f397c8d8SUlf Hansson #include <linux/slab.h>
38f397c8d8SUlf Hansson
39f397c8d8SUlf Hansson #include <linux/mmc/core.h>
40f397c8d8SUlf Hansson #include <linux/mmc/card.h>
41f397c8d8SUlf Hansson #include <linux/mmc/sdio_func.h>
42f397c8d8SUlf Hansson #include <linux/mmc/sdio_ids.h>
43f397c8d8SUlf Hansson
44f397c8d8SUlf Hansson
45f397c8d8SUlf Hansson #define UART_NR 8 /* Number of UARTs this driver can handle */
46f397c8d8SUlf Hansson
47f397c8d8SUlf Hansson
48f397c8d8SUlf Hansson #define FIFO_SIZE PAGE_SIZE
49f397c8d8SUlf Hansson #define WAKEUP_CHARS 256
50f397c8d8SUlf Hansson
51f397c8d8SUlf Hansson struct uart_icount {
52f397c8d8SUlf Hansson __u32 cts;
53f397c8d8SUlf Hansson __u32 dsr;
54f397c8d8SUlf Hansson __u32 rng;
55f397c8d8SUlf Hansson __u32 dcd;
56f397c8d8SUlf Hansson __u32 rx;
57f397c8d8SUlf Hansson __u32 tx;
58f397c8d8SUlf Hansson __u32 frame;
59f397c8d8SUlf Hansson __u32 overrun;
60f397c8d8SUlf Hansson __u32 parity;
61f397c8d8SUlf Hansson __u32 brk;
62f397c8d8SUlf Hansson };
63f397c8d8SUlf Hansson
64f397c8d8SUlf Hansson struct sdio_uart_port {
65f397c8d8SUlf Hansson struct tty_port port;
66f397c8d8SUlf Hansson unsigned int index;
67f397c8d8SUlf Hansson struct sdio_func *func;
68f397c8d8SUlf Hansson struct mutex func_lock;
69f397c8d8SUlf Hansson struct task_struct *in_sdio_uart_irq;
70f397c8d8SUlf Hansson unsigned int regs_offset;
71f397c8d8SUlf Hansson struct kfifo xmit_fifo;
72f397c8d8SUlf Hansson spinlock_t write_lock;
73f397c8d8SUlf Hansson struct uart_icount icount;
74f397c8d8SUlf Hansson unsigned int uartclk;
75f397c8d8SUlf Hansson unsigned int mctrl;
76f397c8d8SUlf Hansson unsigned int rx_mctrl;
77f397c8d8SUlf Hansson unsigned int read_status_mask;
78f397c8d8SUlf Hansson unsigned int ignore_status_mask;
79f397c8d8SUlf Hansson unsigned char x_char;
80f397c8d8SUlf Hansson unsigned char ier;
81f397c8d8SUlf Hansson unsigned char lcr;
82f397c8d8SUlf Hansson };
83f397c8d8SUlf Hansson
84f397c8d8SUlf Hansson static struct sdio_uart_port *sdio_uart_table[UART_NR];
85f397c8d8SUlf Hansson static DEFINE_SPINLOCK(sdio_uart_table_lock);
86f397c8d8SUlf Hansson
sdio_uart_add_port(struct sdio_uart_port * port)87f397c8d8SUlf Hansson static int sdio_uart_add_port(struct sdio_uart_port *port)
88f397c8d8SUlf Hansson {
89f397c8d8SUlf Hansson int index, ret = -EBUSY;
90f397c8d8SUlf Hansson
91f397c8d8SUlf Hansson mutex_init(&port->func_lock);
92f397c8d8SUlf Hansson spin_lock_init(&port->write_lock);
93f397c8d8SUlf Hansson if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL))
94f397c8d8SUlf Hansson return -ENOMEM;
95f397c8d8SUlf Hansson
96f397c8d8SUlf Hansson spin_lock(&sdio_uart_table_lock);
97f397c8d8SUlf Hansson for (index = 0; index < UART_NR; index++) {
98f397c8d8SUlf Hansson if (!sdio_uart_table[index]) {
99f397c8d8SUlf Hansson port->index = index;
100f397c8d8SUlf Hansson sdio_uart_table[index] = port;
101f397c8d8SUlf Hansson ret = 0;
102f397c8d8SUlf Hansson break;
103f397c8d8SUlf Hansson }
104f397c8d8SUlf Hansson }
105f397c8d8SUlf Hansson spin_unlock(&sdio_uart_table_lock);
106f397c8d8SUlf Hansson
107f397c8d8SUlf Hansson return ret;
108f397c8d8SUlf Hansson }
109f397c8d8SUlf Hansson
sdio_uart_port_get(unsigned index)110f397c8d8SUlf Hansson static struct sdio_uart_port *sdio_uart_port_get(unsigned index)
111f397c8d8SUlf Hansson {
112f397c8d8SUlf Hansson struct sdio_uart_port *port;
113f397c8d8SUlf Hansson
114f397c8d8SUlf Hansson if (index >= UART_NR)
115f397c8d8SUlf Hansson return NULL;
116f397c8d8SUlf Hansson
117f397c8d8SUlf Hansson spin_lock(&sdio_uart_table_lock);
118f397c8d8SUlf Hansson port = sdio_uart_table[index];
119f397c8d8SUlf Hansson if (port)
120f397c8d8SUlf Hansson tty_port_get(&port->port);
121f397c8d8SUlf Hansson spin_unlock(&sdio_uart_table_lock);
122f397c8d8SUlf Hansson
123f397c8d8SUlf Hansson return port;
124f397c8d8SUlf Hansson }
125f397c8d8SUlf Hansson
sdio_uart_port_put(struct sdio_uart_port * port)126f397c8d8SUlf Hansson static void sdio_uart_port_put(struct sdio_uart_port *port)
127f397c8d8SUlf Hansson {
128f397c8d8SUlf Hansson tty_port_put(&port->port);
129f397c8d8SUlf Hansson }
130f397c8d8SUlf Hansson
sdio_uart_port_remove(struct sdio_uart_port * port)131f397c8d8SUlf Hansson static void sdio_uart_port_remove(struct sdio_uart_port *port)
132f397c8d8SUlf Hansson {
133f397c8d8SUlf Hansson struct sdio_func *func;
134f397c8d8SUlf Hansson
135f397c8d8SUlf Hansson spin_lock(&sdio_uart_table_lock);
136f397c8d8SUlf Hansson sdio_uart_table[port->index] = NULL;
137f397c8d8SUlf Hansson spin_unlock(&sdio_uart_table_lock);
138f397c8d8SUlf Hansson
139f397c8d8SUlf Hansson /*
140f397c8d8SUlf Hansson * We're killing a port that potentially still is in use by
141f397c8d8SUlf Hansson * the tty layer. Be careful to prevent any further access
142f397c8d8SUlf Hansson * to the SDIO function and arrange for the tty layer to
143f397c8d8SUlf Hansson * give up on that port ASAP.
144f397c8d8SUlf Hansson * Beware: the lock ordering is critical.
145f397c8d8SUlf Hansson */
146f397c8d8SUlf Hansson mutex_lock(&port->port.mutex);
147f397c8d8SUlf Hansson mutex_lock(&port->func_lock);
148f397c8d8SUlf Hansson func = port->func;
149f397c8d8SUlf Hansson sdio_claim_host(func);
150f397c8d8SUlf Hansson port->func = NULL;
151f397c8d8SUlf Hansson mutex_unlock(&port->func_lock);
152f397c8d8SUlf Hansson /* tty_hangup is async so is this safe as is ?? */
153f397c8d8SUlf Hansson tty_port_tty_hangup(&port->port, false);
154f397c8d8SUlf Hansson mutex_unlock(&port->port.mutex);
155f397c8d8SUlf Hansson sdio_release_irq(func);
156f397c8d8SUlf Hansson sdio_disable_func(func);
157f397c8d8SUlf Hansson sdio_release_host(func);
158f397c8d8SUlf Hansson
159f397c8d8SUlf Hansson sdio_uart_port_put(port);
160f397c8d8SUlf Hansson }
161f397c8d8SUlf Hansson
sdio_uart_claim_func(struct sdio_uart_port * port)162f397c8d8SUlf Hansson static int sdio_uart_claim_func(struct sdio_uart_port *port)
163f397c8d8SUlf Hansson {
164f397c8d8SUlf Hansson mutex_lock(&port->func_lock);
165f397c8d8SUlf Hansson if (unlikely(!port->func)) {
166f397c8d8SUlf Hansson mutex_unlock(&port->func_lock);
167f397c8d8SUlf Hansson return -ENODEV;
168f397c8d8SUlf Hansson }
169f397c8d8SUlf Hansson if (likely(port->in_sdio_uart_irq != current))
170f397c8d8SUlf Hansson sdio_claim_host(port->func);
171f397c8d8SUlf Hansson mutex_unlock(&port->func_lock);
172f397c8d8SUlf Hansson return 0;
173f397c8d8SUlf Hansson }
174f397c8d8SUlf Hansson
sdio_uart_release_func(struct sdio_uart_port * port)175f397c8d8SUlf Hansson static inline void sdio_uart_release_func(struct sdio_uart_port *port)
176f397c8d8SUlf Hansson {
177f397c8d8SUlf Hansson if (likely(port->in_sdio_uart_irq != current))
178f397c8d8SUlf Hansson sdio_release_host(port->func);
179f397c8d8SUlf Hansson }
180f397c8d8SUlf Hansson
sdio_in(struct sdio_uart_port * port,int offset)181f397c8d8SUlf Hansson static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
182f397c8d8SUlf Hansson {
183f397c8d8SUlf Hansson unsigned char c;
184f397c8d8SUlf Hansson c = sdio_readb(port->func, port->regs_offset + offset, NULL);
185f397c8d8SUlf Hansson return c;
186f397c8d8SUlf Hansson }
187f397c8d8SUlf Hansson
sdio_out(struct sdio_uart_port * port,int offset,int value)188f397c8d8SUlf Hansson static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
189f397c8d8SUlf Hansson {
190f397c8d8SUlf Hansson sdio_writeb(port->func, value, port->regs_offset + offset, NULL);
191f397c8d8SUlf Hansson }
192f397c8d8SUlf Hansson
sdio_uart_get_mctrl(struct sdio_uart_port * port)193f397c8d8SUlf Hansson static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
194f397c8d8SUlf Hansson {
195f397c8d8SUlf Hansson unsigned char status;
196f397c8d8SUlf Hansson unsigned int ret;
197f397c8d8SUlf Hansson
198f397c8d8SUlf Hansson /* FIXME: What stops this losing the delta bits and breaking
199f397c8d8SUlf Hansson sdio_uart_check_modem_status ? */
200f397c8d8SUlf Hansson status = sdio_in(port, UART_MSR);
201f397c8d8SUlf Hansson
202f397c8d8SUlf Hansson ret = 0;
203f397c8d8SUlf Hansson if (status & UART_MSR_DCD)
204f397c8d8SUlf Hansson ret |= TIOCM_CAR;
205f397c8d8SUlf Hansson if (status & UART_MSR_RI)
206f397c8d8SUlf Hansson ret |= TIOCM_RNG;
207f397c8d8SUlf Hansson if (status & UART_MSR_DSR)
208f397c8d8SUlf Hansson ret |= TIOCM_DSR;
209f397c8d8SUlf Hansson if (status & UART_MSR_CTS)
210f397c8d8SUlf Hansson ret |= TIOCM_CTS;
211f397c8d8SUlf Hansson return ret;
212f397c8d8SUlf Hansson }
213f397c8d8SUlf Hansson
sdio_uart_write_mctrl(struct sdio_uart_port * port,unsigned int mctrl)214f397c8d8SUlf Hansson static void sdio_uart_write_mctrl(struct sdio_uart_port *port,
215f397c8d8SUlf Hansson unsigned int mctrl)
216f397c8d8SUlf Hansson {
217f397c8d8SUlf Hansson unsigned char mcr = 0;
218f397c8d8SUlf Hansson
219f397c8d8SUlf Hansson if (mctrl & TIOCM_RTS)
220f397c8d8SUlf Hansson mcr |= UART_MCR_RTS;
221f397c8d8SUlf Hansson if (mctrl & TIOCM_DTR)
222f397c8d8SUlf Hansson mcr |= UART_MCR_DTR;
223f397c8d8SUlf Hansson if (mctrl & TIOCM_OUT1)
224f397c8d8SUlf Hansson mcr |= UART_MCR_OUT1;
225f397c8d8SUlf Hansson if (mctrl & TIOCM_OUT2)
226f397c8d8SUlf Hansson mcr |= UART_MCR_OUT2;
227f397c8d8SUlf Hansson if (mctrl & TIOCM_LOOP)
228f397c8d8SUlf Hansson mcr |= UART_MCR_LOOP;
229f397c8d8SUlf Hansson
230f397c8d8SUlf Hansson sdio_out(port, UART_MCR, mcr);
231f397c8d8SUlf Hansson }
232f397c8d8SUlf Hansson
sdio_uart_update_mctrl(struct sdio_uart_port * port,unsigned int set,unsigned int clear)233f397c8d8SUlf Hansson static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port,
234f397c8d8SUlf Hansson unsigned int set, unsigned int clear)
235f397c8d8SUlf Hansson {
236f397c8d8SUlf Hansson unsigned int old;
237f397c8d8SUlf Hansson
238f397c8d8SUlf Hansson old = port->mctrl;
239f397c8d8SUlf Hansson port->mctrl = (old & ~clear) | set;
240f397c8d8SUlf Hansson if (old != port->mctrl)
241f397c8d8SUlf Hansson sdio_uart_write_mctrl(port, port->mctrl);
242f397c8d8SUlf Hansson }
243f397c8d8SUlf Hansson
244f397c8d8SUlf Hansson #define sdio_uart_set_mctrl(port, x) sdio_uart_update_mctrl(port, x, 0)
245f397c8d8SUlf Hansson #define sdio_uart_clear_mctrl(port, x) sdio_uart_update_mctrl(port, 0, x)
246f397c8d8SUlf Hansson
sdio_uart_change_speed(struct sdio_uart_port * port,struct ktermios * termios,const struct ktermios * old)247f397c8d8SUlf Hansson static void sdio_uart_change_speed(struct sdio_uart_port *port,
248f397c8d8SUlf Hansson struct ktermios *termios,
249a8c11c15SIlpo Järvinen const struct ktermios *old)
250f397c8d8SUlf Hansson {
251f397c8d8SUlf Hansson unsigned char cval, fcr = 0;
252f397c8d8SUlf Hansson unsigned int baud, quot;
253f397c8d8SUlf Hansson
254834119f5SJiri Slaby cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
255f397c8d8SUlf Hansson
256f397c8d8SUlf Hansson if (termios->c_cflag & CSTOPB)
257f397c8d8SUlf Hansson cval |= UART_LCR_STOP;
258f397c8d8SUlf Hansson if (termios->c_cflag & PARENB)
259f397c8d8SUlf Hansson cval |= UART_LCR_PARITY;
260f397c8d8SUlf Hansson if (!(termios->c_cflag & PARODD))
261f397c8d8SUlf Hansson cval |= UART_LCR_EPAR;
262f397c8d8SUlf Hansson
263f397c8d8SUlf Hansson for (;;) {
264f397c8d8SUlf Hansson baud = tty_termios_baud_rate(termios);
265f397c8d8SUlf Hansson if (baud == 0)
266f397c8d8SUlf Hansson baud = 9600; /* Special case: B0 rate. */
267f397c8d8SUlf Hansson if (baud <= port->uartclk)
268f397c8d8SUlf Hansson break;
269f397c8d8SUlf Hansson /*
270f397c8d8SUlf Hansson * Oops, the quotient was zero. Try again with the old
271f397c8d8SUlf Hansson * baud rate if possible, otherwise default to 9600.
272f397c8d8SUlf Hansson */
273f397c8d8SUlf Hansson termios->c_cflag &= ~CBAUD;
274f397c8d8SUlf Hansson if (old) {
275f397c8d8SUlf Hansson termios->c_cflag |= old->c_cflag & CBAUD;
276f397c8d8SUlf Hansson old = NULL;
277f397c8d8SUlf Hansson } else
278f397c8d8SUlf Hansson termios->c_cflag |= B9600;
279f397c8d8SUlf Hansson }
280f397c8d8SUlf Hansson quot = (2 * port->uartclk + baud) / (2 * baud);
281f397c8d8SUlf Hansson
282f397c8d8SUlf Hansson if (baud < 2400)
283f397c8d8SUlf Hansson fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
284f397c8d8SUlf Hansson else
285f397c8d8SUlf Hansson fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
286f397c8d8SUlf Hansson
287f397c8d8SUlf Hansson port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
288f397c8d8SUlf Hansson if (termios->c_iflag & INPCK)
289f397c8d8SUlf Hansson port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
290f397c8d8SUlf Hansson if (termios->c_iflag & (BRKINT | PARMRK))
291f397c8d8SUlf Hansson port->read_status_mask |= UART_LSR_BI;
292f397c8d8SUlf Hansson
293f397c8d8SUlf Hansson /*
294f397c8d8SUlf Hansson * Characters to ignore
295f397c8d8SUlf Hansson */
296f397c8d8SUlf Hansson port->ignore_status_mask = 0;
297f397c8d8SUlf Hansson if (termios->c_iflag & IGNPAR)
298f397c8d8SUlf Hansson port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
299f397c8d8SUlf Hansson if (termios->c_iflag & IGNBRK) {
300f397c8d8SUlf Hansson port->ignore_status_mask |= UART_LSR_BI;
301f397c8d8SUlf Hansson /*
302f397c8d8SUlf Hansson * If we're ignoring parity and break indicators,
303f397c8d8SUlf Hansson * ignore overruns too (for real raw support).
304f397c8d8SUlf Hansson */
305f397c8d8SUlf Hansson if (termios->c_iflag & IGNPAR)
306f397c8d8SUlf Hansson port->ignore_status_mask |= UART_LSR_OE;
307f397c8d8SUlf Hansson }
308f397c8d8SUlf Hansson
309f397c8d8SUlf Hansson /*
310f397c8d8SUlf Hansson * ignore all characters if CREAD is not set
311f397c8d8SUlf Hansson */
312f397c8d8SUlf Hansson if ((termios->c_cflag & CREAD) == 0)
313f397c8d8SUlf Hansson port->ignore_status_mask |= UART_LSR_DR;
314f397c8d8SUlf Hansson
315f397c8d8SUlf Hansson /*
316f397c8d8SUlf Hansson * CTS flow control flag and modem status interrupts
317f397c8d8SUlf Hansson */
318f397c8d8SUlf Hansson port->ier &= ~UART_IER_MSI;
319f397c8d8SUlf Hansson if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))
320f397c8d8SUlf Hansson port->ier |= UART_IER_MSI;
321f397c8d8SUlf Hansson
322f397c8d8SUlf Hansson port->lcr = cval;
323f397c8d8SUlf Hansson
324f397c8d8SUlf Hansson sdio_out(port, UART_IER, port->ier);
325f397c8d8SUlf Hansson sdio_out(port, UART_LCR, cval | UART_LCR_DLAB);
326f397c8d8SUlf Hansson sdio_out(port, UART_DLL, quot & 0xff);
327f397c8d8SUlf Hansson sdio_out(port, UART_DLM, quot >> 8);
328f397c8d8SUlf Hansson sdio_out(port, UART_LCR, cval);
329f397c8d8SUlf Hansson sdio_out(port, UART_FCR, fcr);
330f397c8d8SUlf Hansson
331f397c8d8SUlf Hansson sdio_uart_write_mctrl(port, port->mctrl);
332f397c8d8SUlf Hansson }
333f397c8d8SUlf Hansson
sdio_uart_start_tx(struct sdio_uart_port * port)334f397c8d8SUlf Hansson static void sdio_uart_start_tx(struct sdio_uart_port *port)
335f397c8d8SUlf Hansson {
336f397c8d8SUlf Hansson if (!(port->ier & UART_IER_THRI)) {
337f397c8d8SUlf Hansson port->ier |= UART_IER_THRI;
338f397c8d8SUlf Hansson sdio_out(port, UART_IER, port->ier);
339f397c8d8SUlf Hansson }
340f397c8d8SUlf Hansson }
341f397c8d8SUlf Hansson
sdio_uart_stop_tx(struct sdio_uart_port * port)342f397c8d8SUlf Hansson static void sdio_uart_stop_tx(struct sdio_uart_port *port)
343f397c8d8SUlf Hansson {
344f397c8d8SUlf Hansson if (port->ier & UART_IER_THRI) {
345f397c8d8SUlf Hansson port->ier &= ~UART_IER_THRI;
346f397c8d8SUlf Hansson sdio_out(port, UART_IER, port->ier);
347f397c8d8SUlf Hansson }
348f397c8d8SUlf Hansson }
349f397c8d8SUlf Hansson
sdio_uart_stop_rx(struct sdio_uart_port * port)350f397c8d8SUlf Hansson static void sdio_uart_stop_rx(struct sdio_uart_port *port)
351f397c8d8SUlf Hansson {
352f397c8d8SUlf Hansson port->ier &= ~UART_IER_RLSI;
353f397c8d8SUlf Hansson port->read_status_mask &= ~UART_LSR_DR;
354f397c8d8SUlf Hansson sdio_out(port, UART_IER, port->ier);
355f397c8d8SUlf Hansson }
356f397c8d8SUlf Hansson
sdio_uart_receive_chars(struct sdio_uart_port * port,unsigned int * status)357f397c8d8SUlf Hansson static void sdio_uart_receive_chars(struct sdio_uart_port *port,
358f397c8d8SUlf Hansson unsigned int *status)
359f397c8d8SUlf Hansson {
360f397c8d8SUlf Hansson unsigned int ch, flag;
361f397c8d8SUlf Hansson int max_count = 256;
362f397c8d8SUlf Hansson
363f397c8d8SUlf Hansson do {
364f397c8d8SUlf Hansson ch = sdio_in(port, UART_RX);
365f397c8d8SUlf Hansson flag = TTY_NORMAL;
366f397c8d8SUlf Hansson port->icount.rx++;
367f397c8d8SUlf Hansson
368f397c8d8SUlf Hansson if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
369f397c8d8SUlf Hansson UART_LSR_FE | UART_LSR_OE))) {
370f397c8d8SUlf Hansson /*
371f397c8d8SUlf Hansson * For statistics only
372f397c8d8SUlf Hansson */
373f397c8d8SUlf Hansson if (*status & UART_LSR_BI) {
374f397c8d8SUlf Hansson *status &= ~(UART_LSR_FE | UART_LSR_PE);
375f397c8d8SUlf Hansson port->icount.brk++;
376f397c8d8SUlf Hansson } else if (*status & UART_LSR_PE)
377f397c8d8SUlf Hansson port->icount.parity++;
378f397c8d8SUlf Hansson else if (*status & UART_LSR_FE)
379f397c8d8SUlf Hansson port->icount.frame++;
380f397c8d8SUlf Hansson if (*status & UART_LSR_OE)
381f397c8d8SUlf Hansson port->icount.overrun++;
382f397c8d8SUlf Hansson
383f397c8d8SUlf Hansson /*
384f397c8d8SUlf Hansson * Mask off conditions which should be ignored.
385f397c8d8SUlf Hansson */
386f397c8d8SUlf Hansson *status &= port->read_status_mask;
387f397c8d8SUlf Hansson if (*status & UART_LSR_BI)
388f397c8d8SUlf Hansson flag = TTY_BREAK;
389f397c8d8SUlf Hansson else if (*status & UART_LSR_PE)
390f397c8d8SUlf Hansson flag = TTY_PARITY;
391f397c8d8SUlf Hansson else if (*status & UART_LSR_FE)
392f397c8d8SUlf Hansson flag = TTY_FRAME;
393f397c8d8SUlf Hansson }
394f397c8d8SUlf Hansson
395f397c8d8SUlf Hansson if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
396f397c8d8SUlf Hansson tty_insert_flip_char(&port->port, ch, flag);
397f397c8d8SUlf Hansson
398f397c8d8SUlf Hansson /*
399f397c8d8SUlf Hansson * Overrun is special. Since it's reported immediately,
400f397c8d8SUlf Hansson * it doesn't affect the current character.
401f397c8d8SUlf Hansson */
402f397c8d8SUlf Hansson if (*status & ~port->ignore_status_mask & UART_LSR_OE)
403f397c8d8SUlf Hansson tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
404f397c8d8SUlf Hansson
405f397c8d8SUlf Hansson *status = sdio_in(port, UART_LSR);
406f397c8d8SUlf Hansson } while ((*status & UART_LSR_DR) && (max_count-- > 0));
407f397c8d8SUlf Hansson
408f397c8d8SUlf Hansson tty_flip_buffer_push(&port->port);
409f397c8d8SUlf Hansson }
410f397c8d8SUlf Hansson
sdio_uart_transmit_chars(struct sdio_uart_port * port)411f397c8d8SUlf Hansson static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
412f397c8d8SUlf Hansson {
413f397c8d8SUlf Hansson struct kfifo *xmit = &port->xmit_fifo;
414f397c8d8SUlf Hansson int count;
415f397c8d8SUlf Hansson struct tty_struct *tty;
416f397c8d8SUlf Hansson u8 iobuf[16];
417f397c8d8SUlf Hansson int len;
418f397c8d8SUlf Hansson
419f397c8d8SUlf Hansson if (port->x_char) {
420f397c8d8SUlf Hansson sdio_out(port, UART_TX, port->x_char);
421f397c8d8SUlf Hansson port->icount.tx++;
422f397c8d8SUlf Hansson port->x_char = 0;
423f397c8d8SUlf Hansson return;
424f397c8d8SUlf Hansson }
425f397c8d8SUlf Hansson
426f397c8d8SUlf Hansson tty = tty_port_tty_get(&port->port);
427f397c8d8SUlf Hansson
428f397c8d8SUlf Hansson if (tty == NULL || !kfifo_len(xmit) ||
4296e94dbc7SJiri Slaby tty->flow.stopped || tty->hw_stopped) {
430f397c8d8SUlf Hansson sdio_uart_stop_tx(port);
431f397c8d8SUlf Hansson tty_kref_put(tty);
432f397c8d8SUlf Hansson return;
433f397c8d8SUlf Hansson }
434f397c8d8SUlf Hansson
435f397c8d8SUlf Hansson len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock);
436f397c8d8SUlf Hansson for (count = 0; count < len; count++) {
437f397c8d8SUlf Hansson sdio_out(port, UART_TX, iobuf[count]);
438f397c8d8SUlf Hansson port->icount.tx++;
439f397c8d8SUlf Hansson }
440f397c8d8SUlf Hansson
441f397c8d8SUlf Hansson len = kfifo_len(xmit);
442f397c8d8SUlf Hansson if (len < WAKEUP_CHARS) {
443f397c8d8SUlf Hansson tty_wakeup(tty);
444f397c8d8SUlf Hansson if (len == 0)
445f397c8d8SUlf Hansson sdio_uart_stop_tx(port);
446f397c8d8SUlf Hansson }
447f397c8d8SUlf Hansson tty_kref_put(tty);
448f397c8d8SUlf Hansson }
449f397c8d8SUlf Hansson
sdio_uart_check_modem_status(struct sdio_uart_port * port)450f397c8d8SUlf Hansson static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
451f397c8d8SUlf Hansson {
452f397c8d8SUlf Hansson int status;
453f397c8d8SUlf Hansson struct tty_struct *tty;
454f397c8d8SUlf Hansson
455f397c8d8SUlf Hansson status = sdio_in(port, UART_MSR);
456f397c8d8SUlf Hansson
457f397c8d8SUlf Hansson if ((status & UART_MSR_ANY_DELTA) == 0)
458f397c8d8SUlf Hansson return;
459f397c8d8SUlf Hansson
460f397c8d8SUlf Hansson if (status & UART_MSR_TERI)
461f397c8d8SUlf Hansson port->icount.rng++;
462f397c8d8SUlf Hansson if (status & UART_MSR_DDSR)
463f397c8d8SUlf Hansson port->icount.dsr++;
464f397c8d8SUlf Hansson if (status & UART_MSR_DDCD) {
465f397c8d8SUlf Hansson port->icount.dcd++;
466f397c8d8SUlf Hansson /* DCD raise - wake for open */
467f397c8d8SUlf Hansson if (status & UART_MSR_DCD)
468f397c8d8SUlf Hansson wake_up_interruptible(&port->port.open_wait);
469f397c8d8SUlf Hansson else {
470f397c8d8SUlf Hansson /* DCD drop - hang up if tty attached */
471f397c8d8SUlf Hansson tty_port_tty_hangup(&port->port, false);
472f397c8d8SUlf Hansson }
473f397c8d8SUlf Hansson }
474f397c8d8SUlf Hansson if (status & UART_MSR_DCTS) {
475f397c8d8SUlf Hansson port->icount.cts++;
476f397c8d8SUlf Hansson tty = tty_port_tty_get(&port->port);
477f397c8d8SUlf Hansson if (tty && C_CRTSCTS(tty)) {
478f397c8d8SUlf Hansson int cts = (status & UART_MSR_CTS);
479f397c8d8SUlf Hansson if (tty->hw_stopped) {
480f397c8d8SUlf Hansson if (cts) {
481035173c9SIlpo Järvinen tty->hw_stopped = false;
482f397c8d8SUlf Hansson sdio_uart_start_tx(port);
483f397c8d8SUlf Hansson tty_wakeup(tty);
484f397c8d8SUlf Hansson }
485f397c8d8SUlf Hansson } else {
486f397c8d8SUlf Hansson if (!cts) {
487035173c9SIlpo Järvinen tty->hw_stopped = true;
488f397c8d8SUlf Hansson sdio_uart_stop_tx(port);
489f397c8d8SUlf Hansson }
490f397c8d8SUlf Hansson }
491f397c8d8SUlf Hansson }
492f397c8d8SUlf Hansson tty_kref_put(tty);
493f397c8d8SUlf Hansson }
494f397c8d8SUlf Hansson }
495f397c8d8SUlf Hansson
496f397c8d8SUlf Hansson /*
497f397c8d8SUlf Hansson * This handles the interrupt from one port.
498f397c8d8SUlf Hansson */
sdio_uart_irq(struct sdio_func * func)499f397c8d8SUlf Hansson static void sdio_uart_irq(struct sdio_func *func)
500f397c8d8SUlf Hansson {
501f397c8d8SUlf Hansson struct sdio_uart_port *port = sdio_get_drvdata(func);
502f397c8d8SUlf Hansson unsigned int iir, lsr;
503f397c8d8SUlf Hansson
504f397c8d8SUlf Hansson /*
505f397c8d8SUlf Hansson * In a few places sdio_uart_irq() is called directly instead of
506f397c8d8SUlf Hansson * waiting for the actual interrupt to be raised and the SDIO IRQ
507f397c8d8SUlf Hansson * thread scheduled in order to reduce latency. However, some
508f397c8d8SUlf Hansson * interaction with the tty core may end up calling us back
509f397c8d8SUlf Hansson * (serial echo, flow control, etc.) through those same places
510f397c8d8SUlf Hansson * causing undesirable effects. Let's stop the recursion here.
511f397c8d8SUlf Hansson */
512f397c8d8SUlf Hansson if (unlikely(port->in_sdio_uart_irq == current))
513f397c8d8SUlf Hansson return;
514f397c8d8SUlf Hansson
515f397c8d8SUlf Hansson iir = sdio_in(port, UART_IIR);
516f397c8d8SUlf Hansson if (iir & UART_IIR_NO_INT)
517f397c8d8SUlf Hansson return;
518f397c8d8SUlf Hansson
519f397c8d8SUlf Hansson port->in_sdio_uart_irq = current;
520f397c8d8SUlf Hansson lsr = sdio_in(port, UART_LSR);
521f397c8d8SUlf Hansson if (lsr & UART_LSR_DR)
522f397c8d8SUlf Hansson sdio_uart_receive_chars(port, &lsr);
523f397c8d8SUlf Hansson sdio_uart_check_modem_status(port);
524f397c8d8SUlf Hansson if (lsr & UART_LSR_THRE)
525f397c8d8SUlf Hansson sdio_uart_transmit_chars(port);
526f397c8d8SUlf Hansson port->in_sdio_uart_irq = NULL;
527f397c8d8SUlf Hansson }
528f397c8d8SUlf Hansson
uart_carrier_raised(struct tty_port * tport)529b300fb26SIlpo Järvinen static bool uart_carrier_raised(struct tty_port *tport)
530f397c8d8SUlf Hansson {
531f397c8d8SUlf Hansson struct sdio_uart_port *port =
532f397c8d8SUlf Hansson container_of(tport, struct sdio_uart_port, port);
533f397c8d8SUlf Hansson unsigned int ret = sdio_uart_claim_func(port);
534f397c8d8SUlf Hansson if (ret) /* Missing hardware shouldn't block for carrier */
535f397c8d8SUlf Hansson return 1;
536f397c8d8SUlf Hansson ret = sdio_uart_get_mctrl(port);
537f397c8d8SUlf Hansson sdio_uart_release_func(port);
538b300fb26SIlpo Järvinen
539b300fb26SIlpo Järvinen return ret & TIOCM_CAR;
540f397c8d8SUlf Hansson }
541f397c8d8SUlf Hansson
542f397c8d8SUlf Hansson /**
543f397c8d8SUlf Hansson * uart_dtr_rts - port helper to set uart signals
544f397c8d8SUlf Hansson * @tport: tty port to be updated
5455701cb8bSIlpo Järvinen * @active: set to turn on DTR/RTS
546f397c8d8SUlf Hansson *
547f397c8d8SUlf Hansson * Called by the tty port helpers when the modem signals need to be
548f397c8d8SUlf Hansson * adjusted during an open, close and hangup.
549f397c8d8SUlf Hansson */
550f397c8d8SUlf Hansson
uart_dtr_rts(struct tty_port * tport,bool active)5515701cb8bSIlpo Järvinen static void uart_dtr_rts(struct tty_port *tport, bool active)
552f397c8d8SUlf Hansson {
553f397c8d8SUlf Hansson struct sdio_uart_port *port =
554f397c8d8SUlf Hansson container_of(tport, struct sdio_uart_port, port);
555f397c8d8SUlf Hansson int ret = sdio_uart_claim_func(port);
556f397c8d8SUlf Hansson if (ret)
557f397c8d8SUlf Hansson return;
5585701cb8bSIlpo Järvinen if (!active)
559f397c8d8SUlf Hansson sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
560f397c8d8SUlf Hansson else
561f397c8d8SUlf Hansson sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
562f397c8d8SUlf Hansson sdio_uart_release_func(port);
563f397c8d8SUlf Hansson }
564f397c8d8SUlf Hansson
565f397c8d8SUlf Hansson /**
566f397c8d8SUlf Hansson * sdio_uart_activate - start up hardware
567f397c8d8SUlf Hansson * @tport: tty port to activate
568f397c8d8SUlf Hansson * @tty: tty bound to this port
569f397c8d8SUlf Hansson *
570f397c8d8SUlf Hansson * Activate a tty port. The port locking guarantees us this will be
571f397c8d8SUlf Hansson * run exactly once per set of opens, and if successful will see the
572f397c8d8SUlf Hansson * shutdown method run exactly once to match. Start up and shutdown are
573f397c8d8SUlf Hansson * protected from each other by the internal locking and will not run
574f397c8d8SUlf Hansson * at the same time even during a hangup event.
575f397c8d8SUlf Hansson *
576f397c8d8SUlf Hansson * If we successfully start up the port we take an extra kref as we
577f397c8d8SUlf Hansson * will keep it around until shutdown when the kref is dropped.
578f397c8d8SUlf Hansson */
579f397c8d8SUlf Hansson
sdio_uart_activate(struct tty_port * tport,struct tty_struct * tty)580f397c8d8SUlf Hansson static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
581f397c8d8SUlf Hansson {
582f397c8d8SUlf Hansson struct sdio_uart_port *port =
583f397c8d8SUlf Hansson container_of(tport, struct sdio_uart_port, port);
584f397c8d8SUlf Hansson int ret;
585f397c8d8SUlf Hansson
586f397c8d8SUlf Hansson /*
587f397c8d8SUlf Hansson * Set the TTY IO error marker - we will only clear this
588f397c8d8SUlf Hansson * once we have successfully opened the port.
589f397c8d8SUlf Hansson */
590f397c8d8SUlf Hansson set_bit(TTY_IO_ERROR, &tty->flags);
591f397c8d8SUlf Hansson
592f397c8d8SUlf Hansson kfifo_reset(&port->xmit_fifo);
593f397c8d8SUlf Hansson
594f397c8d8SUlf Hansson ret = sdio_uart_claim_func(port);
595f397c8d8SUlf Hansson if (ret)
596f397c8d8SUlf Hansson return ret;
597f397c8d8SUlf Hansson ret = sdio_enable_func(port->func);
598f397c8d8SUlf Hansson if (ret)
599f397c8d8SUlf Hansson goto err1;
600f397c8d8SUlf Hansson ret = sdio_claim_irq(port->func, sdio_uart_irq);
601f397c8d8SUlf Hansson if (ret)
602f397c8d8SUlf Hansson goto err2;
603f397c8d8SUlf Hansson
604f397c8d8SUlf Hansson /*
605f397c8d8SUlf Hansson * Clear the FIFO buffers and disable them.
606f397c8d8SUlf Hansson * (they will be reenabled in sdio_change_speed())
607f397c8d8SUlf Hansson */
608f397c8d8SUlf Hansson sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
609f397c8d8SUlf Hansson sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
610f397c8d8SUlf Hansson UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
611f397c8d8SUlf Hansson sdio_out(port, UART_FCR, 0);
612f397c8d8SUlf Hansson
613f397c8d8SUlf Hansson /*
614f397c8d8SUlf Hansson * Clear the interrupt registers.
615f397c8d8SUlf Hansson */
616f397c8d8SUlf Hansson (void) sdio_in(port, UART_LSR);
617f397c8d8SUlf Hansson (void) sdio_in(port, UART_RX);
618f397c8d8SUlf Hansson (void) sdio_in(port, UART_IIR);
619f397c8d8SUlf Hansson (void) sdio_in(port, UART_MSR);
620f397c8d8SUlf Hansson
621f397c8d8SUlf Hansson /*
622f397c8d8SUlf Hansson * Now, initialize the UART
623f397c8d8SUlf Hansson */
624f397c8d8SUlf Hansson sdio_out(port, UART_LCR, UART_LCR_WLEN8);
625f397c8d8SUlf Hansson
626f397c8d8SUlf Hansson port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
627f397c8d8SUlf Hansson port->mctrl = TIOCM_OUT2;
628f397c8d8SUlf Hansson
629f397c8d8SUlf Hansson sdio_uart_change_speed(port, &tty->termios, NULL);
630f397c8d8SUlf Hansson
631f397c8d8SUlf Hansson if (C_BAUD(tty))
632f397c8d8SUlf Hansson sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
633f397c8d8SUlf Hansson
634f397c8d8SUlf Hansson if (C_CRTSCTS(tty))
635f397c8d8SUlf Hansson if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
636035173c9SIlpo Järvinen tty->hw_stopped = true;
637f397c8d8SUlf Hansson
638f397c8d8SUlf Hansson clear_bit(TTY_IO_ERROR, &tty->flags);
639f397c8d8SUlf Hansson
640f397c8d8SUlf Hansson /* Kick the IRQ handler once while we're still holding the host lock */
641f397c8d8SUlf Hansson sdio_uart_irq(port->func);
642f397c8d8SUlf Hansson
643f397c8d8SUlf Hansson sdio_uart_release_func(port);
644f397c8d8SUlf Hansson return 0;
645f397c8d8SUlf Hansson
646f397c8d8SUlf Hansson err2:
647f397c8d8SUlf Hansson sdio_disable_func(port->func);
648f397c8d8SUlf Hansson err1:
649f397c8d8SUlf Hansson sdio_uart_release_func(port);
650f397c8d8SUlf Hansson return ret;
651f397c8d8SUlf Hansson }
652f397c8d8SUlf Hansson
653f397c8d8SUlf Hansson /**
654f397c8d8SUlf Hansson * sdio_uart_shutdown - stop hardware
655f397c8d8SUlf Hansson * @tport: tty port to shut down
656f397c8d8SUlf Hansson *
657f397c8d8SUlf Hansson * Deactivate a tty port. The port locking guarantees us this will be
658f397c8d8SUlf Hansson * run only if a successful matching activate already ran. The two are
659f397c8d8SUlf Hansson * protected from each other by the internal locking and will not run
660f397c8d8SUlf Hansson * at the same time even during a hangup event.
661f397c8d8SUlf Hansson */
662f397c8d8SUlf Hansson
sdio_uart_shutdown(struct tty_port * tport)663f397c8d8SUlf Hansson static void sdio_uart_shutdown(struct tty_port *tport)
664f397c8d8SUlf Hansson {
665f397c8d8SUlf Hansson struct sdio_uart_port *port =
666f397c8d8SUlf Hansson container_of(tport, struct sdio_uart_port, port);
667f397c8d8SUlf Hansson int ret;
668f397c8d8SUlf Hansson
669f397c8d8SUlf Hansson ret = sdio_uart_claim_func(port);
670f397c8d8SUlf Hansson if (ret)
671f397c8d8SUlf Hansson return;
672f397c8d8SUlf Hansson
673f397c8d8SUlf Hansson sdio_uart_stop_rx(port);
674f397c8d8SUlf Hansson
675f397c8d8SUlf Hansson /* Disable interrupts from this port */
676f397c8d8SUlf Hansson sdio_release_irq(port->func);
677f397c8d8SUlf Hansson port->ier = 0;
678f397c8d8SUlf Hansson sdio_out(port, UART_IER, 0);
679f397c8d8SUlf Hansson
680f397c8d8SUlf Hansson sdio_uart_clear_mctrl(port, TIOCM_OUT2);
681f397c8d8SUlf Hansson
682f397c8d8SUlf Hansson /* Disable break condition and FIFOs. */
683f397c8d8SUlf Hansson port->lcr &= ~UART_LCR_SBC;
684f397c8d8SUlf Hansson sdio_out(port, UART_LCR, port->lcr);
685f397c8d8SUlf Hansson sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
686f397c8d8SUlf Hansson UART_FCR_CLEAR_RCVR |
687f397c8d8SUlf Hansson UART_FCR_CLEAR_XMIT);
688f397c8d8SUlf Hansson sdio_out(port, UART_FCR, 0);
689f397c8d8SUlf Hansson
690f397c8d8SUlf Hansson sdio_disable_func(port->func);
691f397c8d8SUlf Hansson
692f397c8d8SUlf Hansson sdio_uart_release_func(port);
693f397c8d8SUlf Hansson }
694f397c8d8SUlf Hansson
sdio_uart_port_destroy(struct tty_port * tport)695f397c8d8SUlf Hansson static void sdio_uart_port_destroy(struct tty_port *tport)
696f397c8d8SUlf Hansson {
697f397c8d8SUlf Hansson struct sdio_uart_port *port =
698f397c8d8SUlf Hansson container_of(tport, struct sdio_uart_port, port);
699f397c8d8SUlf Hansson kfifo_free(&port->xmit_fifo);
700f397c8d8SUlf Hansson kfree(port);
701f397c8d8SUlf Hansson }
702f397c8d8SUlf Hansson
703f397c8d8SUlf Hansson /**
704f397c8d8SUlf Hansson * sdio_uart_install - install method
705f397c8d8SUlf Hansson * @driver: the driver in use (sdio_uart in our case)
706f397c8d8SUlf Hansson * @tty: the tty being bound
707f397c8d8SUlf Hansson *
708f397c8d8SUlf Hansson * Look up and bind the tty and the driver together. Initialize
709f397c8d8SUlf Hansson * any needed private data (in our case the termios)
710f397c8d8SUlf Hansson */
711f397c8d8SUlf Hansson
sdio_uart_install(struct tty_driver * driver,struct tty_struct * tty)712f397c8d8SUlf Hansson static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
713f397c8d8SUlf Hansson {
714f397c8d8SUlf Hansson int idx = tty->index;
715f397c8d8SUlf Hansson struct sdio_uart_port *port = sdio_uart_port_get(idx);
716f397c8d8SUlf Hansson int ret = tty_standard_install(driver, tty);
717f397c8d8SUlf Hansson
718f397c8d8SUlf Hansson if (ret == 0)
719f397c8d8SUlf Hansson /* This is the ref sdio_uart_port get provided */
720f397c8d8SUlf Hansson tty->driver_data = port;
721f397c8d8SUlf Hansson else
722f397c8d8SUlf Hansson sdio_uart_port_put(port);
723f397c8d8SUlf Hansson return ret;
724f397c8d8SUlf Hansson }
725f397c8d8SUlf Hansson
726f397c8d8SUlf Hansson /**
727f397c8d8SUlf Hansson * sdio_uart_cleanup - called on the last tty kref drop
728f397c8d8SUlf Hansson * @tty: the tty being destroyed
729f397c8d8SUlf Hansson *
730f397c8d8SUlf Hansson * Called asynchronously when the last reference to the tty is dropped.
731f397c8d8SUlf Hansson * We cannot destroy the tty->driver_data port kref until this point
732f397c8d8SUlf Hansson */
733f397c8d8SUlf Hansson
sdio_uart_cleanup(struct tty_struct * tty)734f397c8d8SUlf Hansson static void sdio_uart_cleanup(struct tty_struct *tty)
735f397c8d8SUlf Hansson {
736f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
737f397c8d8SUlf Hansson tty->driver_data = NULL; /* Bug trap */
738f397c8d8SUlf Hansson sdio_uart_port_put(port);
739f397c8d8SUlf Hansson }
740f397c8d8SUlf Hansson
741f397c8d8SUlf Hansson /*
742f397c8d8SUlf Hansson * Open/close/hangup is now entirely boilerplate
743f397c8d8SUlf Hansson */
744f397c8d8SUlf Hansson
sdio_uart_open(struct tty_struct * tty,struct file * filp)745f397c8d8SUlf Hansson static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
746f397c8d8SUlf Hansson {
747f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
748f397c8d8SUlf Hansson return tty_port_open(&port->port, tty, filp);
749f397c8d8SUlf Hansson }
750f397c8d8SUlf Hansson
sdio_uart_close(struct tty_struct * tty,struct file * filp)751f397c8d8SUlf Hansson static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
752f397c8d8SUlf Hansson {
753f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
754f397c8d8SUlf Hansson tty_port_close(&port->port, tty, filp);
755f397c8d8SUlf Hansson }
756f397c8d8SUlf Hansson
sdio_uart_hangup(struct tty_struct * tty)757f397c8d8SUlf Hansson static void sdio_uart_hangup(struct tty_struct *tty)
758f397c8d8SUlf Hansson {
759f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
760f397c8d8SUlf Hansson tty_port_hangup(&port->port);
761f397c8d8SUlf Hansson }
762f397c8d8SUlf Hansson
sdio_uart_write(struct tty_struct * tty,const u8 * buf,size_t count)763*95713967SJiri Slaby (SUSE) static ssize_t sdio_uart_write(struct tty_struct *tty, const u8 *buf,
764*95713967SJiri Slaby (SUSE) size_t count)
765f397c8d8SUlf Hansson {
766f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
767f397c8d8SUlf Hansson int ret;
768f397c8d8SUlf Hansson
769f397c8d8SUlf Hansson if (!port->func)
770f397c8d8SUlf Hansson return -ENODEV;
771f397c8d8SUlf Hansson
772f397c8d8SUlf Hansson ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock);
773f397c8d8SUlf Hansson if (!(port->ier & UART_IER_THRI)) {
774f397c8d8SUlf Hansson int err = sdio_uart_claim_func(port);
775f397c8d8SUlf Hansson if (!err) {
776f397c8d8SUlf Hansson sdio_uart_start_tx(port);
777f397c8d8SUlf Hansson sdio_uart_irq(port->func);
778f397c8d8SUlf Hansson sdio_uart_release_func(port);
779f397c8d8SUlf Hansson } else
780f397c8d8SUlf Hansson ret = err;
781f397c8d8SUlf Hansson }
782f397c8d8SUlf Hansson
783f397c8d8SUlf Hansson return ret;
784f397c8d8SUlf Hansson }
785f397c8d8SUlf Hansson
sdio_uart_write_room(struct tty_struct * tty)78603b3b1a2SJiri Slaby static unsigned int sdio_uart_write_room(struct tty_struct *tty)
787f397c8d8SUlf Hansson {
788f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
789f397c8d8SUlf Hansson return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
790f397c8d8SUlf Hansson }
791f397c8d8SUlf Hansson
sdio_uart_chars_in_buffer(struct tty_struct * tty)792fff4ef17SJiri Slaby static unsigned int sdio_uart_chars_in_buffer(struct tty_struct *tty)
793f397c8d8SUlf Hansson {
794f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
795f397c8d8SUlf Hansson return kfifo_len(&port->xmit_fifo);
796f397c8d8SUlf Hansson }
797f397c8d8SUlf Hansson
sdio_uart_send_xchar(struct tty_struct * tty,char ch)798f397c8d8SUlf Hansson static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
799f397c8d8SUlf Hansson {
800f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
801f397c8d8SUlf Hansson
802f397c8d8SUlf Hansson port->x_char = ch;
803f397c8d8SUlf Hansson if (ch && !(port->ier & UART_IER_THRI)) {
804f397c8d8SUlf Hansson if (sdio_uart_claim_func(port) != 0)
805f397c8d8SUlf Hansson return;
806f397c8d8SUlf Hansson sdio_uart_start_tx(port);
807f397c8d8SUlf Hansson sdio_uart_irq(port->func);
808f397c8d8SUlf Hansson sdio_uart_release_func(port);
809f397c8d8SUlf Hansson }
810f397c8d8SUlf Hansson }
811f397c8d8SUlf Hansson
sdio_uart_throttle(struct tty_struct * tty)812f397c8d8SUlf Hansson static void sdio_uart_throttle(struct tty_struct *tty)
813f397c8d8SUlf Hansson {
814f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
815f397c8d8SUlf Hansson
816f397c8d8SUlf Hansson if (!I_IXOFF(tty) && !C_CRTSCTS(tty))
817f397c8d8SUlf Hansson return;
818f397c8d8SUlf Hansson
819f397c8d8SUlf Hansson if (sdio_uart_claim_func(port) != 0)
820f397c8d8SUlf Hansson return;
821f397c8d8SUlf Hansson
822f397c8d8SUlf Hansson if (I_IXOFF(tty)) {
823f397c8d8SUlf Hansson port->x_char = STOP_CHAR(tty);
824f397c8d8SUlf Hansson sdio_uart_start_tx(port);
825f397c8d8SUlf Hansson }
826f397c8d8SUlf Hansson
827f397c8d8SUlf Hansson if (C_CRTSCTS(tty))
828f397c8d8SUlf Hansson sdio_uart_clear_mctrl(port, TIOCM_RTS);
829f397c8d8SUlf Hansson
830f397c8d8SUlf Hansson sdio_uart_irq(port->func);
831f397c8d8SUlf Hansson sdio_uart_release_func(port);
832f397c8d8SUlf Hansson }
833f397c8d8SUlf Hansson
sdio_uart_unthrottle(struct tty_struct * tty)834f397c8d8SUlf Hansson static void sdio_uart_unthrottle(struct tty_struct *tty)
835f397c8d8SUlf Hansson {
836f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
837f397c8d8SUlf Hansson
838f397c8d8SUlf Hansson if (!I_IXOFF(tty) && !C_CRTSCTS(tty))
839f397c8d8SUlf Hansson return;
840f397c8d8SUlf Hansson
841f397c8d8SUlf Hansson if (sdio_uart_claim_func(port) != 0)
842f397c8d8SUlf Hansson return;
843f397c8d8SUlf Hansson
844f397c8d8SUlf Hansson if (I_IXOFF(tty)) {
845f397c8d8SUlf Hansson if (port->x_char) {
846f397c8d8SUlf Hansson port->x_char = 0;
847f397c8d8SUlf Hansson } else {
848f397c8d8SUlf Hansson port->x_char = START_CHAR(tty);
849f397c8d8SUlf Hansson sdio_uart_start_tx(port);
850f397c8d8SUlf Hansson }
851f397c8d8SUlf Hansson }
852f397c8d8SUlf Hansson
853f397c8d8SUlf Hansson if (C_CRTSCTS(tty))
854f397c8d8SUlf Hansson sdio_uart_set_mctrl(port, TIOCM_RTS);
855f397c8d8SUlf Hansson
856f397c8d8SUlf Hansson sdio_uart_irq(port->func);
857f397c8d8SUlf Hansson sdio_uart_release_func(port);
858f397c8d8SUlf Hansson }
859f397c8d8SUlf Hansson
sdio_uart_set_termios(struct tty_struct * tty,const struct ktermios * old_termios)860f397c8d8SUlf Hansson static void sdio_uart_set_termios(struct tty_struct *tty,
861a8c11c15SIlpo Järvinen const struct ktermios *old_termios)
862f397c8d8SUlf Hansson {
863f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
864f397c8d8SUlf Hansson unsigned int cflag = tty->termios.c_cflag;
865f397c8d8SUlf Hansson
866f397c8d8SUlf Hansson if (sdio_uart_claim_func(port) != 0)
867f397c8d8SUlf Hansson return;
868f397c8d8SUlf Hansson
869f397c8d8SUlf Hansson sdio_uart_change_speed(port, &tty->termios, old_termios);
870f397c8d8SUlf Hansson
871f397c8d8SUlf Hansson /* Handle transition to B0 status */
872f397c8d8SUlf Hansson if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
873f397c8d8SUlf Hansson sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR);
874f397c8d8SUlf Hansson
875f397c8d8SUlf Hansson /* Handle transition away from B0 status */
876f397c8d8SUlf Hansson if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
877f397c8d8SUlf Hansson unsigned int mask = TIOCM_DTR;
878f397c8d8SUlf Hansson if (!(cflag & CRTSCTS) || !tty_throttled(tty))
879f397c8d8SUlf Hansson mask |= TIOCM_RTS;
880f397c8d8SUlf Hansson sdio_uart_set_mctrl(port, mask);
881f397c8d8SUlf Hansson }
882f397c8d8SUlf Hansson
883f397c8d8SUlf Hansson /* Handle turning off CRTSCTS */
884f397c8d8SUlf Hansson if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
885035173c9SIlpo Järvinen tty->hw_stopped = false;
886f397c8d8SUlf Hansson sdio_uart_start_tx(port);
887f397c8d8SUlf Hansson }
888f397c8d8SUlf Hansson
889f397c8d8SUlf Hansson /* Handle turning on CRTSCTS */
890f397c8d8SUlf Hansson if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
891f397c8d8SUlf Hansson if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) {
892035173c9SIlpo Järvinen tty->hw_stopped = true;
893f397c8d8SUlf Hansson sdio_uart_stop_tx(port);
894f397c8d8SUlf Hansson }
895f397c8d8SUlf Hansson }
896f397c8d8SUlf Hansson
897f397c8d8SUlf Hansson sdio_uart_release_func(port);
898f397c8d8SUlf Hansson }
899f397c8d8SUlf Hansson
sdio_uart_break_ctl(struct tty_struct * tty,int break_state)900f397c8d8SUlf Hansson static int sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
901f397c8d8SUlf Hansson {
902f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
903f397c8d8SUlf Hansson int result;
904f397c8d8SUlf Hansson
905f397c8d8SUlf Hansson result = sdio_uart_claim_func(port);
906f397c8d8SUlf Hansson if (result != 0)
907f397c8d8SUlf Hansson return result;
908f397c8d8SUlf Hansson
909f397c8d8SUlf Hansson if (break_state == -1)
910f397c8d8SUlf Hansson port->lcr |= UART_LCR_SBC;
911f397c8d8SUlf Hansson else
912f397c8d8SUlf Hansson port->lcr &= ~UART_LCR_SBC;
913f397c8d8SUlf Hansson sdio_out(port, UART_LCR, port->lcr);
914f397c8d8SUlf Hansson
915f397c8d8SUlf Hansson sdio_uart_release_func(port);
916f397c8d8SUlf Hansson return 0;
917f397c8d8SUlf Hansson }
918f397c8d8SUlf Hansson
sdio_uart_tiocmget(struct tty_struct * tty)919f397c8d8SUlf Hansson static int sdio_uart_tiocmget(struct tty_struct *tty)
920f397c8d8SUlf Hansson {
921f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
922f397c8d8SUlf Hansson int result;
923f397c8d8SUlf Hansson
924f397c8d8SUlf Hansson result = sdio_uart_claim_func(port);
925f397c8d8SUlf Hansson if (!result) {
926f397c8d8SUlf Hansson result = port->mctrl | sdio_uart_get_mctrl(port);
927f397c8d8SUlf Hansson sdio_uart_release_func(port);
928f397c8d8SUlf Hansson }
929f397c8d8SUlf Hansson
930f397c8d8SUlf Hansson return result;
931f397c8d8SUlf Hansson }
932f397c8d8SUlf Hansson
sdio_uart_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)933f397c8d8SUlf Hansson static int sdio_uart_tiocmset(struct tty_struct *tty,
934f397c8d8SUlf Hansson unsigned int set, unsigned int clear)
935f397c8d8SUlf Hansson {
936f397c8d8SUlf Hansson struct sdio_uart_port *port = tty->driver_data;
937f397c8d8SUlf Hansson int result;
938f397c8d8SUlf Hansson
939f397c8d8SUlf Hansson result = sdio_uart_claim_func(port);
940f397c8d8SUlf Hansson if (!result) {
941f397c8d8SUlf Hansson sdio_uart_update_mctrl(port, set, clear);
942f397c8d8SUlf Hansson sdio_uart_release_func(port);
943f397c8d8SUlf Hansson }
944f397c8d8SUlf Hansson
945f397c8d8SUlf Hansson return result;
946f397c8d8SUlf Hansson }
947f397c8d8SUlf Hansson
sdio_uart_proc_show(struct seq_file * m,void * v)948f397c8d8SUlf Hansson static int sdio_uart_proc_show(struct seq_file *m, void *v)
949f397c8d8SUlf Hansson {
950f397c8d8SUlf Hansson int i;
951f397c8d8SUlf Hansson
952f397c8d8SUlf Hansson seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
953f397c8d8SUlf Hansson "", "", "");
954f397c8d8SUlf Hansson for (i = 0; i < UART_NR; i++) {
955f397c8d8SUlf Hansson struct sdio_uart_port *port = sdio_uart_port_get(i);
956f397c8d8SUlf Hansson if (port) {
957f397c8d8SUlf Hansson seq_printf(m, "%d: uart:SDIO", i);
958f397c8d8SUlf Hansson if (capable(CAP_SYS_ADMIN)) {
959f397c8d8SUlf Hansson seq_printf(m, " tx:%d rx:%d",
960f397c8d8SUlf Hansson port->icount.tx, port->icount.rx);
961f397c8d8SUlf Hansson if (port->icount.frame)
962f397c8d8SUlf Hansson seq_printf(m, " fe:%d",
963f397c8d8SUlf Hansson port->icount.frame);
964f397c8d8SUlf Hansson if (port->icount.parity)
965f397c8d8SUlf Hansson seq_printf(m, " pe:%d",
966f397c8d8SUlf Hansson port->icount.parity);
967f397c8d8SUlf Hansson if (port->icount.brk)
968f397c8d8SUlf Hansson seq_printf(m, " brk:%d",
969f397c8d8SUlf Hansson port->icount.brk);
970f397c8d8SUlf Hansson if (port->icount.overrun)
971f397c8d8SUlf Hansson seq_printf(m, " oe:%d",
972f397c8d8SUlf Hansson port->icount.overrun);
973f397c8d8SUlf Hansson if (port->icount.cts)
974f397c8d8SUlf Hansson seq_printf(m, " cts:%d",
975f397c8d8SUlf Hansson port->icount.cts);
976f397c8d8SUlf Hansson if (port->icount.dsr)
977f397c8d8SUlf Hansson seq_printf(m, " dsr:%d",
978f397c8d8SUlf Hansson port->icount.dsr);
979f397c8d8SUlf Hansson if (port->icount.rng)
980f397c8d8SUlf Hansson seq_printf(m, " rng:%d",
981f397c8d8SUlf Hansson port->icount.rng);
982f397c8d8SUlf Hansson if (port->icount.dcd)
983f397c8d8SUlf Hansson seq_printf(m, " dcd:%d",
984f397c8d8SUlf Hansson port->icount.dcd);
985f397c8d8SUlf Hansson }
986f397c8d8SUlf Hansson sdio_uart_port_put(port);
987f397c8d8SUlf Hansson seq_putc(m, '\n');
988f397c8d8SUlf Hansson }
989f397c8d8SUlf Hansson }
990f397c8d8SUlf Hansson return 0;
991f397c8d8SUlf Hansson }
992f397c8d8SUlf Hansson
993f397c8d8SUlf Hansson static const struct tty_port_operations sdio_uart_port_ops = {
994f397c8d8SUlf Hansson .dtr_rts = uart_dtr_rts,
995f397c8d8SUlf Hansson .carrier_raised = uart_carrier_raised,
996f397c8d8SUlf Hansson .shutdown = sdio_uart_shutdown,
997f397c8d8SUlf Hansson .activate = sdio_uart_activate,
998f397c8d8SUlf Hansson .destruct = sdio_uart_port_destroy,
999f397c8d8SUlf Hansson };
1000f397c8d8SUlf Hansson
1001f397c8d8SUlf Hansson static const struct tty_operations sdio_uart_ops = {
1002f397c8d8SUlf Hansson .open = sdio_uart_open,
1003f397c8d8SUlf Hansson .close = sdio_uart_close,
1004f397c8d8SUlf Hansson .write = sdio_uart_write,
1005f397c8d8SUlf Hansson .write_room = sdio_uart_write_room,
1006f397c8d8SUlf Hansson .chars_in_buffer = sdio_uart_chars_in_buffer,
1007f397c8d8SUlf Hansson .send_xchar = sdio_uart_send_xchar,
1008f397c8d8SUlf Hansson .throttle = sdio_uart_throttle,
1009f397c8d8SUlf Hansson .unthrottle = sdio_uart_unthrottle,
1010f397c8d8SUlf Hansson .set_termios = sdio_uart_set_termios,
1011f397c8d8SUlf Hansson .hangup = sdio_uart_hangup,
1012f397c8d8SUlf Hansson .break_ctl = sdio_uart_break_ctl,
1013f397c8d8SUlf Hansson .tiocmget = sdio_uart_tiocmget,
1014f397c8d8SUlf Hansson .tiocmset = sdio_uart_tiocmset,
1015f397c8d8SUlf Hansson .install = sdio_uart_install,
1016f397c8d8SUlf Hansson .cleanup = sdio_uart_cleanup,
10178a8dcabfSChristoph Hellwig .proc_show = sdio_uart_proc_show,
1018f397c8d8SUlf Hansson };
1019f397c8d8SUlf Hansson
1020f397c8d8SUlf Hansson static struct tty_driver *sdio_uart_tty_driver;
1021f397c8d8SUlf Hansson
sdio_uart_probe(struct sdio_func * func,const struct sdio_device_id * id)1022f397c8d8SUlf Hansson static int sdio_uart_probe(struct sdio_func *func,
1023f397c8d8SUlf Hansson const struct sdio_device_id *id)
1024f397c8d8SUlf Hansson {
1025f397c8d8SUlf Hansson struct sdio_uart_port *port;
1026f397c8d8SUlf Hansson int ret;
1027f397c8d8SUlf Hansson
1028f397c8d8SUlf Hansson port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL);
1029f397c8d8SUlf Hansson if (!port)
1030f397c8d8SUlf Hansson return -ENOMEM;
1031f397c8d8SUlf Hansson
1032f397c8d8SUlf Hansson if (func->class == SDIO_CLASS_UART) {
1033f397c8d8SUlf Hansson pr_warn("%s: need info on UART class basic setup\n",
1034f397c8d8SUlf Hansson sdio_func_id(func));
1035f397c8d8SUlf Hansson kfree(port);
1036f397c8d8SUlf Hansson return -ENOSYS;
1037f397c8d8SUlf Hansson } else if (func->class == SDIO_CLASS_GPS) {
1038f397c8d8SUlf Hansson /*
1039f397c8d8SUlf Hansson * We need tuple 0x91. It contains SUBTPL_SIOREG
1040f397c8d8SUlf Hansson * and SUBTPL_RCVCAPS.
1041f397c8d8SUlf Hansson */
1042f397c8d8SUlf Hansson struct sdio_func_tuple *tpl;
1043f397c8d8SUlf Hansson for (tpl = func->tuples; tpl; tpl = tpl->next) {
1044f397c8d8SUlf Hansson if (tpl->code != 0x91)
1045f397c8d8SUlf Hansson continue;
1046f397c8d8SUlf Hansson if (tpl->size < 10)
1047f397c8d8SUlf Hansson continue;
1048f397c8d8SUlf Hansson if (tpl->data[1] == 0) /* SUBTPL_SIOREG */
1049f397c8d8SUlf Hansson break;
1050f397c8d8SUlf Hansson }
1051f397c8d8SUlf Hansson if (!tpl) {
1052f397c8d8SUlf Hansson pr_warn("%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
1053f397c8d8SUlf Hansson sdio_func_id(func));
1054f397c8d8SUlf Hansson kfree(port);
1055f397c8d8SUlf Hansson return -EINVAL;
1056f397c8d8SUlf Hansson }
1057f397c8d8SUlf Hansson pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
1058f397c8d8SUlf Hansson sdio_func_id(func), tpl->data[2], tpl->data[3]);
1059f397c8d8SUlf Hansson port->regs_offset = (tpl->data[4] << 0) |
1060f397c8d8SUlf Hansson (tpl->data[5] << 8) |
1061f397c8d8SUlf Hansson (tpl->data[6] << 16);
1062f397c8d8SUlf Hansson pr_debug("%s: regs offset = 0x%x\n",
1063f397c8d8SUlf Hansson sdio_func_id(func), port->regs_offset);
1064f397c8d8SUlf Hansson port->uartclk = tpl->data[7] * 115200;
1065f397c8d8SUlf Hansson if (port->uartclk == 0)
1066f397c8d8SUlf Hansson port->uartclk = 115200;
1067f397c8d8SUlf Hansson pr_debug("%s: clk %d baudcode %u 4800-div %u\n",
1068f397c8d8SUlf Hansson sdio_func_id(func), port->uartclk,
1069f397c8d8SUlf Hansson tpl->data[7], tpl->data[8] | (tpl->data[9] << 8));
1070f397c8d8SUlf Hansson } else {
1071f397c8d8SUlf Hansson kfree(port);
1072f397c8d8SUlf Hansson return -EINVAL;
1073f397c8d8SUlf Hansson }
1074f397c8d8SUlf Hansson
1075f397c8d8SUlf Hansson port->func = func;
1076f397c8d8SUlf Hansson sdio_set_drvdata(func, port);
1077f397c8d8SUlf Hansson tty_port_init(&port->port);
1078f397c8d8SUlf Hansson port->port.ops = &sdio_uart_port_ops;
1079f397c8d8SUlf Hansson
1080f397c8d8SUlf Hansson ret = sdio_uart_add_port(port);
1081f397c8d8SUlf Hansson if (ret) {
1082f397c8d8SUlf Hansson kfree(port);
1083f397c8d8SUlf Hansson } else {
1084f397c8d8SUlf Hansson struct device *dev;
1085f397c8d8SUlf Hansson dev = tty_port_register_device(&port->port,
1086f397c8d8SUlf Hansson sdio_uart_tty_driver, port->index, &func->dev);
1087f397c8d8SUlf Hansson if (IS_ERR(dev)) {
1088f397c8d8SUlf Hansson sdio_uart_port_remove(port);
1089f397c8d8SUlf Hansson ret = PTR_ERR(dev);
1090f397c8d8SUlf Hansson }
1091f397c8d8SUlf Hansson }
1092f397c8d8SUlf Hansson
1093f397c8d8SUlf Hansson return ret;
1094f397c8d8SUlf Hansson }
1095f397c8d8SUlf Hansson
sdio_uart_remove(struct sdio_func * func)1096f397c8d8SUlf Hansson static void sdio_uart_remove(struct sdio_func *func)
1097f397c8d8SUlf Hansson {
1098f397c8d8SUlf Hansson struct sdio_uart_port *port = sdio_get_drvdata(func);
1099f397c8d8SUlf Hansson
1100f397c8d8SUlf Hansson tty_unregister_device(sdio_uart_tty_driver, port->index);
1101f397c8d8SUlf Hansson sdio_uart_port_remove(port);
1102f397c8d8SUlf Hansson }
1103f397c8d8SUlf Hansson
1104f397c8d8SUlf Hansson static const struct sdio_device_id sdio_uart_ids[] = {
1105f397c8d8SUlf Hansson { SDIO_DEVICE_CLASS(SDIO_CLASS_UART) },
1106f397c8d8SUlf Hansson { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS) },
1107f397c8d8SUlf Hansson { /* end: all zeroes */ },
1108f397c8d8SUlf Hansson };
1109f397c8d8SUlf Hansson
1110f397c8d8SUlf Hansson MODULE_DEVICE_TABLE(sdio, sdio_uart_ids);
1111f397c8d8SUlf Hansson
1112f397c8d8SUlf Hansson static struct sdio_driver sdio_uart_driver = {
1113f397c8d8SUlf Hansson .probe = sdio_uart_probe,
1114f397c8d8SUlf Hansson .remove = sdio_uart_remove,
1115f397c8d8SUlf Hansson .name = "sdio_uart",
1116f397c8d8SUlf Hansson .id_table = sdio_uart_ids,
1117f397c8d8SUlf Hansson };
1118f397c8d8SUlf Hansson
sdio_uart_init(void)1119f397c8d8SUlf Hansson static int __init sdio_uart_init(void)
1120f397c8d8SUlf Hansson {
1121f397c8d8SUlf Hansson int ret;
1122f397c8d8SUlf Hansson struct tty_driver *tty_drv;
1123f397c8d8SUlf Hansson
112439b7b42bSJiri Slaby sdio_uart_tty_driver = tty_drv = tty_alloc_driver(UART_NR,
112539b7b42bSJiri Slaby TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
112639b7b42bSJiri Slaby if (IS_ERR(tty_drv))
112739b7b42bSJiri Slaby return PTR_ERR(tty_drv);
1128f397c8d8SUlf Hansson
1129f397c8d8SUlf Hansson tty_drv->driver_name = "sdio_uart";
1130f397c8d8SUlf Hansson tty_drv->name = "ttySDIO";
1131f397c8d8SUlf Hansson tty_drv->major = 0; /* dynamically allocated */
1132f397c8d8SUlf Hansson tty_drv->minor_start = 0;
1133f397c8d8SUlf Hansson tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
1134f397c8d8SUlf Hansson tty_drv->subtype = SERIAL_TYPE_NORMAL;
1135f397c8d8SUlf Hansson tty_drv->init_termios = tty_std_termios;
1136f397c8d8SUlf Hansson tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
1137f397c8d8SUlf Hansson tty_drv->init_termios.c_ispeed = 4800;
1138f397c8d8SUlf Hansson tty_drv->init_termios.c_ospeed = 4800;
1139f397c8d8SUlf Hansson tty_set_operations(tty_drv, &sdio_uart_ops);
1140f397c8d8SUlf Hansson
1141f397c8d8SUlf Hansson ret = tty_register_driver(tty_drv);
1142f397c8d8SUlf Hansson if (ret)
1143f397c8d8SUlf Hansson goto err1;
1144f397c8d8SUlf Hansson
1145f397c8d8SUlf Hansson ret = sdio_register_driver(&sdio_uart_driver);
1146f397c8d8SUlf Hansson if (ret)
1147f397c8d8SUlf Hansson goto err2;
1148f397c8d8SUlf Hansson
1149f397c8d8SUlf Hansson return 0;
1150f397c8d8SUlf Hansson
1151f397c8d8SUlf Hansson err2:
1152f397c8d8SUlf Hansson tty_unregister_driver(tty_drv);
1153f397c8d8SUlf Hansson err1:
11549f90a4ddSJiri Slaby tty_driver_kref_put(tty_drv);
1155f397c8d8SUlf Hansson return ret;
1156f397c8d8SUlf Hansson }
1157f397c8d8SUlf Hansson
sdio_uart_exit(void)1158f397c8d8SUlf Hansson static void __exit sdio_uart_exit(void)
1159f397c8d8SUlf Hansson {
1160f397c8d8SUlf Hansson sdio_unregister_driver(&sdio_uart_driver);
1161f397c8d8SUlf Hansson tty_unregister_driver(sdio_uart_tty_driver);
11629f90a4ddSJiri Slaby tty_driver_kref_put(sdio_uart_tty_driver);
1163f397c8d8SUlf Hansson }
1164f397c8d8SUlf Hansson
1165f397c8d8SUlf Hansson module_init(sdio_uart_init);
1166f397c8d8SUlf Hansson module_exit(sdio_uart_exit);
1167f397c8d8SUlf Hansson
1168f397c8d8SUlf Hansson MODULE_AUTHOR("Nicolas Pitre");
1169f397c8d8SUlf Hansson MODULE_LICENSE("GPL");
1170