Merge tag 'tty-3.3-rc3' tty-next
This is needed to handle the 8250 file merge mess properly for future patches. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
commit
5a22e30def
|
@ -0,0 +1,14 @@
|
|||
* Energymicro efm32 UART
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "efm32,uart"
|
||||
- reg : Address and length of the register set
|
||||
- interrupts : Should contain uart interrupt
|
||||
|
||||
Example:
|
||||
|
||||
uart@0x4000c400 {
|
||||
compatible = "efm32,uart";
|
||||
reg = <0x4000c400 0x400>;
|
||||
interrupts = <15>;
|
||||
};
|
|
@ -1015,14 +1015,11 @@ capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
{
|
||||
int idx = tty->index;
|
||||
struct capiminor *mp = capiminor_get(idx);
|
||||
int ret = tty_init_termios(tty);
|
||||
int ret = tty_standard_install(driver, tty);
|
||||
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
if (ret == 0)
|
||||
tty->driver_data = mp;
|
||||
driver->ttys[idx] = tty;
|
||||
} else
|
||||
else
|
||||
capiminor_put(mp);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -481,13 +481,9 @@ static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
{
|
||||
int idx = tty->index;
|
||||
struct pti_tty *pti_tty_data;
|
||||
int ret = tty_init_termios(tty);
|
||||
int ret = tty_standard_install(driver, tty);
|
||||
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[idx] = tty;
|
||||
|
||||
pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
|
||||
if (pti_tty_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -750,15 +750,12 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
{
|
||||
int idx = tty->index;
|
||||
struct sdio_uart_port *port = sdio_uart_port_get(idx);
|
||||
int ret = tty_init_termios(tty);
|
||||
int ret = tty_standard_install(driver, tty);
|
||||
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
if (ret == 0)
|
||||
/* This is the ref sdio_uart_port get provided */
|
||||
tty->driver_data = port;
|
||||
driver->ttys[idx] = tty;
|
||||
} else
|
||||
else
|
||||
sdio_uart_port_put(port);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ static int __init hvc_beat_init(void)
|
|||
if (!firmware_has_feature(FW_FEATURE_BEAT))
|
||||
return -ENODEV;
|
||||
|
||||
hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
|
||||
hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
|
||||
if (IS_ERR(hp))
|
||||
return PTR_ERR(hp);
|
||||
hvc_beat_dev = hp;
|
||||
|
|
|
@ -94,7 +94,7 @@ static int __init hvc_rtas_init(void)
|
|||
|
||||
/* Allocate an hvc_struct for the console device we instantiated
|
||||
* earlier. Save off hp so that we can return it on exit */
|
||||
hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
|
||||
hp = hvc_alloc(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops, 16);
|
||||
if (IS_ERR(hp))
|
||||
return PTR_ERR(hp);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ static int __init hvc_udbg_init(void)
|
|||
|
||||
BUG_ON(hvc_udbg_dev);
|
||||
|
||||
hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
|
||||
hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16);
|
||||
if (IS_ERR(hp))
|
||||
return PTR_ERR(hp);
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ static int __init xen_hvc_init(void)
|
|||
xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
|
||||
}
|
||||
if (xencons_irq < 0)
|
||||
xencons_irq = 0; /* NO_IRQ */
|
||||
xencons_irq = 0;
|
||||
else
|
||||
irq_set_noprobe(xencons_irq);
|
||||
|
||||
|
|
|
@ -1203,7 +1203,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
|||
{
|
||||
struct hvcs_struct *hvcsd;
|
||||
unsigned long flags;
|
||||
int irq = NO_IRQ;
|
||||
int irq;
|
||||
|
||||
/*
|
||||
* Is someone trying to close the file associated with this device after
|
||||
|
@ -1264,7 +1264,7 @@ static void hvcs_hangup(struct tty_struct * tty)
|
|||
struct hvcs_struct *hvcsd = tty->driver_data;
|
||||
unsigned long flags;
|
||||
int temp_open_count;
|
||||
int irq = NO_IRQ;
|
||||
int irq;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
/* Preserve this so that we know how many kref refs to put */
|
||||
|
|
|
@ -1237,7 +1237,7 @@ static int __init hvsi_console_init(void)
|
|||
hp->state = HVSI_CLOSED;
|
||||
hp->vtermno = *vtermno;
|
||||
hp->virq = irq_create_mapping(NULL, irq[0]);
|
||||
if (hp->virq == NO_IRQ) {
|
||||
if (hp->virq == 0) {
|
||||
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
|
||||
__func__, irq[0]);
|
||||
continue;
|
||||
|
|
|
@ -1602,13 +1602,9 @@ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
int ret;
|
||||
if (!port || !dc || dc->state != NOZOMI_STATE_READY)
|
||||
return -ENODEV;
|
||||
ret = tty_init_termios(tty);
|
||||
if (ret == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
ret = tty_standard_install(driver, tty);
|
||||
if (ret == 0)
|
||||
tty->driver_data = port;
|
||||
driver->ttys[tty->index] = tty;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/major.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
|
@ -55,11 +54,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
|||
wake_up_interruptible(&tty->link->write_wait);
|
||||
if (tty->driver->subtype == PTY_TYPE_MASTER) {
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->flags);
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
if (tty->driver == ptm_driver)
|
||||
devpts_pty_kill(tty->link);
|
||||
#endif
|
||||
tty_unlock();
|
||||
devpts_pty_kill(tty->link);
|
||||
tty_vhangup(tty->link);
|
||||
tty_lock();
|
||||
}
|
||||
|
@ -439,55 +435,9 @@ static inline void legacy_pty_init(void) { }
|
|||
|
||||
/* Unix98 devices */
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
/*
|
||||
* sysctl support for setting limits on the number of Unix98 ptys allocated.
|
||||
* Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
|
||||
*/
|
||||
int pty_limit = NR_UNIX98_PTY_DEFAULT;
|
||||
static int pty_limit_min;
|
||||
static int pty_limit_max = NR_UNIX98_PTY_MAX;
|
||||
static int pty_count;
|
||||
|
||||
static struct cdev ptmx_cdev;
|
||||
|
||||
static struct ctl_table pty_table[] = {
|
||||
{
|
||||
.procname = "max",
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.data = &pty_limit,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &pty_limit_min,
|
||||
.extra2 = &pty_limit_max,
|
||||
}, {
|
||||
.procname = "nr",
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0444,
|
||||
.data = &pty_count,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct ctl_table pty_kern_table[] = {
|
||||
{
|
||||
.procname = "pty",
|
||||
.mode = 0555,
|
||||
.child = pty_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct ctl_table pty_root_table[] = {
|
||||
{
|
||||
.procname = "kernel",
|
||||
.mode = 0555,
|
||||
.child = pty_kern_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
static int pty_unix98_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
@ -515,10 +465,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
|
|||
static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
|
||||
struct inode *ptm_inode, int idx)
|
||||
{
|
||||
struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
|
||||
if (tty)
|
||||
tty = tty->link;
|
||||
return tty;
|
||||
/* Master must be open via /dev/ptmx */
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -589,7 +537,6 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
*/
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
pty_count++;
|
||||
return 0;
|
||||
err_free_mem:
|
||||
deinitialize_tty_struct(o_tty);
|
||||
|
@ -603,7 +550,6 @@ err_free_tty:
|
|||
|
||||
static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
pty_count--;
|
||||
}
|
||||
|
||||
static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
|
@ -667,9 +613,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||
return retval;
|
||||
|
||||
/* find a device that is not in use. */
|
||||
tty_lock();
|
||||
index = devpts_new_index(inode);
|
||||
tty_unlock();
|
||||
if (index < 0) {
|
||||
retval = index;
|
||||
goto err_file;
|
||||
|
@ -677,7 +621,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
tty = tty_init_dev(ptm_driver, index, 1);
|
||||
tty = tty_init_dev(ptm_driver, index);
|
||||
mutex_unlock(&tty_mutex);
|
||||
|
||||
if (IS_ERR(tty)) {
|
||||
|
@ -704,8 +648,8 @@ err_release:
|
|||
tty_release(inode, filp);
|
||||
return retval;
|
||||
out:
|
||||
devpts_kill_index(inode, index);
|
||||
tty_unlock();
|
||||
devpts_kill_index(inode, index);
|
||||
err_file:
|
||||
tty_free_file(filp);
|
||||
return retval;
|
||||
|
@ -762,8 +706,6 @@ static void __init unix98_pty_init(void)
|
|||
if (tty_register_driver(pts_driver))
|
||||
panic("Couldn't register Unix98 pts driver");
|
||||
|
||||
register_sysctl_table(pty_root_table);
|
||||
|
||||
/* Now create the /dev/ptmx special device */
|
||||
tty_default_fops(&ptmx_fops);
|
||||
ptmx_fops.open = ptmx_open;
|
||||
|
|
|
@ -331,7 +331,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct
|
|||
int ret = 0;
|
||||
if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
|
||||
ret = -EINVAL;
|
||||
if (ser->irq != NO_IRQ)
|
||||
if (ser->irq <= 0)
|
||||
ret = -EINVAL;
|
||||
if (ser->baud_base != port->uartclk / 16)
|
||||
ret = -EINVAL;
|
||||
|
@ -360,7 +360,7 @@ static struct uart_ops serial21285_ops = {
|
|||
static struct uart_port serial21285_port = {
|
||||
.mapbase = 0x42000160,
|
||||
.iotype = UPIO_MEM,
|
||||
.irq = NO_IRQ,
|
||||
.irq = 0,
|
||||
.fifosize = 16,
|
||||
.ops = &serial21285_ops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
|
|
|
@ -86,13 +86,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
|
|||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
|
||||
/*
|
||||
* We default to IRQ0 for the "no irq" hack. Some
|
||||
* machine types want others as well - they're free
|
||||
* to redefine this in their header file.
|
||||
*/
|
||||
#define is_real_interrupt(irq) ((irq) != 0)
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define CONFIG_SERIAL_DETECT_IRQ 1
|
||||
#endif
|
||||
|
@ -1750,7 +1743,7 @@ static void serial8250_backup_timeout(unsigned long data)
|
|||
* Must disable interrupts or else we risk racing with the interrupt
|
||||
* based handler.
|
||||
*/
|
||||
if (is_real_interrupt(up->port.irq)) {
|
||||
if (up->port.irq) {
|
||||
ier = serial_in(up, UART_IER);
|
||||
serial_out(up, UART_IER, 0);
|
||||
}
|
||||
|
@ -1775,7 +1768,7 @@ static void serial8250_backup_timeout(unsigned long data)
|
|||
if (!(iir & UART_IIR_NO_INT))
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
if (is_real_interrupt(up->port.irq))
|
||||
if (up->port.irq)
|
||||
serial_out(up, UART_IER, ier);
|
||||
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
|
@ -2028,7 +2021,7 @@ static int serial8250_startup(struct uart_port *port)
|
|||
serial_outp(up, UART_LCR, 0);
|
||||
}
|
||||
|
||||
if (is_real_interrupt(up->port.irq)) {
|
||||
if (up->port.irq) {
|
||||
unsigned char iir1;
|
||||
/*
|
||||
* Test for UARTs that do not reassert THRE when the
|
||||
|
@ -2083,7 +2076,7 @@ static int serial8250_startup(struct uart_port *port)
|
|||
* hardware interrupt, we use a timer-based system. The original
|
||||
* driver used to do this with IRQ0.
|
||||
*/
|
||||
if (!is_real_interrupt(up->port.irq)) {
|
||||
if (!up->port.irq) {
|
||||
up->timer.data = (unsigned long)up;
|
||||
mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
|
||||
} else {
|
||||
|
@ -2099,13 +2092,13 @@ static int serial8250_startup(struct uart_port *port)
|
|||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
if (up->port.flags & UPF_FOURPORT) {
|
||||
if (!is_real_interrupt(up->port.irq))
|
||||
if (!up->port.irq)
|
||||
up->port.mctrl |= TIOCM_OUT1;
|
||||
} else
|
||||
/*
|
||||
* Most PC uarts need OUT2 raised to enable interrupts.
|
||||
*/
|
||||
if (is_real_interrupt(up->port.irq))
|
||||
if (up->port.irq)
|
||||
up->port.mctrl |= TIOCM_OUT2;
|
||||
|
||||
serial8250_set_mctrl(&up->port, up->port.mctrl);
|
||||
|
@ -2223,7 +2216,7 @@ static void serial8250_shutdown(struct uart_port *port)
|
|||
|
||||
del_timer_sync(&up->timer);
|
||||
up->timer.function = serial8250_timeout;
|
||||
if (is_real_interrupt(up->port.irq))
|
||||
if (up->port.irq)
|
||||
serial_unlink_irq_chain(up);
|
||||
}
|
||||
|
||||
|
|
|
@ -1347,4 +1347,17 @@ config SERIAL_AR933X_NR_UARTS
|
|||
Set this to the number of serial ports you want the driver
|
||||
to support.
|
||||
|
||||
config SERIAL_EFM32_UART
|
||||
tristate "EFM32 UART/USART port."
|
||||
depends on ARCH_EFM32
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver support the USART and UART ports on
|
||||
Energy Micro's efm32 SoCs.
|
||||
|
||||
config SERIAL_EFM32_UART_CONSOLE
|
||||
bool "EFM32 UART/USART console support"
|
||||
depends on SERIAL_EFM32_UART=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -61,12 +61,12 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
|
|||
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
|
||||
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
|
||||
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
|
||||
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
|
||||
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
|
||||
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
|
||||
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
|
||||
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
|
||||
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
|
||||
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
|
||||
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
|
||||
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
|
||||
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
|
||||
|
@ -78,3 +78,4 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
|
|||
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
|
||||
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
|
||||
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
|
||||
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
|
||||
|
|
|
@ -377,6 +377,26 @@ static int altera_uart_verify_port(struct uart_port *port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int altera_uart_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
ALTERA_UART_STATUS_RRDY_MSK))
|
||||
cpu_relax();
|
||||
|
||||
return altera_uart_readl(port, ALTERA_UART_RXDATA_REG);
|
||||
}
|
||||
|
||||
static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
ALTERA_UART_STATUS_TRDY_MSK))
|
||||
cpu_relax();
|
||||
|
||||
altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the basic serial functions we support.
|
||||
*/
|
||||
|
@ -397,35 +417,16 @@ static struct uart_ops altera_uart_ops = {
|
|||
.release_port = altera_uart_release_port,
|
||||
.config_port = altera_uart_config_port,
|
||||
.verify_port = altera_uart_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = altera_uart_poll_get_char,
|
||||
.poll_put_char = altera_uart_poll_put_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
|
||||
|
||||
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
|
||||
|
||||
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
|
||||
port = &altera_uart_ports[i].port;
|
||||
|
||||
port->line = i;
|
||||
port->type = PORT_ALTERA_UART;
|
||||
port->mapbase = platp[i].mapbase;
|
||||
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
|
||||
port->iotype = SERIAL_IO_MEM;
|
||||
port->irq = platp[i].irq;
|
||||
port->uartclk = platp[i].uartclk;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->ops = &altera_uart_ops;
|
||||
port->private_data = platp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void altera_uart_console_putc(struct uart_port *port, const char c)
|
||||
{
|
||||
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
|
|
|
@ -0,0 +1,830 @@
|
|||
#if defined(CONFIG_SERIAL_EFM32_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/platform_data/efm32-uart.h>
|
||||
|
||||
#define DRIVER_NAME "efm32-uart"
|
||||
#define DEV_NAME "ttyefm"
|
||||
|
||||
#define UARTn_CTRL 0x00
|
||||
#define UARTn_CTRL_SYNC 0x0001
|
||||
#define UARTn_CTRL_TXBIL 0x1000
|
||||
|
||||
#define UARTn_FRAME 0x04
|
||||
#define UARTn_FRAME_DATABITS__MASK 0x000f
|
||||
#define UARTn_FRAME_DATABITS(n) ((n) - 3)
|
||||
#define UARTn_FRAME_PARITY_NONE 0x0000
|
||||
#define UARTn_FRAME_PARITY_EVEN 0x0200
|
||||
#define UARTn_FRAME_PARITY_ODD 0x0300
|
||||
#define UARTn_FRAME_STOPBITS_HALF 0x0000
|
||||
#define UARTn_FRAME_STOPBITS_ONE 0x1000
|
||||
#define UARTn_FRAME_STOPBITS_TWO 0x3000
|
||||
|
||||
#define UARTn_CMD 0x0c
|
||||
#define UARTn_CMD_RXEN 0x0001
|
||||
#define UARTn_CMD_RXDIS 0x0002
|
||||
#define UARTn_CMD_TXEN 0x0004
|
||||
#define UARTn_CMD_TXDIS 0x0008
|
||||
|
||||
#define UARTn_STATUS 0x10
|
||||
#define UARTn_STATUS_TXENS 0x0002
|
||||
#define UARTn_STATUS_TXC 0x0020
|
||||
#define UARTn_STATUS_TXBL 0x0040
|
||||
#define UARTn_STATUS_RXDATAV 0x0080
|
||||
|
||||
#define UARTn_CLKDIV 0x14
|
||||
|
||||
#define UARTn_RXDATAX 0x18
|
||||
#define UARTn_RXDATAX_RXDATA__MASK 0x01ff
|
||||
#define UARTn_RXDATAX_PERR 0x4000
|
||||
#define UARTn_RXDATAX_FERR 0x8000
|
||||
/*
|
||||
* This is a software only flag used for ignore_status_mask and
|
||||
* read_status_mask! It's used for breaks that the hardware doesn't report
|
||||
* explicitly.
|
||||
*/
|
||||
#define SW_UARTn_RXDATAX_BERR 0x2000
|
||||
|
||||
#define UARTn_TXDATA 0x34
|
||||
|
||||
#define UARTn_IF 0x40
|
||||
#define UARTn_IF_TXC 0x0001
|
||||
#define UARTn_IF_TXBL 0x0002
|
||||
#define UARTn_IF_RXDATAV 0x0004
|
||||
#define UARTn_IF_RXOF 0x0010
|
||||
|
||||
#define UARTn_IFS 0x44
|
||||
#define UARTn_IFC 0x48
|
||||
#define UARTn_IEN 0x4c
|
||||
|
||||
#define UARTn_ROUTE 0x54
|
||||
#define UARTn_ROUTE_LOCATION__MASK 0x0700
|
||||
#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK)
|
||||
#define UARTn_ROUTE_RXPEN 0x0001
|
||||
#define UARTn_ROUTE_TXPEN 0x0002
|
||||
|
||||
struct efm32_uart_port {
|
||||
struct uart_port port;
|
||||
unsigned int txirq;
|
||||
struct clk *clk;
|
||||
};
|
||||
#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
|
||||
#define efm_debug(efm_port, format, arg...) \
|
||||
dev_dbg(efm_port->port.dev, format, ##arg)
|
||||
|
||||
static void efm32_uart_write32(struct efm32_uart_port *efm_port,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel_relaxed(value, efm_port->port.membase + offset);
|
||||
}
|
||||
|
||||
static u32 efm32_uart_read32(struct efm32_uart_port *efm_port,
|
||||
unsigned offset)
|
||||
{
|
||||
return readl_relaxed(efm_port->port.membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int efm32_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
|
||||
if (status & UARTn_STATUS_TXC)
|
||||
return TIOCSER_TEMT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* sorry, neither handshaking lines nor loop functionallity */
|
||||
}
|
||||
|
||||
static unsigned int efm32_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
/* sorry, no handshaking lines available */
|
||||
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
|
||||
}
|
||||
|
||||
static void efm32_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 ien = efm32_uart_read32(efm_port, UARTn_IEN);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
|
||||
ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL);
|
||||
efm32_uart_write32(efm_port, ien, UARTn_IEN);
|
||||
}
|
||||
|
||||
static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct uart_port *port = &efm_port->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_TXBL) {
|
||||
if (port->x_char) {
|
||||
port->icount.tx++;
|
||||
efm32_uart_write32(efm_port, port->x_char,
|
||||
UARTn_TXDATA);
|
||||
port->x_char = 0;
|
||||
continue;
|
||||
}
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
|
||||
port->icount.tx++;
|
||||
efm32_uart_write32(efm_port, xmit->buf[xmit->tail],
|
||||
UARTn_TXDATA);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (!port->x_char && uart_circ_empty(xmit) &&
|
||||
efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_TXC)
|
||||
efm32_uart_stop_tx(port);
|
||||
}
|
||||
|
||||
static void efm32_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 ien;
|
||||
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC);
|
||||
ien = efm32_uart_read32(efm_port, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port,
|
||||
ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
|
||||
|
||||
efm32_uart_tx_chars(efm_port);
|
||||
}
|
||||
|
||||
static void efm32_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
|
||||
}
|
||||
|
||||
static void efm32_uart_enable_ms(struct uart_port *port)
|
||||
{
|
||||
/* no handshake lines, no modem status interrupts */
|
||||
}
|
||||
|
||||
static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
|
||||
{
|
||||
/* not possible without fiddling with gpios */
|
||||
}
|
||||
|
||||
static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port,
|
||||
struct tty_struct *tty)
|
||||
{
|
||||
struct uart_port *port = &efm_port->port;
|
||||
|
||||
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_RXDATAV) {
|
||||
u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX);
|
||||
int flag = 0;
|
||||
|
||||
/*
|
||||
* This is a reserved bit and I only saw it read as 0. But to be
|
||||
* sure not to be confused too much by new devices adhere to the
|
||||
* warning in the reference manual that reserverd bits might
|
||||
* read as 1 in the future.
|
||||
*/
|
||||
rxdata &= ~SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
port->icount.rx++;
|
||||
|
||||
if ((rxdata & UARTn_RXDATAX_FERR) &&
|
||||
!(rxdata & UARTn_RXDATAX_RXDATA__MASK)) {
|
||||
rxdata |= SW_UARTn_RXDATAX_BERR;
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else if (rxdata & UARTn_RXDATAX_PERR)
|
||||
port->icount.parity++;
|
||||
else if (rxdata & UARTn_RXDATAX_FERR)
|
||||
port->icount.frame++;
|
||||
|
||||
rxdata &= port->read_status_mask;
|
||||
|
||||
if (rxdata & SW_UARTn_RXDATAX_BERR)
|
||||
flag = TTY_BREAK;
|
||||
else if (rxdata & UARTn_RXDATAX_PERR)
|
||||
flag = TTY_PARITY;
|
||||
else if (rxdata & UARTn_RXDATAX_FERR)
|
||||
flag = TTY_FRAME;
|
||||
else if (uart_handle_sysrq_char(port,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK))
|
||||
continue;
|
||||
|
||||
if (tty && (rxdata & port->ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(tty,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t efm32_uart_rxirq(int irq, void *data)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = data;
|
||||
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
|
||||
int handled = IRQ_NONE;
|
||||
struct uart_port *port = &efm_port->port;
|
||||
struct tty_struct *tty;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
tty = tty_kref_get(port->state->port.tty);
|
||||
|
||||
if (irqflag & UARTn_IF_RXDATAV) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
|
||||
efm32_uart_rx_chars(efm_port, tty);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (irqflag & UARTn_IF_RXOF) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
|
||||
port->icount.overrun++;
|
||||
if (tty)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
static irqreturn_t efm32_uart_txirq(int irq, void *data)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = data;
|
||||
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
|
||||
|
||||
/* TXBL doesn't need to be cleared */
|
||||
if (irqflag & UARTn_IF_TXC)
|
||||
efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC);
|
||||
|
||||
if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) {
|
||||
efm32_uart_tx_chars(efm_port);
|
||||
return IRQ_HANDLED;
|
||||
} else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int efm32_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 location = 0;
|
||||
struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
location = UARTn_ROUTE_LOCATION(pdata->location);
|
||||
|
||||
ret = clk_enable(efm_port->clk);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to enable clk\n");
|
||||
goto err_clk_enable;
|
||||
}
|
||||
port->uartclk = clk_get_rate(efm_port->clk);
|
||||
|
||||
/* Enable pins at configured location */
|
||||
efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
|
||||
UARTn_ROUTE);
|
||||
|
||||
ret = request_irq(port->irq, efm32_uart_rxirq, 0,
|
||||
DRIVER_NAME, efm_port);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to register rxirq\n");
|
||||
goto err_request_irq_rx;
|
||||
}
|
||||
|
||||
/* disable all irqs */
|
||||
efm32_uart_write32(efm_port, 0, UARTn_IEN);
|
||||
|
||||
ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0,
|
||||
DRIVER_NAME, efm_port);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to register txirq\n");
|
||||
free_irq(port->irq, efm_port);
|
||||
err_request_irq_rx:
|
||||
|
||||
clk_disable(efm_port->clk);
|
||||
} else {
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD);
|
||||
}
|
||||
|
||||
err_clk_enable:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void efm32_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
efm32_uart_write32(efm_port, 0, UARTn_IEN);
|
||||
free_irq(port->irq, efm_port);
|
||||
|
||||
clk_disable(efm_port->clk);
|
||||
}
|
||||
|
||||
static void efm32_uart_set_termios(struct uart_port *port,
|
||||
struct ktermios *new, struct ktermios *old)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
unsigned long flags;
|
||||
unsigned baud;
|
||||
u32 clkdiv;
|
||||
u32 frame = 0;
|
||||
|
||||
/* no modem control lines */
|
||||
new->c_cflag &= ~(CRTSCTS | CMSPAR);
|
||||
|
||||
baud = uart_get_baud_rate(port, new, old,
|
||||
DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192),
|
||||
DIV_ROUND_CLOSEST(port->uartclk, 16));
|
||||
|
||||
switch (new->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
frame |= UARTn_FRAME_DATABITS(5);
|
||||
break;
|
||||
case CS6:
|
||||
frame |= UARTn_FRAME_DATABITS(6);
|
||||
break;
|
||||
case CS7:
|
||||
frame |= UARTn_FRAME_DATABITS(7);
|
||||
break;
|
||||
case CS8:
|
||||
frame |= UARTn_FRAME_DATABITS(8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (new->c_cflag & CSTOPB)
|
||||
/* the receiver only verifies the first stop bit */
|
||||
frame |= UARTn_FRAME_STOPBITS_TWO;
|
||||
else
|
||||
frame |= UARTn_FRAME_STOPBITS_ONE;
|
||||
|
||||
if (new->c_cflag & PARENB) {
|
||||
if (new->c_cflag & PARODD)
|
||||
frame |= UARTn_FRAME_PARITY_ODD;
|
||||
else
|
||||
frame |= UARTn_FRAME_PARITY_EVEN;
|
||||
} else
|
||||
frame |= UARTn_FRAME_PARITY_NONE;
|
||||
|
||||
/*
|
||||
* the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25.
|
||||
* port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow.
|
||||
*/
|
||||
clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD);
|
||||
|
||||
port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK;
|
||||
if (new->c_iflag & INPCK)
|
||||
port->read_status_mask |=
|
||||
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
|
||||
if (new->c_iflag & (BRKINT | PARMRK))
|
||||
port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
port->ignore_status_mask = 0;
|
||||
if (new->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |=
|
||||
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
|
||||
if (new->c_iflag & IGNBRK)
|
||||
port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
uart_update_timeout(port, new->c_cflag, baud);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL);
|
||||
efm32_uart_write32(efm_port, frame, UARTn_FRAME);
|
||||
efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN,
|
||||
UARTn_CMD);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *efm32_uart_type(struct uart_port *port)
|
||||
{
|
||||
return port->type == PORT_EFMUART ? "efm32-uart" : NULL;
|
||||
}
|
||||
|
||||
static void efm32_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
clk_unprepare(efm_port->clk);
|
||||
clk_put(efm_port->clk);
|
||||
iounmap(port->membase);
|
||||
}
|
||||
|
||||
static int efm32_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
int ret;
|
||||
|
||||
port->membase = ioremap(port->mapbase, 60);
|
||||
if (!efm_port->port.membase) {
|
||||
ret = -ENOMEM;
|
||||
efm_debug(efm_port, "failed to remap\n");
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
efm_port->clk = clk_get(port->dev, NULL);
|
||||
if (IS_ERR(efm_port->clk)) {
|
||||
ret = PTR_ERR(efm_port->clk);
|
||||
efm_debug(efm_port, "failed to get clock\n");
|
||||
goto err_clk_get;
|
||||
}
|
||||
|
||||
ret = clk_prepare(efm_port->clk);
|
||||
if (ret) {
|
||||
clk_put(efm_port->clk);
|
||||
err_clk_get:
|
||||
|
||||
iounmap(port->membase);
|
||||
err_ioremap:
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void efm32_uart_config_port(struct uart_port *port, int type)
|
||||
{
|
||||
if (type & UART_CONFIG_TYPE &&
|
||||
!efm32_uart_request_port(port))
|
||||
port->type = PORT_EFMUART;
|
||||
}
|
||||
|
||||
static int efm32_uart_verify_port(struct uart_port *port,
|
||||
struct serial_struct *serinfo)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct uart_ops efm32_uart_pops = {
|
||||
.tx_empty = efm32_uart_tx_empty,
|
||||
.set_mctrl = efm32_uart_set_mctrl,
|
||||
.get_mctrl = efm32_uart_get_mctrl,
|
||||
.stop_tx = efm32_uart_stop_tx,
|
||||
.start_tx = efm32_uart_start_tx,
|
||||
.stop_rx = efm32_uart_stop_rx,
|
||||
.enable_ms = efm32_uart_enable_ms,
|
||||
.break_ctl = efm32_uart_break_ctl,
|
||||
.startup = efm32_uart_startup,
|
||||
.shutdown = efm32_uart_shutdown,
|
||||
.set_termios = efm32_uart_set_termios,
|
||||
.type = efm32_uart_type,
|
||||
.release_port = efm32_uart_release_port,
|
||||
.request_port = efm32_uart_request_port,
|
||||
.config_port = efm32_uart_config_port,
|
||||
.verify_port = efm32_uart_verify_port,
|
||||
};
|
||||
|
||||
static struct efm32_uart_port *efm32_uart_ports[5];
|
||||
|
||||
#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE
|
||||
static void efm32_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
unsigned int timeout = 0x400;
|
||||
u32 status;
|
||||
|
||||
while (1) {
|
||||
status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
|
||||
if (status & UARTn_STATUS_TXBL)
|
||||
break;
|
||||
if (!timeout--)
|
||||
return;
|
||||
}
|
||||
efm32_uart_write32(efm_port, ch, UARTn_TXDATA);
|
||||
}
|
||||
|
||||
static void efm32_uart_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = efm32_uart_ports[co->index];
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
unsigned int timeout = 0x400;
|
||||
|
||||
if (!(status & UARTn_STATUS_TXENS))
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
|
||||
|
||||
uart_console_write(&efm_port->port, s, count,
|
||||
efm32_uart_console_putchar);
|
||||
|
||||
/* Wait for the transmitter to become empty */
|
||||
while (1) {
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
if (status & UARTn_STATUS_TXC)
|
||||
break;
|
||||
if (!timeout--)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(status & UARTn_STATUS_TXENS))
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
|
||||
}
|
||||
|
||||
static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port,
|
||||
int *baud, int *parity, int *bits)
|
||||
{
|
||||
u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL);
|
||||
u32 route, clkdiv, frame;
|
||||
|
||||
if (ctrl & UARTn_CTRL_SYNC)
|
||||
/* not operating in async mode */
|
||||
return;
|
||||
|
||||
route = efm32_uart_read32(efm_port, UARTn_ROUTE);
|
||||
if (!(route & UARTn_ROUTE_TXPEN))
|
||||
/* tx pin not routed */
|
||||
return;
|
||||
|
||||
clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV);
|
||||
|
||||
*baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk,
|
||||
16 * (4 + (clkdiv >> 6)));
|
||||
|
||||
frame = efm32_uart_read32(efm_port, UARTn_FRAME);
|
||||
if (frame & UARTn_FRAME_PARITY_ODD)
|
||||
*parity = 'o';
|
||||
else if (frame & UARTn_FRAME_PARITY_EVEN)
|
||||
*parity = 'e';
|
||||
else
|
||||
*parity = 'n';
|
||||
|
||||
*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
|
||||
UARTn_FRAME_DATABITS(4) + 4;
|
||||
|
||||
efm_debug(efm_port, "get_opts: options=%d%c%d\n",
|
||||
*baud, *parity, *bits);
|
||||
}
|
||||
|
||||
static int efm32_uart_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct efm32_uart_port *efm_port;
|
||||
int baud = 115200;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
int ret;
|
||||
|
||||
if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) {
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) {
|
||||
if (efm32_uart_ports[i]) {
|
||||
pr_warn("efm32-console: fall back to console index %u (from %hhi)\n",
|
||||
i, co->index);
|
||||
co->index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
efm_port = efm32_uart_ports[co->index];
|
||||
if (!efm_port) {
|
||||
pr_warn("efm32-console: No port at %d\n", co->index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_prepare(efm_port->clk);
|
||||
if (ret) {
|
||||
dev_warn(efm_port->port.dev,
|
||||
"console: clk_prepare failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
efm_port->port.uartclk = clk_get_rate(efm_port->clk);
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
else
|
||||
efm32_uart_console_get_options(efm_port,
|
||||
&baud, &parity, &bits);
|
||||
|
||||
return uart_set_options(&efm_port->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver efm32_uart_reg;
|
||||
|
||||
static struct console efm32_uart_console = {
|
||||
.name = DEV_NAME,
|
||||
.write = efm32_uart_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = efm32_uart_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &efm32_uart_reg,
|
||||
};
|
||||
|
||||
#else
|
||||
#define efm32_uart_console (*(struct console *)NULL)
|
||||
#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
|
||||
|
||||
static struct uart_driver efm32_uart_reg = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = DRIVER_NAME,
|
||||
.dev_name = DEV_NAME,
|
||||
.nr = ARRAY_SIZE(efm32_uart_ports),
|
||||
.cons = &efm32_uart_console,
|
||||
};
|
||||
|
||||
static int efm32_uart_probe_dt(struct platform_device *pdev,
|
||||
struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
return 1;
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
|
||||
return ret;
|
||||
} else {
|
||||
efm_port->port.line = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int __devinit efm32_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct efm32_uart_port *efm_port;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
|
||||
if (!efm_port) {
|
||||
dev_dbg(&pdev->dev, "failed to allocate private data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
dev_dbg(&pdev->dev, "failed to determine base address\n");
|
||||
goto err_get_base;
|
||||
}
|
||||
|
||||
if (resource_size(res) < 60) {
|
||||
ret = -EINVAL;
|
||||
dev_dbg(&pdev->dev, "memory resource too small\n");
|
||||
goto err_too_small;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_dbg(&pdev->dev, "failed to get rx irq\n");
|
||||
goto err_get_rxirq;
|
||||
}
|
||||
|
||||
efm_port->port.irq = ret;
|
||||
|
||||
ret = platform_get_irq(pdev, 1);
|
||||
if (ret <= 0)
|
||||
ret = efm_port->port.irq + 1;
|
||||
|
||||
efm_port->txirq = ret;
|
||||
|
||||
efm_port->port.dev = &pdev->dev;
|
||||
efm_port->port.mapbase = res->start;
|
||||
efm_port->port.type = PORT_EFMUART;
|
||||
efm_port->port.iotype = UPIO_MEM32;
|
||||
efm_port->port.fifosize = 2;
|
||||
efm_port->port.ops = &efm32_uart_pops;
|
||||
efm_port->port.flags = UPF_BOOT_AUTOCONF;
|
||||
|
||||
ret = efm32_uart_probe_dt(pdev, efm_port);
|
||||
if (ret > 0)
|
||||
/* not created by device tree */
|
||||
efm_port->port.line = pdev->id;
|
||||
|
||||
if (efm_port->port.line >= 0 &&
|
||||
efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[efm_port->port.line] = efm_port;
|
||||
|
||||
ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
|
||||
|
||||
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[pdev->id] = NULL;
|
||||
err_get_rxirq:
|
||||
err_too_small:
|
||||
err_get_base:
|
||||
kfree(efm_port);
|
||||
} else {
|
||||
platform_set_drvdata(pdev, efm_port);
|
||||
dev_dbg(&pdev->dev, "\\o/\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit efm32_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
|
||||
|
||||
if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[pdev->id] = NULL;
|
||||
|
||||
kfree(efm_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id efm32_uart_dt_ids[] = {
|
||||
{
|
||||
.compatible = "efm32,uart",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
|
||||
|
||||
static struct platform_driver efm32_uart_driver = {
|
||||
.probe = efm32_uart_probe,
|
||||
.remove = __devexit_p(efm32_uart_remove),
|
||||
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = efm32_uart_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init efm32_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&efm32_uart_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&efm32_uart_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&efm32_uart_reg);
|
||||
|
||||
pr_info("EFM32 UART/USART driver\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(efm32_uart_init);
|
||||
|
||||
static void __exit efm32_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&efm32_uart_driver);
|
||||
uart_unregister_driver(&efm32_uart_reg);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("EFM32 UART/USART driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
|
@ -70,13 +70,6 @@
|
|||
|
||||
#define PASS_LIMIT 256
|
||||
|
||||
/*
|
||||
* We default to IRQ0 for the "no irq" hack. Some
|
||||
* machine types want others as well - they're free
|
||||
* to redefine this in their header file.
|
||||
*/
|
||||
#define is_real_interrupt(irq) ((irq) != 0)
|
||||
|
||||
#define BASE_BAUD 115200
|
||||
|
||||
/* Standard COM flags */
|
||||
|
@ -640,7 +633,7 @@ static int m32r_sio_startup(struct uart_port *port)
|
|||
* hardware interrupt, we use a timer-based system. The original
|
||||
* driver used to do this with IRQ0.
|
||||
*/
|
||||
if (!is_real_interrupt(up->port.irq)) {
|
||||
if (!up->port.irq) {
|
||||
unsigned int timeout = up->port.timeout;
|
||||
|
||||
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
|
||||
|
@ -687,7 +680,7 @@ static void m32r_sio_shutdown(struct uart_port *port)
|
|||
|
||||
sio_init();
|
||||
|
||||
if (!is_real_interrupt(up->port.irq))
|
||||
if (!up->port.irq)
|
||||
del_timer_sync(&up->timer);
|
||||
else
|
||||
serial_unlink_irq_chain(up);
|
||||
|
|
|
@ -507,7 +507,7 @@ static int __init mpc512x_psc_fifoc_init(void)
|
|||
|
||||
psc_fifoc_irq = irq_of_parse_and_map(np, 0);
|
||||
of_node_put(np);
|
||||
if (psc_fifoc_irq == NO_IRQ) {
|
||||
if (psc_fifoc_irq == 0) {
|
||||
pr_err("%s: Can't get FIFOC irq\n", __func__);
|
||||
iounmap(psc_fifoc);
|
||||
return -ENODEV;
|
||||
|
@ -1354,7 +1354,7 @@ static int __devinit mpc52xx_uart_of_probe(struct platform_device *op)
|
|||
}
|
||||
|
||||
psc_ops->get_irq(port, op->dev.of_node);
|
||||
if (port->irq == NO_IRQ) {
|
||||
if (port->irq == 0) {
|
||||
dev_dbg(&op->dev, "Could not get irq\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -499,7 +499,7 @@ static int __init mux_probe(struct parisc_device *dev)
|
|||
port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET);
|
||||
port->iotype = UPIO_MEM;
|
||||
port->type = PORT_MUX;
|
||||
port->irq = NO_IRQ;
|
||||
port->irq = 0;
|
||||
port->uartclk = 0;
|
||||
port->fifosize = MUX_FIFO_SIZE;
|
||||
port->ops = &mux_pops;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/nmi.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/pch_dma.h>
|
||||
|
||||
|
@ -144,6 +145,8 @@ enum {
|
|||
#define PCH_UART_DLL 0x00
|
||||
#define PCH_UART_DLM 0x01
|
||||
|
||||
#define PCH_UART_BRCSR 0x0E
|
||||
|
||||
#define PCH_UART_IID_RLS (PCH_UART_IIR_REI)
|
||||
#define PCH_UART_IID_RDR (PCH_UART_IIR_RRI)
|
||||
#define PCH_UART_IID_RDR_TO (PCH_UART_IIR_RRI | PCH_UART_IIR_TOI)
|
||||
|
@ -243,6 +246,8 @@ struct eg20t_port {
|
|||
int tx_dma_use;
|
||||
void *rx_buf_virt;
|
||||
dma_addr_t rx_buf_dma;
|
||||
|
||||
struct dentry *debugfs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -292,23 +297,73 @@ static const int trigger_level_64[4] = { 1, 16, 32, 56 };
|
|||
static const int trigger_level_16[4] = { 1, 4, 8, 14 };
|
||||
static const int trigger_level_1[4] = { 1, 1, 1, 1 };
|
||||
|
||||
static void pch_uart_hal_request(struct pci_dev *pdev, int fifosize,
|
||||
int base_baud)
|
||||
{
|
||||
struct eg20t_port *priv = pci_get_drvdata(pdev);
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
priv->trigger_level = 1;
|
||||
priv->fcr = 0;
|
||||
#define PCH_REGS_BUFSIZE 1024
|
||||
static int pch_show_regs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int get_msr(struct eg20t_port *priv, void __iomem *base)
|
||||
static ssize_t port_show_regs(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned int msr = ioread8(base + UART_MSR);
|
||||
priv->dmsr |= msr & PCH_UART_MSR_DELTA;
|
||||
struct eg20t_port *priv = file->private_data;
|
||||
char *buf;
|
||||
u32 len = 0;
|
||||
ssize_t ret;
|
||||
unsigned char lcr;
|
||||
|
||||
return msr;
|
||||
buf = kzalloc(PCH_REGS_BUFSIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"PCH EG20T port[%d] regs:\n", priv->port.line);
|
||||
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"=================================\n");
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"IER: \t0x%02x\n", ioread8(priv->membase + UART_IER));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"BRCSR: \t0x%02x\n",
|
||||
ioread8(priv->membase + PCH_UART_BRCSR));
|
||||
|
||||
lcr = ioread8(priv->membase + UART_LCR);
|
||||
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM));
|
||||
iowrite8(lcr, priv->membase + UART_LCR);
|
||||
|
||||
if (len > PCH_REGS_BUFSIZE)
|
||||
len = PCH_REGS_BUFSIZE;
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations port_regs_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = pch_show_regs_open,
|
||||
.read = port_show_regs,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
static void pch_uart_hal_enable_interrupt(struct eg20t_port *priv,
|
||||
unsigned int flag)
|
||||
{
|
||||
|
@ -442,8 +497,9 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv,
|
|||
|
||||
static u8 pch_uart_hal_get_modem(struct eg20t_port *priv)
|
||||
{
|
||||
priv->dmsr = 0;
|
||||
return get_msr(priv, priv->membase);
|
||||
unsigned int msr = ioread8(priv->membase + UART_MSR);
|
||||
priv->dmsr = msr & PCH_UART_MSR_DELTA;
|
||||
return (u8)msr;
|
||||
}
|
||||
|
||||
static void pch_uart_hal_write(struct eg20t_port *priv,
|
||||
|
@ -524,7 +580,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
|
|||
|
||||
static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct uart_port *port = &priv->port;
|
||||
|
||||
if (port->x_char) {
|
||||
|
@ -533,8 +589,6 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf)
|
|||
buf[0] = port->x_char;
|
||||
port->x_char = 0;
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1032,14 +1086,12 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
static unsigned int pch_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct eg20t_port *priv;
|
||||
int ret;
|
||||
|
||||
priv = container_of(port, struct eg20t_port, port);
|
||||
if (priv->tx_empty)
|
||||
ret = TIOCSER_TEMT;
|
||||
return TIOCSER_TEMT;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns the current state of modem control inputs. */
|
||||
|
@ -1273,9 +1325,8 @@ static void pch_uart_set_termios(struct uart_port *port,
|
|||
else
|
||||
parity = PCH_UART_HAL_PARITY_EVEN;
|
||||
|
||||
} else {
|
||||
} else
|
||||
parity = PCH_UART_HAL_PARITY_NONE;
|
||||
}
|
||||
|
||||
/* Only UART0 has auto hardware flow function */
|
||||
if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
|
||||
|
@ -1447,7 +1498,6 @@ static void
|
|||
pch_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct eg20t_port *priv;
|
||||
|
||||
unsigned long flags;
|
||||
u8 ier;
|
||||
int locked = 1;
|
||||
|
@ -1554,6 +1604,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
int port_type;
|
||||
struct pch_uart_driver_data *board;
|
||||
const char *board_name;
|
||||
char name[32]; /* for debugfs file name */
|
||||
|
||||
board = &drv_dat[id->driver_data];
|
||||
port_type = board->port_type;
|
||||
|
@ -1614,7 +1665,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
spin_lock_init(&priv->port.lock);
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
pch_uart_hal_request(pdev, fifosize, base_baud);
|
||||
priv->trigger_level = 1;
|
||||
priv->fcr = 0;
|
||||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
pch_uart_ports[board->line_no] = priv;
|
||||
|
@ -1623,6 +1675,12 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
if (ret < 0)
|
||||
goto init_port_hal_free;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
snprintf(name, sizeof(name), "uart%d_regs", board->line_no);
|
||||
priv->debugfs = debugfs_create_file(name, S_IFREG | S_IRUGO,
|
||||
NULL, priv, &port_regs_ops);
|
||||
#endif
|
||||
|
||||
return priv;
|
||||
|
||||
init_port_hal_free:
|
||||
|
@ -1639,6 +1697,11 @@ init_port_alloc_err:
|
|||
|
||||
static void pch_uart_exit_port(struct eg20t_port *priv)
|
||||
{
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
if (priv->debugfs)
|
||||
debugfs_remove(priv->debugfs);
|
||||
#endif
|
||||
uart_remove_one_port(&pch_uart_driver, &priv->port);
|
||||
pci_set_drvdata(priv->pdev, NULL);
|
||||
free_page((unsigned long)priv->rxbuf.buf);
|
||||
|
@ -1646,9 +1709,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
|
|||
|
||||
static void pch_uart_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct eg20t_port *priv;
|
||||
|
||||
priv = (struct eg20t_port *)pci_get_drvdata(pdev);
|
||||
struct eg20t_port *priv = pci_get_drvdata(pdev);
|
||||
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
|
|
|
@ -1506,7 +1506,7 @@ no_dma:
|
|||
* fixed up interrupt info, but we use the device-tree directly
|
||||
* here due to early probing so we need the fixup too.
|
||||
*/
|
||||
if (uap->port.irq == NO_IRQ &&
|
||||
if (uap->port.irq == 0 &&
|
||||
np->parent && np->parent->parent &&
|
||||
of_device_is_compatible(np->parent->parent, "gatwick")) {
|
||||
/* IRQs on gatwick are offset by 64 */
|
||||
|
|
|
@ -1397,7 +1397,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int zilog_irq = -1;
|
||||
static int zilog_irq;
|
||||
|
||||
static int __devinit zs_probe(struct platform_device *op)
|
||||
{
|
||||
|
@ -1425,7 +1425,7 @@ static int __devinit zs_probe(struct platform_device *op)
|
|||
|
||||
rp = sunzilog_chip_regs[inst];
|
||||
|
||||
if (zilog_irq == -1)
|
||||
if (!zilog_irq)
|
||||
zilog_irq = op->archdata.irqs[0];
|
||||
|
||||
up = &sunzilog_port_table[inst * 2];
|
||||
|
@ -1580,7 +1580,7 @@ static int __init sunzilog_init(void)
|
|||
if (err)
|
||||
goto out_unregister_uart;
|
||||
|
||||
if (zilog_irq != -1) {
|
||||
if (!zilog_irq) {
|
||||
struct uart_sunzilog_port *up = sunzilog_irq_chain;
|
||||
err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
|
||||
"zs", sunzilog_irq_chain);
|
||||
|
@ -1621,7 +1621,7 @@ static void __exit sunzilog_exit(void)
|
|||
{
|
||||
platform_driver_unregister(&zs_driver);
|
||||
|
||||
if (zilog_irq != -1) {
|
||||
if (!zilog_irq) {
|
||||
struct uart_sunzilog_port *up = sunzilog_irq_chain;
|
||||
|
||||
/* Disable Interrupts */
|
||||
|
@ -1637,7 +1637,7 @@ static void __exit sunzilog_exit(void)
|
|||
}
|
||||
|
||||
free_irq(zilog_irq, sunzilog_irq_chain);
|
||||
zilog_irq = -1;
|
||||
zilog_irq = 0;
|
||||
}
|
||||
|
||||
if (sunzilog_reg.nr) {
|
||||
|
|
|
@ -1360,7 +1360,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
|
|||
}
|
||||
|
||||
qe_port->port.irq = irq_of_parse_and_map(np, 0);
|
||||
if (qe_port->port.irq == NO_IRQ) {
|
||||
if (qe_port->port.irq == 0) {
|
||||
dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
|
||||
qe_port->ucc_num + 1);
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
|
||||
[0 ... SIU_PORTS_MAX-1] = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
|
||||
.irq = -1,
|
||||
.irq = 0,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -171,7 +171,7 @@ static inline unsigned int siu_check_type(struct uart_port *port)
|
|||
{
|
||||
if (port->line == 0)
|
||||
return PORT_VR41XX_SIU;
|
||||
if (port->line == 1 && port->irq != -1)
|
||||
if (port->line == 1 && port->irq)
|
||||
return PORT_VR41XX_DSIU;
|
||||
|
||||
return PORT_UNKNOWN;
|
||||
|
|
|
@ -322,11 +322,16 @@ static void send_sig_all(int sig)
|
|||
{
|
||||
struct task_struct *p;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process(p) {
|
||||
if (p->mm && !is_global_init(p))
|
||||
/* Not swapper, init nor kernel thread */
|
||||
if (p->flags & PF_KTHREAD)
|
||||
continue;
|
||||
if (is_global_init(p))
|
||||
continue;
|
||||
|
||||
force_sig(sig, p);
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
}
|
||||
|
||||
static void sysrq_handle_term(int key)
|
||||
|
|
|
@ -1271,6 +1271,19 @@ int tty_init_termios(struct tty_struct *tty)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tty_init_termios);
|
||||
|
||||
int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
int ret = tty_init_termios(tty);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[tty->index] = tty;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_standard_install);
|
||||
|
||||
/**
|
||||
* tty_driver_install_tty() - install a tty entry in the driver
|
||||
* @driver: the driver for the tty
|
||||
|
@ -1286,21 +1299,8 @@ EXPORT_SYMBOL_GPL(tty_init_termios);
|
|||
static int tty_driver_install_tty(struct tty_driver *driver,
|
||||
struct tty_struct *tty)
|
||||
{
|
||||
int idx = tty->index;
|
||||
int ret;
|
||||
|
||||
if (driver->ops->install) {
|
||||
ret = driver->ops->install(driver, tty);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tty_init_termios(tty) == 0) {
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[idx] = tty;
|
||||
return 0;
|
||||
}
|
||||
return -ENOMEM;
|
||||
return driver->ops->install ? driver->ops->install(driver, tty) :
|
||||
tty_standard_install(driver, tty);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1365,7 +1365,6 @@ static int tty_reopen(struct tty_struct *tty)
|
|||
* @driver: tty driver we are opening a device on
|
||||
* @idx: device index
|
||||
* @ret_tty: returned tty structure
|
||||
* @first_ok: ok to open a new device (used by ptmx)
|
||||
*
|
||||
* Prepare a tty device. This may not be a "new" clean device but
|
||||
* could also be an active device. The pty drivers require special
|
||||
|
@ -1385,18 +1384,11 @@ static int tty_reopen(struct tty_struct *tty)
|
|||
* relaxed for the (most common) case of reopening a tty.
|
||||
*/
|
||||
|
||||
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||
int first_ok)
|
||||
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
int retval;
|
||||
|
||||
/* Check if pty master is being opened multiple times */
|
||||
if (driver->subtype == PTY_TYPE_MASTER &&
|
||||
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* First time open is complex, especially for PTY devices.
|
||||
* This code guarantees that either everything succeeds and the
|
||||
|
@ -1797,11 +1789,11 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
* the slots and preserving the termios structure.
|
||||
*/
|
||||
release_tty(tty, idx);
|
||||
tty_unlock();
|
||||
|
||||
/* Make this pty number available for reallocation */
|
||||
if (devpts)
|
||||
devpts_kill_index(inode, idx);
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1950,7 +1942,7 @@ retry_open:
|
|||
if (retval)
|
||||
tty = ERR_PTR(retval);
|
||||
} else
|
||||
tty = tty_init_dev(driver, index, 0);
|
||||
tty = tty_init_dev(driver, index);
|
||||
|
||||
mutex_unlock(&tty_mutex);
|
||||
if (driver)
|
||||
|
|
|
@ -214,15 +214,14 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
if (!try_module_get(serial->type->driver.owner))
|
||||
goto error_module_get;
|
||||
|
||||
/* perform the standard setup */
|
||||
retval = tty_init_termios(tty);
|
||||
if (retval)
|
||||
goto error_init_termios;
|
||||
|
||||
retval = usb_autopm_get_interface(serial->interface);
|
||||
if (retval)
|
||||
goto error_get_interface;
|
||||
|
||||
retval = tty_standard_install(driver, tty);
|
||||
if (retval)
|
||||
goto error_init_termios;
|
||||
|
||||
mutex_unlock(&serial->disc_mutex);
|
||||
|
||||
/* allow the driver to update the settings */
|
||||
|
@ -231,14 +230,11 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||
|
||||
tty->driver_data = port;
|
||||
|
||||
/* Final install (we use the default method) */
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[idx] = tty;
|
||||
return retval;
|
||||
|
||||
error_get_interface:
|
||||
error_init_termios:
|
||||
usb_autopm_put_interface(serial->interface);
|
||||
error_get_interface:
|
||||
module_put(serial->type->driver.owner);
|
||||
error_module_get:
|
||||
error_no_port:
|
||||
|
|
|
@ -36,7 +36,61 @@
|
|||
#define DEVPTS_DEFAULT_PTMX_MODE 0000
|
||||
#define PTMX_MINOR 2
|
||||
|
||||
extern int pty_limit; /* Config limit on Unix98 ptys */
|
||||
/*
|
||||
* sysctl support for setting limits on the number of Unix98 ptys allocated.
|
||||
* Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
|
||||
*/
|
||||
static int pty_limit = NR_UNIX98_PTY_DEFAULT;
|
||||
static int pty_reserve = NR_UNIX98_PTY_RESERVE;
|
||||
static int pty_limit_min;
|
||||
static int pty_limit_max = INT_MAX;
|
||||
static int pty_count;
|
||||
|
||||
static struct ctl_table pty_table[] = {
|
||||
{
|
||||
.procname = "max",
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.data = &pty_limit,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &pty_limit_min,
|
||||
.extra2 = &pty_limit_max,
|
||||
}, {
|
||||
.procname = "reserve",
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.data = &pty_reserve,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = &pty_limit_min,
|
||||
.extra2 = &pty_limit_max,
|
||||
}, {
|
||||
.procname = "nr",
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0444,
|
||||
.data = &pty_count,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct ctl_table pty_kern_table[] = {
|
||||
{
|
||||
.procname = "pty",
|
||||
.mode = 0555,
|
||||
.child = pty_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct ctl_table pty_root_table[] = {
|
||||
{
|
||||
.procname = "kernel",
|
||||
.mode = 0555,
|
||||
.child = pty_kern_table,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(allocated_ptys_lock);
|
||||
|
||||
static struct vfsmount *devpts_mnt;
|
||||
|
@ -49,10 +103,11 @@ struct pts_mount_opts {
|
|||
umode_t mode;
|
||||
umode_t ptmxmode;
|
||||
int newinstance;
|
||||
int max;
|
||||
};
|
||||
|
||||
enum {
|
||||
Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance,
|
||||
Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max,
|
||||
Opt_err
|
||||
};
|
||||
|
||||
|
@ -63,6 +118,7 @@ static const match_table_t tokens = {
|
|||
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
|
||||
{Opt_ptmxmode, "ptmxmode=%o"},
|
||||
{Opt_newinstance, "newinstance"},
|
||||
{Opt_max, "max=%d"},
|
||||
#endif
|
||||
{Opt_err, NULL}
|
||||
};
|
||||
|
@ -109,6 +165,7 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
|
|||
opts->gid = 0;
|
||||
opts->mode = DEVPTS_DEFAULT_MODE;
|
||||
opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
|
||||
opts->max = NR_UNIX98_PTY_MAX;
|
||||
|
||||
/* newinstance makes sense only on initial mount */
|
||||
if (op == PARSE_MOUNT)
|
||||
|
@ -152,6 +209,12 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
|
|||
if (op == PARSE_MOUNT)
|
||||
opts->newinstance = 1;
|
||||
break;
|
||||
case Opt_max:
|
||||
if (match_int(&args[0], &option) ||
|
||||
option < 0 || option > NR_UNIX98_PTY_MAX)
|
||||
return -EINVAL;
|
||||
opts->max = option;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printk(KERN_ERR "devpts: called with bogus options\n");
|
||||
|
@ -258,6 +321,8 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root)
|
|||
seq_printf(seq, ",mode=%03o", opts->mode);
|
||||
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
|
||||
seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
|
||||
if (opts->max < NR_UNIX98_PTY_MAX)
|
||||
seq_printf(seq, ",max=%d", opts->max);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -438,6 +503,12 @@ retry:
|
|||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&allocated_ptys_lock);
|
||||
if (pty_count >= pty_limit -
|
||||
(fsi->mount_opts.newinstance ? pty_reserve : 0)) {
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
|
||||
if (ida_ret < 0) {
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
|
@ -446,11 +517,12 @@ retry:
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (index >= pty_limit) {
|
||||
if (index >= fsi->mount_opts.max) {
|
||||
ida_remove(&fsi->allocated_ptys, index);
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
return -EIO;
|
||||
return -ENOSPC;
|
||||
}
|
||||
pty_count++;
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
return index;
|
||||
}
|
||||
|
@ -462,6 +534,7 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
|
|||
|
||||
mutex_lock(&allocated_ptys_lock);
|
||||
ida_remove(&fsi->allocated_ptys, idx);
|
||||
pty_count--;
|
||||
mutex_unlock(&allocated_ptys_lock);
|
||||
}
|
||||
|
||||
|
@ -558,11 +631,15 @@ void devpts_pty_kill(struct tty_struct *tty)
|
|||
static int __init init_devpts_fs(void)
|
||||
{
|
||||
int err = register_filesystem(&devpts_fs_type);
|
||||
struct ctl_table_header *table;
|
||||
|
||||
if (!err) {
|
||||
table = register_sysctl_table(pty_root_table);
|
||||
devpts_mnt = kern_mount(&devpts_fs_type);
|
||||
if (IS_ERR(devpts_mnt)) {
|
||||
err = PTR_ERR(devpts_mnt);
|
||||
unregister_filesystem(&devpts_fs_type);
|
||||
unregister_sysctl_table(table);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#ifndef __ALTUART_H
|
||||
#define __ALTUART_H
|
||||
|
||||
#include <linux/init.h>
|
||||
|
||||
struct altera_uart_platform_uart {
|
||||
unsigned long mapbase; /* Physical address base */
|
||||
unsigned int irq; /* Interrupt vector */
|
||||
|
@ -14,6 +12,4 @@ struct altera_uart_platform_uart {
|
|||
unsigned int bus_shift; /* Bus shift (address stride) */
|
||||
};
|
||||
|
||||
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp);
|
||||
|
||||
#endif /* __ALTUART_H */
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__
|
||||
#define __LINUX_PLATFORM_DATA_EFM32_UART_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* struct efm32_uart_pdata
|
||||
* @location: pinmux location for the I/O pins (to be written to the ROUTE
|
||||
* register)
|
||||
*/
|
||||
struct efm32_uart_pdata {
|
||||
u8 location;
|
||||
};
|
||||
#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ */
|
|
@ -210,6 +210,8 @@
|
|||
/* Atheros AR933X SoC */
|
||||
#define PORT_AR933X 99
|
||||
|
||||
/* Energy Micro efm32 SoC */
|
||||
#define PORT_EFMUART 100
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
* hardcoded at present.)
|
||||
*/
|
||||
#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
|
||||
#define NR_UNIX98_PTY_RESERVE 1024 /* Default reserve for main devpts */
|
||||
#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
|
||||
|
||||
/*
|
||||
|
@ -480,10 +481,11 @@ extern void free_tty_struct(struct tty_struct *tty);
|
|||
extern void initialize_tty_struct(struct tty_struct *tty,
|
||||
struct tty_driver *driver, int idx);
|
||||
extern void deinitialize_tty_struct(struct tty_struct *tty);
|
||||
extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||
int first_ok);
|
||||
extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx);
|
||||
extern int tty_release(struct inode *inode, struct file *filp);
|
||||
extern int tty_init_termios(struct tty_struct *tty);
|
||||
extern int tty_standard_install(struct tty_driver *driver,
|
||||
struct tty_struct *tty);
|
||||
|
||||
extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
|
||||
extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
|
||||
|
|
Loading…
Reference in New Issue