16e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre/*
26e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver
36e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre *
46e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Based on drivers/serial/8250.c and drivers/serial/serial_core.c
56e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * by Russell King.
66e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre *
76e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Author:	Nicolas Pitre
86e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Created:	June 15, 2007
96e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Copyright:	MontaVista Software, Inc.
106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre *
116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * This program is free software; you can redistribute it and/or modify
126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * it under the terms of the GNU General Public License as published by
136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * the Free Software Foundation; either version 2 of the License, or (at
146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * your option) any later version.
156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */
166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre/*
186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Note: Although this driver assumes a 16550A-like UART implementation,
196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * it is not possible to leverage the common 8250/16550 driver, nor the
206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * core UART infrastructure, as they assumes direct access to the hardware
216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * registers, often under a spinlock.  This is not possible in the SDIO
226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * context as SDIO access functions must be able to sleep.
236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre *
246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Because we need to lock the SDIO host to ensure an exclusive access to
256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * the card, we simply rely on that lock to also prevent and serialize
266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * concurrent access to the same port.
276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */
286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/module.h>
306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/init.h>
316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/kernel.h>
324b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox#include <linux/sched.h>
336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mutex.h>
34201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan#include <linux/seq_file.h>
356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/serial_reg.h>
366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/circ_buf.h>
376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/tty.h>
386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/tty_flip.h>
398b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox#include <linux/kfifo.h>
405a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/core.h>
436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/card.h>
446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/sdio_func.h>
456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/sdio_ids.h>
466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define UART_NR		8	/* Number of UARTs this driver can handle */
496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
518b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox#define FIFO_SIZE	PAGE_SIZE
526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define WAKEUP_CHARS	256
536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestruct uart_icount {
556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	cts;
566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	dsr;
576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	rng;
586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	dcd;
596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	rx;
606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	tx;
616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	frame;
626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	overrun;
636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	parity;
646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	__u32	brk;
656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre};
666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestruct sdio_uart_port {
68b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox	struct tty_port		port;
696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct kref		kref;
706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct tty_struct	*tty;
716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int		index;
726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_func	*func;
736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct mutex		func_lock;
7415b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	struct task_struct	*in_sdio_uart_irq;
756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int		regs_offset;
768b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	struct kfifo		xmit_fifo;
776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spinlock_t		write_lock;
786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct uart_icount	icount;
796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int		uartclk;
806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int		mctrl;
814b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	unsigned int		rx_mctrl;
826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int		read_status_mask;
836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int		ignore_status_mask;
846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned char		x_char;
856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned char           ier;
866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned char           lcr;
876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre};
886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct sdio_uart_port *sdio_uart_table[UART_NR];
906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic DEFINE_SPINLOCK(sdio_uart_table_lock);
916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_add_port(struct sdio_uart_port *port)
936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int index, ret = -EBUSY;
956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	kref_init(&port->kref);
976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	mutex_init(&port->func_lock);
986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spin_lock_init(&port->write_lock);
998b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL))
1008b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox		return -ENOMEM;
1016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spin_lock(&sdio_uart_table_lock);
1036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	for (index = 0; index < UART_NR; index++) {
1046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (!sdio_uart_table[index]) {
1056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			port->index = index;
1066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			sdio_uart_table[index] = port;
1076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			ret = 0;
1086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			break;
1096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
1106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
1116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spin_unlock(&sdio_uart_table_lock);
1126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return ret;
1146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
1156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct sdio_uart_port *sdio_uart_port_get(unsigned index)
1176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
1186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port;
1196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (index >= UART_NR)
1216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return NULL;
1226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spin_lock(&sdio_uart_table_lock);
1246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port = sdio_uart_table[index];
1256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (port)
1266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		kref_get(&port->kref);
1276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spin_unlock(&sdio_uart_table_lock);
1286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return port;
1306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
1316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_port_destroy(struct kref *kref)
1336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
1346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port =
1356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		container_of(kref, struct sdio_uart_port, kref);
1368b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	kfifo_free(&port->xmit_fifo);
1376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	kfree(port);
1386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
1396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_port_put(struct sdio_uart_port *port)
1416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
1426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	kref_put(&port->kref, sdio_uart_port_destroy);
1436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
1446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_port_remove(struct sdio_uart_port *port)
1466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
1476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_func *func;
148584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct tty_struct *tty;
1496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	BUG_ON(sdio_uart_table[port->index] != port);
1516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spin_lock(&sdio_uart_table_lock);
1536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_table[port->index] = NULL;
1546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	spin_unlock(&sdio_uart_table_lock);
1556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
1576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * We're killing a port that potentially still is in use by
1586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * the tty layer. Be careful to prevent any further access
1596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * to the SDIO function and arrange for the tty layer to
1606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * give up on that port ASAP.
1616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * Beware: the lock ordering is critical.
1626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
1630a68f64febf365313987c570ad59c9069f61306dAlan Cox	mutex_lock(&port->port.mutex);
1646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	mutex_lock(&port->func_lock);
1656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	func = port->func;
1666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_claim_host(func);
1676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->func = NULL;
1686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	mutex_unlock(&port->func_lock);
169584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	tty = tty_port_tty_get(&port->port);
170584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	/* tty_hangup is async so is this safe as is ?? */
171584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	if (tty) {
172584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox		tty_hangup(tty);
173530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox		tty_kref_put(tty);
174530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	}
1750a68f64febf365313987c570ad59c9069f61306dAlan Cox	mutex_unlock(&port->port.mutex);
1766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_release_irq(func);
1776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_disable_func(func);
1786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_release_host(func);
1796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_port_put(port);
1816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
1826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_claim_func(struct sdio_uart_port *port)
1846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
1856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	mutex_lock(&port->func_lock);
1866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (unlikely(!port->func)) {
1876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		mutex_unlock(&port->func_lock);
1886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return -ENODEV;
1896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
19015b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	if (likely(port->in_sdio_uart_irq != current))
19115b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre		sdio_claim_host(port->func);
1926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	mutex_unlock(&port->func_lock);
1936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return 0;
1946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
1956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
1966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline void sdio_uart_release_func(struct sdio_uart_port *port)
1976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
19815b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	if (likely(port->in_sdio_uart_irq != current))
19915b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre		sdio_release_host(port->func);
2006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
2016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
2036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
2046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned char c;
2056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	c = sdio_readb(port->func, port->regs_offset + offset, NULL);
2066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return c;
2076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
2086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
2106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
2116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_writeb(port->func, value, port->regs_offset + offset, NULL);
2126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
2136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
2156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
2166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned char status;
2176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int ret;
2186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2194b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	/* FIXME: What stops this losing the delta bits and breaking
2204b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	   sdio_uart_check_modem_status ? */
2216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	status = sdio_in(port, UART_MSR);
2226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = 0;
2246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (status & UART_MSR_DCD)
2256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		ret |= TIOCM_CAR;
2266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (status & UART_MSR_RI)
2276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		ret |= TIOCM_RNG;
2286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (status & UART_MSR_DSR)
2296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		ret |= TIOCM_DSR;
2306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (status & UART_MSR_CTS)
2316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		ret |= TIOCM_CTS;
2326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return ret;
2336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
2346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2351e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardostatic void sdio_uart_write_mctrl(struct sdio_uart_port *port,
2361e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo				  unsigned int mctrl)
2376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
2386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned char mcr = 0;
2396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (mctrl & TIOCM_RTS)
2416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		mcr |= UART_MCR_RTS;
2426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (mctrl & TIOCM_DTR)
2436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		mcr |= UART_MCR_DTR;
2446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (mctrl & TIOCM_OUT1)
2456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		mcr |= UART_MCR_OUT1;
2466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (mctrl & TIOCM_OUT2)
2476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		mcr |= UART_MCR_OUT2;
2486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (mctrl & TIOCM_LOOP)
2496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		mcr |= UART_MCR_LOOP;
2506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_MCR, mcr);
2526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
2536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline void sdio_uart_update_mctrl(struct sdio_uart_port *port,
2556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre					  unsigned int set, unsigned int clear)
2566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
2576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int old;
2586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	old = port->mctrl;
2606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->mctrl = (old & ~clear) | set;
2616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (old != port->mctrl)
2626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_write_mctrl(port, port->mctrl);
2636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
2646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define sdio_uart_set_mctrl(port, x)	sdio_uart_update_mctrl(port, x, 0)
2666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define sdio_uart_clear_mctrl(port, x)	sdio_uart_update_mctrl(port, 0, x)
2676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_change_speed(struct sdio_uart_port *port,
2696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				   struct ktermios *termios,
2706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				   struct ktermios *old)
2716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
2726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned char cval, fcr = 0;
2736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int baud, quot;
2746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	switch (termios->c_cflag & CSIZE) {
2766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	case CS5:
2776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		cval = UART_LCR_WLEN5;
2786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		break;
2796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	case CS6:
2806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		cval = UART_LCR_WLEN6;
2816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		break;
2826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	case CS7:
2836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		cval = UART_LCR_WLEN7;
2846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		break;
2856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	default:
2866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	case CS8:
2876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		cval = UART_LCR_WLEN8;
2886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		break;
2896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
2906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (termios->c_cflag & CSTOPB)
2926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		cval |= UART_LCR_STOP;
2936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (termios->c_cflag & PARENB)
2946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		cval |= UART_LCR_PARITY;
2956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!(termios->c_cflag & PARODD))
2966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		cval |= UART_LCR_EPAR;
2976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
2986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	for (;;) {
2996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		baud = tty_termios_baud_rate(termios);
3006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (baud == 0)
3016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			baud = 9600;  /* Special case: B0 rate. */
3026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (baud <= port->uartclk)
3036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			break;
3046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		/*
3056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * Oops, the quotient was zero.  Try again with the old
3066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * baud rate if possible, otherwise default to 9600.
3076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 */
3086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		termios->c_cflag &= ~CBAUD;
3096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (old) {
3106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			termios->c_cflag |= old->c_cflag & CBAUD;
3116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			old = NULL;
3126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		} else
3136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			termios->c_cflag |= B9600;
3146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
3156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	quot = (2 * port->uartclk + baud) / (2 * baud);
3166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (baud < 2400)
3186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
3196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	else
3206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
3216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
3236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (termios->c_iflag & INPCK)
3246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
3256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (termios->c_iflag & (BRKINT | PARMRK))
3266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->read_status_mask |= UART_LSR_BI;
3276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
3296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * Characters to ignore
3306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
3316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->ignore_status_mask = 0;
3326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (termios->c_iflag & IGNPAR)
3336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
3346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (termios->c_iflag & IGNBRK) {
3356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->ignore_status_mask |= UART_LSR_BI;
3366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		/*
3376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * If we're ignoring parity and break indicators,
3386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * ignore overruns too (for real raw support).
3396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 */
3406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (termios->c_iflag & IGNPAR)
3416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			port->ignore_status_mask |= UART_LSR_OE;
3426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
3436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
3456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * ignore all characters if CREAD is not set
3466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
3476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if ((termios->c_cflag & CREAD) == 0)
3486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->ignore_status_mask |= UART_LSR_DR;
3496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
3516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * CTS flow control flag and modem status interrupts
3526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
3536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->ier &= ~UART_IER_MSI;
3546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))
3556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->ier |= UART_IER_MSI;
3566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->lcr = cval;
3586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_IER, port->ier);
3606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_LCR, cval | UART_LCR_DLAB);
3616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_DLL, quot & 0xff);
3626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_DLM, quot >> 8);
3636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_LCR, cval);
3646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_FCR, fcr);
3656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_write_mctrl(port, port->mctrl);
3676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
3686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_start_tx(struct sdio_uart_port *port)
3706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
3716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!(port->ier & UART_IER_THRI)) {
3726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->ier |= UART_IER_THRI;
3736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_out(port, UART_IER, port->ier);
3746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
3756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
3766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_stop_tx(struct sdio_uart_port *port)
3786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
3796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (port->ier & UART_IER_THRI) {
3806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->ier &= ~UART_IER_THRI;
3816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_out(port, UART_IER, port->ier);
3826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
3836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
3846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_stop_rx(struct sdio_uart_port *port)
3866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
3876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->ier &= ~UART_IER_RLSI;
3886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->read_status_mask &= ~UART_LSR_DR;
3896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_IER, port->ier);
3906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
3916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3921e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardostatic void sdio_uart_receive_chars(struct sdio_uart_port *port,
3931e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo				    unsigned int *status)
3946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
395530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	struct tty_struct *tty = tty_port_tty_get(&port->port);
3966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int ch, flag;
3976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int max_count = 256;
3986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
3996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	do {
4006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		ch = sdio_in(port, UART_RX);
4016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		flag = TTY_NORMAL;
4026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->icount.rx++;
4036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
4051e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo					UART_LSR_FE | UART_LSR_OE))) {
4066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			/*
4076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			 * For statistics only
4086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			 */
4096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			if (*status & UART_LSR_BI) {
4106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				*status &= ~(UART_LSR_FE | UART_LSR_PE);
4116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				port->icount.brk++;
4126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			} else if (*status & UART_LSR_PE)
4136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				port->icount.parity++;
4146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			else if (*status & UART_LSR_FE)
4156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				port->icount.frame++;
4166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			if (*status & UART_LSR_OE)
4176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				port->icount.overrun++;
4186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			/*
4206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			 * Mask off conditions which should be ignored.
4216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			 */
4226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			*status &= port->read_status_mask;
4231e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo			if (*status & UART_LSR_BI)
4246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				flag = TTY_BREAK;
4251e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo			else if (*status & UART_LSR_PE)
4266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				flag = TTY_PARITY;
4276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			else if (*status & UART_LSR_FE)
4286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				flag = TTY_FRAME;
4296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
4306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
432530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox			if (tty)
433530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox				tty_insert_flip_char(tty, ch, flag);
4346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		/*
4366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * Overrun is special.  Since it's reported immediately,
4376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * it doesn't affect the current character.
4386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 */
4396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (*status & ~port->ignore_status_mask & UART_LSR_OE)
440530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox			if (tty)
441530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox				tty_insert_flip_char(tty, 0, TTY_OVERRUN);
4426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		*status = sdio_in(port, UART_LSR);
4446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
445530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	if (tty) {
446530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox		tty_flip_buffer_push(tty);
447530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox		tty_kref_put(tty);
448530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	}
4496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
4506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_transmit_chars(struct sdio_uart_port *port)
4526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
4538b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	struct kfifo *xmit = &port->xmit_fifo;
4546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int count;
455530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	struct tty_struct *tty;
4568b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	u8 iobuf[16];
4578b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	int len;
4586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (port->x_char) {
4606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_out(port, UART_TX, port->x_char);
4616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->icount.tx++;
4626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->x_char = 0;
4636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
4646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
465530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox
466530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	tty = tty_port_tty_get(&port->port);
467530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox
4688b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	if (tty == NULL || !kfifo_len(xmit) ||
469c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox				tty->stopped || tty->hw_stopped) {
4706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_stop_tx(port);
471530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox		tty_kref_put(tty);
4726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
4736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
4746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4758b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock);
4768b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	for (count = 0; count < len; count++) {
4778b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox		sdio_out(port, UART_TX, iobuf[count]);
4786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->icount.tx++;
4798b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	}
4806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4818b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	len = kfifo_len(xmit);
4828b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	if (len < WAKEUP_CHARS) {
483b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox		tty_wakeup(tty);
4848b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox		if (len == 0)
4858b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox			sdio_uart_stop_tx(port);
4868b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	}
487530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	tty_kref_put(tty);
4886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
4896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_check_modem_status(struct sdio_uart_port *port)
4916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
4926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int status;
493530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox	struct tty_struct *tty;
4946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	status = sdio_in(port, UART_MSR);
4966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
4976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if ((status & UART_MSR_ANY_DELTA) == 0)
4986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
4996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
5006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (status & UART_MSR_TERI)
5016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->icount.rng++;
5026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (status & UART_MSR_DDSR)
5036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->icount.dsr++;
5044b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	if (status & UART_MSR_DDCD) {
5056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->icount.dcd++;
5064b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox		/* DCD raise - wake for open */
5074b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox		if (status & UART_MSR_DCD)
5084b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox			wake_up_interruptible(&port->port.open_wait);
5094b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox		else {
5104b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox			/* DCD drop - hang up if tty attached */
5114b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox			tty = tty_port_tty_get(&port->port);
5124b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox			if (tty) {
5134b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox				tty_hangup(tty);
5144b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox				tty_kref_put(tty);
5154b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox			}
5164b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox		}
5174b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	}
5186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (status & UART_MSR_DCTS) {
5196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->icount.cts++;
520530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox		tty = tty_port_tty_get(&port->port);
521530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox		if (tty && (tty->termios->c_cflag & CRTSCTS)) {
5226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			int cts = (status & UART_MSR_CTS);
523b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox			if (tty->hw_stopped) {
5246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				if (cts) {
525b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox					tty->hw_stopped = 0;
5266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre					sdio_uart_start_tx(port);
527b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox					tty_wakeup(tty);
5286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				}
5296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			} else {
5306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				if (!cts) {
531b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox					tty->hw_stopped = 1;
5326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre					sdio_uart_stop_tx(port);
5336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				}
5346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			}
5356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
536530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox		tty_kref_put(tty);
5376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
5386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
5396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
5406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre/*
5416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * This handles the interrupt from one port.
5426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */
5436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_irq(struct sdio_func *func)
5446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
5456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = sdio_get_drvdata(func);
5466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int iir, lsr;
5476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
54815b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	/*
54915b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	 * In a few places sdio_uart_irq() is called directly instead of
55015b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	 * waiting for the actual interrupt to be raised and the SDIO IRQ
55115b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	 * thread scheduled in order to reduce latency.  However, some
55215b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	 * interaction with the tty core may end up calling us back
55315b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	 * (serial echo, flow control, etc.) through those same places
55415b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	 * causing undesirable effects.  Let's stop the recursion here.
55515b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	 */
55615b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	if (unlikely(port->in_sdio_uart_irq == current))
55715b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre		return;
55815b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre
5596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	iir = sdio_in(port, UART_IIR);
5606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (iir & UART_IIR_NO_INT)
5616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
56215b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre
56315b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	port->in_sdio_uart_irq = current;
5646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	lsr = sdio_in(port, UART_LSR);
5656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (lsr & UART_LSR_DR)
5666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_receive_chars(port, &lsr);
5676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_check_modem_status(port);
5686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (lsr & UART_LSR_THRE)
5696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_transmit_chars(port);
57015b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre	port->in_sdio_uart_irq = NULL;
5716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
5726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
5734b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Coxstatic int uart_carrier_raised(struct tty_port *tport)
5744b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox{
5754b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	struct sdio_uart_port *port =
5764b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox			container_of(tport, struct sdio_uart_port, port);
5774b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	unsigned int ret = sdio_uart_claim_func(port);
578c9404c9c392d557a4687c4cbda022b03cb787ce9Adam Buchbinder	if (ret)	/* Missing hardware shouldn't block for carrier */
5794b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox		return 1;
5804b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	ret = sdio_uart_get_mctrl(port);
5814b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	sdio_uart_release_func(port);
5824b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	if (ret & TIOCM_CAR)
5834b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox		return 1;
5844b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	return 0;
5854b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox}
5864b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox
587584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/**
588584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	uart_dtr_rts		-	 port helper to set uart signals
589584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@tport: tty port to be updated
590584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@onoff: set to turn on DTR/RTS
591584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *
592584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	Called by the tty port helpers when the modem signals need to be
593584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	adjusted during an open, close and hangup.
594584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */
595584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox
596584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void uart_dtr_rts(struct tty_port *tport, int onoff)
5976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
598584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct sdio_uart_port *port =
599584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox			container_of(tport, struct sdio_uart_port, port);
6001f100b323d19469b06a63ccd6130ed71760145ccAlan Cox	int ret = sdio_uart_claim_func(port);
6011f100b323d19469b06a63ccd6130ed71760145ccAlan Cox	if (ret)
6021f100b323d19469b06a63ccd6130ed71760145ccAlan Cox		return;
603584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	if (onoff == 0)
604584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox		sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
605584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	else
606584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox		sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
6071f100b323d19469b06a63ccd6130ed71760145ccAlan Cox	sdio_uart_release_func(port);
608584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox}
609530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox
610584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/**
611584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	sdio_uart_activate	-	start up hardware
612584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@tport: tty port to activate
613584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@tty: tty bound to this port
614584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *
615584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	Activate a tty port. The port locking guarantees us this will be
616584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	run exactly once per set of opens, and if successful will see the
617584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	shutdown method run exactly once to match. Start up and shutdown are
618584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	protected from each other by the internal locking and will not run
619584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	at the same time even during a hangup event.
620584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *
621584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	If we successfully start up the port we take an extra kref as we
622584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	will keep it around until shutdown when the kref is dropped.
623584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */
624584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox
625584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
626584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{
627584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct sdio_uart_port *port =
628584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox			container_of(tport, struct sdio_uart_port, port);
629584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	int ret;
6306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
6326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * Set the TTY IO error marker - we will only clear this
6336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * once we have successfully opened the port.
6346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
635b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox	set_bit(TTY_IO_ERROR, &tty->flags);
6366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6378b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	kfifo_reset(&port->xmit_fifo);
6386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = sdio_uart_claim_func(port);
6406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ret)
6418b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox		return ret;
6426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = sdio_enable_func(port->func);
6436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ret)
6448b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox		goto err1;
6456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = sdio_claim_irq(port->func, sdio_uart_irq);
6466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ret)
6478b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox		goto err2;
6486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
6506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * Clear the FIFO buffers and disable them.
6516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * (they will be reenabled in sdio_change_speed())
6526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
6536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
6546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
6551e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo		       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
6566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_FCR, 0);
6576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
6596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * Clear the interrupt registers.
6606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
6616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	(void) sdio_in(port, UART_LSR);
6626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	(void) sdio_in(port, UART_RX);
6636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	(void) sdio_in(port, UART_IIR);
6646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	(void) sdio_in(port, UART_MSR);
6656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/*
6676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 * Now, initialize the UART
6686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	 */
6696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_LCR, UART_LCR_WLEN8);
6706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
671c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox	port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
6726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->mctrl = TIOCM_OUT2;
6736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
674b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox	sdio_uart_change_speed(port, tty->termios, NULL);
6756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
676b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox	if (tty->termios->c_cflag & CBAUD)
6776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
6786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
679b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox	if (tty->termios->c_cflag & CRTSCTS)
6806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
681b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox			tty->hw_stopped = 1;
6826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6830395b48c78ed822f251ab15d0fbc3ce06f41ffb1Nicolas Pitre	clear_bit(TTY_IO_ERROR, &tty->flags);
6846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/* Kick the IRQ handler once while we're still holding the host lock */
6866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_irq(port->func);
6876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_release_func(port);
6896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return 0;
6906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
6916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr2:
6928b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	sdio_disable_func(port->func);
6936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr1:
6948b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	sdio_uart_release_func(port);
6956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return ret;
6966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
6976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
698584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/**
699584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	sdio_uart_shutdown	-	stop hardware
700584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@tport: tty port to shut down
701584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *
702584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	Deactivate a tty port. The port locking guarantees us this will be
703584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	run only if a successful matching activate already ran. The two are
704584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	protected from each other by the internal locking and will not run
705584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	at the same time even during a hangup event.
706584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */
707584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox
708584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_shutdown(struct tty_port *tport)
7096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
710584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct sdio_uart_port *port =
711584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox			container_of(tport, struct sdio_uart_port, port);
7126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int ret;
7136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
7146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = sdio_uart_claim_func(port);
7156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ret)
7168b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox		return;
7176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
7186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_stop_rx(port);
7196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
7201e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo	/* Disable interrupts from this port */
7216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_release_irq(port->func);
7226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->ier = 0;
7236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_IER, 0);
7246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
7256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_clear_mctrl(port, TIOCM_OUT2);
7266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
7276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/* Disable break condition and FIFOs. */
7286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->lcr &= ~UART_LCR_SBC;
7296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_LCR, port->lcr);
7306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
7316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				 UART_FCR_CLEAR_RCVR |
7326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				 UART_FCR_CLEAR_XMIT);
7336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_FCR, 0);
7346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
7356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_disable_func(port->func);
7366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
7376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_release_func(port);
7386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
7396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
740584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/**
741584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	sdio_uart_install	-	install method
742584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@driver: the driver in use (sdio_uart in our case)
743584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@tty: the tty being bound
744584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *
745584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	Look up and bind the tty and the driver together. Initialize
746584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	any needed private data (in our case the termios)
747584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */
7486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
749584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
750584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{
751584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	int idx = tty->index;
752584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct sdio_uart_port *port = sdio_uart_port_get(idx);
75381f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby	int ret = tty_standard_install(driver, tty);
754584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox
75581f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby	if (ret == 0)
756584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox		/* This is the ref sdio_uart_port get provided */
757584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox		tty->driver_data = port;
75881f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby	else
7596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_port_put(port);
760584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	return ret;
7616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
7626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
763584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/**
764584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	sdio_uart_cleanup	-	called on the last tty kref drop
765584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	@tty: the tty being destroyed
766584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *
767584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	Called asynchronously when the last reference to the tty is dropped.
768584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	We cannot destroy the tty->driver_data port kref until this point
769584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */
770584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox
771584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_cleanup(struct tty_struct *tty)
7726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
7736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
774584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	tty->driver_data = NULL;	/* Bug trap */
775584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	sdio_uart_port_put(port);
776584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox}
7776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
778584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/*
779584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox *	Open/close/hangup is now entirely boilerplate
780584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */
7816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
782584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic int sdio_uart_open(struct tty_struct *tty, struct file *filp)
783584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{
784584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct sdio_uart_port *port = tty->driver_data;
785584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	return tty_port_open(&port->port, tty, filp);
786584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox}
7876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
788584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_close(struct tty_struct *tty, struct file * filp)
789584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{
790584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct sdio_uart_port *port = tty->driver_data;
791584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	tty_port_close(&port->port, tty, filp);
792584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox}
7936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
794584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_hangup(struct tty_struct *tty)
795584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{
796584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	struct sdio_uart_port *port = tty->driver_data;
797584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	tty_port_hangup(&port->port);
7986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
7996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
800c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Coxstatic int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
8016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			   int count)
8026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
8036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
8048b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	int ret;
8056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!port->func)
8076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return -ENODEV;
8086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8098b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock);
810c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox	if (!(port->ier & UART_IER_THRI)) {
8116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		int err = sdio_uart_claim_func(port);
8126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (!err) {
8136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			sdio_uart_start_tx(port);
8146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			sdio_uart_irq(port->func);
8156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			sdio_uart_release_func(port);
8166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		} else
8176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			ret = err;
8186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
8196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return ret;
8216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
8226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_write_room(struct tty_struct *tty)
8246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
8256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
8268b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
8276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
8286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_chars_in_buffer(struct tty_struct *tty)
8306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
8316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
8328b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox	return kfifo_len(&port->xmit_fifo);
8336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
8346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
8366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
8376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
8386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->x_char = ch;
8406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ch && !(port->ier & UART_IER_THRI)) {
8416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (sdio_uart_claim_func(port) != 0)
8426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			return;
8436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_start_tx(port);
8446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_irq(port->func);
8456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_release_func(port);
8466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
8476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
8486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_throttle(struct tty_struct *tty)
8506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
8516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
8526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
8546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
8556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (sdio_uart_claim_func(port) != 0)
8576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
8586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (I_IXOFF(tty)) {
8606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->x_char = STOP_CHAR(tty);
8616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_start_tx(port);
8626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
8636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (tty->termios->c_cflag & CRTSCTS)
8656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_clear_mctrl(port, TIOCM_RTS);
8666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_irq(port->func);
8686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_release_func(port);
8696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
8706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_unthrottle(struct tty_struct *tty)
8726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
8736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
8746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
8766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
8776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (sdio_uart_claim_func(port) != 0)
8796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
8806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (I_IXOFF(tty)) {
8826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (port->x_char) {
8836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			port->x_char = 0;
8846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		} else {
8856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			port->x_char = START_CHAR(tty);
8866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			sdio_uart_start_tx(port);
8876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
8886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
8896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (tty->termios->c_cflag & CRTSCTS)
8916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_set_mctrl(port, TIOCM_RTS);
8926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
8936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_irq(port->func);
8946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_release_func(port);
8956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
8966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
897c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Coxstatic void sdio_uart_set_termios(struct tty_struct *tty,
898c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox						struct ktermios *old_termios)
8996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
9006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
9016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	unsigned int cflag = tty->termios->c_cflag;
9026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (sdio_uart_claim_func(port) != 0)
9046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return;
9056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_change_speed(port, tty->termios, old_termios);
9076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/* Handle transition to B0 status */
9096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
9106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR);
9116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/* Handle transition away from B0 status */
9136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
9146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		unsigned int mask = TIOCM_DTR;
9156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
9166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			mask |= TIOCM_RTS;
9176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_set_mctrl(port, mask);
9186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
9196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/* Handle turning off CRTSCTS */
9216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
9226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		tty->hw_stopped = 0;
9236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_start_tx(port);
9246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
9256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	/* Handle turning on CRTSCTS */
9276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
9286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) {
9296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			tty->hw_stopped = 1;
9306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			sdio_uart_stop_tx(port);
9316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
9326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
9336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_release_func(port);
9356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
9366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
937c43d8636971c39da993e94082fd65bfff421618eDavid Howellsstatic int sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
9386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
9396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
940c43d8636971c39da993e94082fd65bfff421618eDavid Howells	int result;
9416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
942c43d8636971c39da993e94082fd65bfff421618eDavid Howells	result = sdio_uart_claim_func(port);
943c43d8636971c39da993e94082fd65bfff421618eDavid Howells	if (result != 0)
944c43d8636971c39da993e94082fd65bfff421618eDavid Howells		return result;
9456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (break_state == -1)
9476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->lcr |= UART_LCR_SBC;
9486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	else
9496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->lcr &= ~UART_LCR_SBC;
9506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_out(port, UART_LCR, port->lcr);
9516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_release_func(port);
953c43d8636971c39da993e94082fd65bfff421618eDavid Howells	return 0;
9546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
9556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
95660b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int sdio_uart_tiocmget(struct tty_struct *tty)
9576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
9586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
9596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int result;
9606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	result = sdio_uart_claim_func(port);
9626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!result) {
9636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		result = port->mctrl | sdio_uart_get_mctrl(port);
9646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_release_func(port);
9656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
9666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return result;
9686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
9696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
97020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int sdio_uart_tiocmset(struct tty_struct *tty,
9716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			      unsigned int set, unsigned int clear)
9726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
9736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = tty->driver_data;
9746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int result;
9756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9761e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo	result = sdio_uart_claim_func(port);
977c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox	if (!result) {
9786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_update_mctrl(port, set, clear);
9796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		sdio_uart_release_func(port);
9806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
9816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
9826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return result;
9836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
9846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
985201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyanstatic int sdio_uart_proc_show(struct seq_file *m, void *v)
9865ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre{
987201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	int i;
9885ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre
989201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
9905ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre		       "", "", "");
991201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	for (i = 0; i < UART_NR; i++) {
9925ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre		struct sdio_uart_port *port = sdio_uart_port_get(i);
9935ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre		if (port) {
994201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan			seq_printf(m, "%d: uart:SDIO", i);
995c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox			if (capable(CAP_SYS_ADMIN)) {
996201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan				seq_printf(m, " tx:%d rx:%d",
9971e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo					      port->icount.tx, port->icount.rx);
9985ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.frame)
999201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " fe:%d",
10001e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.frame);
10015ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.parity)
1002201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " pe:%d",
10031e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.parity);
10045ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.brk)
1005201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " brk:%d",
10061e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.brk);
10075ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.overrun)
1008201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " oe:%d",
10091e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.overrun);
10105ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.cts)
1011201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " cts:%d",
10121e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.cts);
10135ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.dsr)
1014201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " dsr:%d",
10151e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.dsr);
10165ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.rng)
1017201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " rng:%d",
10181e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.rng);
10195ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre				if (port->icount.dcd)
1020201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan					seq_printf(m, " dcd:%d",
10211e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo						      port->icount.dcd);
10225ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre			}
10235ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre			sdio_uart_port_put(port);
1024201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan			seq_putc(m, '\n');
10255ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre		}
10265ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre	}
1027201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	return 0;
1028201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan}
10295ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre
1030201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyanstatic int sdio_uart_proc_open(struct inode *inode, struct file *file)
1031201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan{
1032201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	return single_open(file, sdio_uart_proc_show, NULL);
10335ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre}
10345ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre
1035201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyanstatic const struct file_operations sdio_uart_proc_fops = {
1036201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	.owner		= THIS_MODULE,
1037201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	.open		= sdio_uart_proc_open,
1038201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	.read		= seq_read,
1039201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	.llseek		= seq_lseek,
1040201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	.release	= single_release,
1041201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan};
1042201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan
1043584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic const struct tty_port_operations sdio_uart_port_ops = {
1044584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	.dtr_rts = uart_dtr_rts,
10454b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox	.carrier_raised = uart_carrier_raised,
1046584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	.shutdown = sdio_uart_shutdown,
1047584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	.activate = sdio_uart_activate,
1048584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox};
1049584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox
10506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic const struct tty_operations sdio_uart_ops = {
10516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.open			= sdio_uart_open,
10526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.close			= sdio_uart_close,
10536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.write			= sdio_uart_write,
10546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.write_room		= sdio_uart_write_room,
10556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.chars_in_buffer	= sdio_uart_chars_in_buffer,
10566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.send_xchar		= sdio_uart_send_xchar,
10576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.throttle		= sdio_uart_throttle,
10586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.unthrottle		= sdio_uart_unthrottle,
10596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.set_termios		= sdio_uart_set_termios,
1060584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	.hangup			= sdio_uart_hangup,
10616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.break_ctl		= sdio_uart_break_ctl,
10626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.tiocmget		= sdio_uart_tiocmget,
10636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.tiocmset		= sdio_uart_tiocmset,
1064584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	.install		= sdio_uart_install,
1065584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	.cleanup		= sdio_uart_cleanup,
1066201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan	.proc_fops		= &sdio_uart_proc_fops,
10676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre};
10686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
10696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct tty_driver *sdio_uart_tty_driver;
10706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
10716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_probe(struct sdio_func *func,
10726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			   const struct sdio_device_id *id)
10736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
10746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port;
10756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int ret;
10766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
10776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL);
10786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!port)
10796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return -ENOMEM;
10806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
10816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (func->class == SDIO_CLASS_UART) {
1082a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S		pr_warning("%s: need info on UART class basic setup\n",
10836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		       sdio_func_id(func));
10846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		kfree(port);
10856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return -ENOSYS;
10866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	} else if (func->class == SDIO_CLASS_GPS) {
10876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		/*
10886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * We need tuple 0x91.  It contains SUBTPL_SIOREG
10896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 * and SUBTPL_RCVCAPS.
10906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		 */
10916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		struct sdio_func_tuple *tpl;
10926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		for (tpl = func->tuples; tpl; tpl = tpl->next) {
10936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			if (tpl->code != 0x91)
10946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				continue;
10956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			if (tpl->size < 10)
10966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				continue;
10976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			if (tpl->data[1] == 0)  /* SUBTPL_SIOREG */
10986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				break;
10996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
11006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (!tpl) {
1101a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S			pr_warning(
1102c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox       "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
11036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			       sdio_func_id(func));
11046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			kfree(port);
11056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			return -EINVAL;
11066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
1107a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S		pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
11086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		       sdio_func_id(func), tpl->data[2], tpl->data[3]);
11096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->regs_offset = (tpl->data[4] << 0) |
11106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				    (tpl->data[5] << 8) |
11116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre				    (tpl->data[6] << 16);
1112a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S		pr_debug("%s: regs offset = 0x%x\n",
11136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		       sdio_func_id(func), port->regs_offset);
11146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		port->uartclk = tpl->data[7] * 115200;
11156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (port->uartclk == 0)
11166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			port->uartclk = 115200;
1117a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S		pr_debug("%s: clk %d baudcode %u 4800-div %u\n",
11186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		       sdio_func_id(func), port->uartclk,
11196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		       tpl->data[7], tpl->data[8] | (tpl->data[9] << 8));
11206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	} else {
11216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		kfree(port);
11226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return -EINVAL;
11236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
11246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	port->func = func;
11266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_set_drvdata(func, port);
1127b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox	tty_port_init(&port->port);
1128584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox	port->port.ops = &sdio_uart_port_ops;
11296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = sdio_uart_add_port(port);
11316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ret) {
11326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		kfree(port);
11336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	} else {
11346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		struct device *dev;
1135c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox		dev = tty_register_device(sdio_uart_tty_driver,
1136c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox						port->index, &func->dev);
11376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		if (IS_ERR(dev)) {
11386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			sdio_uart_port_remove(port);
11396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre			ret = PTR_ERR(dev);
11406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		}
11416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	}
11426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return ret;
11446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
11456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_remove(struct sdio_func *func)
11476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
11486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct sdio_uart_port *port = sdio_get_drvdata(func);
11496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_unregister_device(sdio_uart_tty_driver, port->index);
11516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_port_remove(port);
11526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
11536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic const struct sdio_device_id sdio_uart_ids[] = {
11556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	{ SDIO_DEVICE_CLASS(SDIO_CLASS_UART)		},
11566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	{ SDIO_DEVICE_CLASS(SDIO_CLASS_GPS)		},
11576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	{ /* end: all zeroes */				},
11586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre};
11596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas PitreMODULE_DEVICE_TABLE(sdio, sdio_uart_ids);
11616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct sdio_driver sdio_uart_driver = {
11636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.probe		= sdio_uart_probe,
11646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.remove		= sdio_uart_remove,
11656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.name		= "sdio_uart",
11666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	.id_table	= sdio_uart_ids,
11676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre};
11686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int __init sdio_uart_init(void)
11706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
11716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	int ret;
11726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	struct tty_driver *tty_drv;
11736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);
11756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (!tty_drv)
11766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		return -ENOMEM;
11776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->driver_name = "sdio_uart";
11796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->name =   "ttySDIO";
11806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->major = 0;  /* dynamically allocated */
11816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->minor_start = 0;
11826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
11836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->subtype = SERIAL_TYPE_NORMAL;
11846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
11856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->init_termios = tty_std_termios;
11866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
11872ba30eedec37e2f65babf4ea54233f98afbe0871Nicolas Pitre	tty_drv->init_termios.c_ispeed = 4800;
11882ba30eedec37e2f65babf4ea54233f98afbe0871Nicolas Pitre	tty_drv->init_termios.c_ospeed = 4800;
11896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_set_operations(tty_drv, &sdio_uart_ops);
11906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = tty_register_driver(tty_drv);
11926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ret)
11936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		goto err1;
11946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	ret = sdio_register_driver(&sdio_uart_driver);
11966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	if (ret)
11976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre		goto err2;
11986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
11996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return 0;
12006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
12016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr2:
12026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_unregister_driver(tty_drv);
12036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr1:
12046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	put_tty_driver(tty_drv);
12056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	return ret;
12066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
12076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
12086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void __exit sdio_uart_exit(void)
12096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{
12106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	sdio_unregister_driver(&sdio_uart_driver);
12116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	tty_unregister_driver(sdio_uart_tty_driver);
12126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre	put_tty_driver(sdio_uart_tty_driver);
12136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}
12146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
12156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitremodule_init(sdio_uart_init);
12166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitremodule_exit(sdio_uart_exit);
12176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre
12186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas PitreMODULE_AUTHOR("Nicolas Pitre");
12196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas PitreMODULE_LICENSE("GPL");
1220