aboutsummaryrefslogtreecommitdiff
path: root/drivers/tty/serial/mfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/mfd.c')
-rw-r--r--drivers/tty/serial/mfd.c130
1 files changed, 84 insertions, 46 deletions
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
index c111f36f5d2..445799dc984 100644
--- a/drivers/tty/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
@@ -21,6 +21,10 @@
* be triggered
*/
+#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
@@ -36,8 +40,10 @@
#include <linux/serial_mfd.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
+#include <linux/nmi.h>
#include <linux/io.h>
#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
#define HSU_DMA_BUF_SIZE 2048
@@ -49,8 +55,8 @@
static int hsu_dma_enable;
module_param(hsu_dma_enable, int, 0);
-MODULE_PARM_DESC(hsu_dma_enable, "It is a bitmap to set working mode, if \
-bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode.");
+MODULE_PARM_DESC(hsu_dma_enable,
+ "It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode.");
struct hsu_dma_buffer {
u8 *buf;
@@ -126,11 +132,6 @@ static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
#define HSU_REGS_BUFSIZE 1024
-static int hsu_show_regs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
static ssize_t port_show_regs(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -230,14 +231,14 @@ static ssize_t dma_show_regs(struct file *file, char __user *user_buf,
static const struct file_operations port_regs_ops = {
.owner = THIS_MODULE,
- .open = hsu_show_regs_open,
+ .open = simple_open,
.read = port_show_regs,
.llseek = default_llseek,
};
static const struct file_operations dma_regs_ops = {
.owner = THIS_MODULE,
- .open = hsu_show_regs_open,
+ .open = simple_open,
.read = dma_show_regs,
.llseek = default_llseek,
};
@@ -292,7 +293,7 @@ static void serial_hsu_enable_ms(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
}
-void hsu_dma_tx(struct uart_hsu_port *up)
+static void hsu_dma_tx(struct uart_hsu_port *up)
{
struct circ_buf *xmit = &up->port.state->xmit;
struct hsu_dma_buffer *dbuf = &up->txbuf;
@@ -339,7 +340,8 @@ void hsu_dma_tx(struct uart_hsu_port *up)
}
/* The buffer is already cache coherent */
-void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf)
+static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc,
+ struct hsu_dma_buffer *dbuf)
{
dbuf->ofs = 0;
@@ -385,17 +387,15 @@ static void serial_hsu_stop_tx(struct uart_port *port)
/* This is always called in spinlock protected mode, so
* modify timeout timer is safe here */
-void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
+static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts,
+ unsigned long *flags)
{
struct hsu_dma_buffer *dbuf = &up->rxbuf;
struct hsu_dma_chan *chan = up->rxc;
struct uart_port *port = &up->port;
- struct tty_struct *tty = port->state->port.tty;
+ struct tty_port *tport = &port->state->port;
int count;
- if (!tty)
- return;
-
/*
* First need to know how many is already transferred,
* then check if its a timeout DMA irq, and return
@@ -426,7 +426,7 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
* explicitly set tail to 0. So head will
* always be greater than tail.
*/
- tty_insert_flip_string(tty, dbuf->buf, count);
+ tty_insert_flip_string(tport, dbuf->buf, count);
port->icount.rx += count;
dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
@@ -440,7 +440,9 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
| (0x1 << 16)
| (0x1 << 24) /* timeout bit, see HSU Errata 1 */
);
- tty_flip_buffer_push(tty);
+ spin_unlock_irqrestore(&up->port.lock, *flags);
+ tty_flip_buffer_push(tport);
+ spin_lock_irqsave(&up->port.lock, *flags);
chan_writel(chan, HSU_CH_CR, 0x3);
@@ -461,15 +463,12 @@ static void serial_hsu_stop_rx(struct uart_port *port)
}
}
-static inline void receive_chars(struct uart_hsu_port *up, int *status)
+static inline void receive_chars(struct uart_hsu_port *up, int *status,
+ unsigned long *flags)
{
- struct tty_struct *tty = up->port.state->port.tty;
unsigned int ch, flag;
unsigned int max_count = 256;
- if (!tty)
- return;
-
do {
ch = serial_in(up, UART_RX);
flag = TTY_NORMAL;
@@ -525,7 +524,10 @@ static inline void receive_chars(struct uart_hsu_port *up, int *status)
ignore_char:
*status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && max_count--);
- tty_flip_buffer_push(tty);
+
+ spin_unlock_irqrestore(&up->port.lock, *flags);
+ tty_flip_buffer_push(&up->port.state->port);
+ spin_lock_irqsave(&up->port.lock, *flags);
}
static void transmit_chars(struct uart_hsu_port *up)
@@ -619,7 +621,7 @@ static irqreturn_t port_irq(int irq, void *dev_id)
lsr = serial_in(up, UART_LSR);
if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr);
+ receive_chars(up, &lsr, &flags);
check_modem_status(up);
/* lsr will be renewed during the receive_chars */
@@ -649,7 +651,7 @@ static inline void dma_chan_irq(struct hsu_dma_chan *chan)
/* Rx channel */
if (chan->dirt == DMA_FROM_DEVICE)
- hsu_dma_rx(up, int_sts);
+ hsu_dma_rx(up, int_sts, &flags);
/* Tx channel */
if (chan->dirt == DMA_TO_DEVICE) {
@@ -764,6 +766,8 @@ static int serial_hsu_startup(struct uart_port *port)
container_of(port, struct uart_hsu_port, port);
unsigned long flags;
+ pm_runtime_get_sync(up->dev);
+
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
@@ -871,6 +875,8 @@ static void serial_hsu_shutdown(struct uart_port *port)
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
serial_out(up, UART_FCR, 0);
+
+ pm_runtime_put(up->dev);
}
static void
@@ -879,7 +885,6 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct uart_hsu_port *up =
container_of(port, struct uart_hsu_port, port);
- struct tty_struct *tty = port->state->port.tty;
unsigned char cval, fcr = 0;
unsigned long flags;
unsigned int baud, quot;
@@ -902,8 +907,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
}
/* CMSPAR isn't supported by this driver */
- if (tty)
- tty->termios->c_cflag &= ~CMSPAR;
+ termios->c_cflag &= ~CMSPAR;
if (termios->c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
@@ -973,7 +977,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios,
up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
up->port.read_status_mask |= UART_LSR_BI;
/* Characters to ignore */
@@ -1115,6 +1119,8 @@ serial_hsu_console_write(struct console *co, const char *s, unsigned int count)
unsigned int ier;
int locked = 1;
+ touch_nmi_watchdog();
+
local_irq_save(flags);
if (up->port.sysrq)
locked = 0;
@@ -1151,7 +1157,6 @@ serial_hsu_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
- int ret;
if (co->index == -1 || co->index >= serial_hsu_reg.nr)
co->index = 0;
@@ -1162,9 +1167,7 @@ serial_hsu_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- ret = uart_set_options(&up->port, co, baud, parity, bits, flow);
-
- return ret;
+ return uart_set_options(&up->port, co, baud, parity, bits, flow);
}
static struct console serial_hsu_console = {
@@ -1173,12 +1176,16 @@ static struct console serial_hsu_console = {
.device = uart_console_device,
.setup = serial_hsu_console_setup,
.flags = CON_PRINTBUFFER,
- .index = 2,
+ .index = -1,
.data = &serial_hsu_reg,
};
+
+#define SERIAL_HSU_CONSOLE (&serial_hsu_console)
+#else
+#define SERIAL_HSU_CONSOLE NULL
#endif
-struct uart_ops serial_hsu_pops = {
+static struct uart_ops serial_hsu_pops = {
.tx_empty = serial_hsu_tx_empty,
.set_mctrl = serial_hsu_set_mctrl,
.get_mctrl = serial_hsu_get_mctrl,
@@ -1205,6 +1212,7 @@ static struct uart_driver serial_hsu_reg = {
.major = TTY_MAJOR,
.minor = 128,
.nr = 3,
+ .cons = SERIAL_HSU_CONSOLE,
};
#ifdef CONFIG_PM
@@ -1249,6 +1257,34 @@ static int serial_hsu_resume(struct pci_dev *pdev)
#define serial_hsu_resume NULL
#endif
+#ifdef CONFIG_PM_RUNTIME
+static int serial_hsu_runtime_idle(struct device *dev)
+{
+ pm_schedule_suspend(dev, 500);
+ return -EBUSY;
+}
+
+static int serial_hsu_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int serial_hsu_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+#else
+#define serial_hsu_runtime_idle NULL
+#define serial_hsu_runtime_suspend NULL
+#define serial_hsu_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops serial_hsu_pm_ops = {
+ .runtime_suspend = serial_hsu_runtime_suspend,
+ .runtime_resume = serial_hsu_runtime_resume,
+ .runtime_idle = serial_hsu_runtime_idle,
+};
+
/* temp global pointer before we settle down on using one or four PCI dev */
static struct hsu_port *phsu;
@@ -1306,15 +1342,12 @@ static int serial_hsu_probe(struct pci_dev *pdev,
}
uart_add_one_port(&serial_hsu_reg, &uport->port);
-#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE
- if (index == 2) {
- register_console(&serial_hsu_console);
- uport->port.cons = &serial_hsu_console;
- }
-#endif
pci_set_drvdata(pdev, uport);
}
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
return 0;
err_disable:
@@ -1411,19 +1444,21 @@ static void serial_hsu_remove(struct pci_dev *pdev)
if (!priv)
return;
+ pm_runtime_forbid(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+
/* For port 0/1/2, priv is the address of uart_hsu_port */
if (pdev->device != 0x081E) {
up = priv;
uart_remove_one_port(&serial_hsu_reg, &up->port);
}
- pci_set_drvdata(pdev, NULL);
free_irq(pdev->irq, priv);
pci_disable_device(pdev);
}
/* First 3 are UART ports, and the 4th is the DMA */
-static const struct pci_device_id pci_ids[] __devinitdata = {
+static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) },
@@ -1435,9 +1470,12 @@ static struct pci_driver hsu_pci_driver = {
.name = "HSU serial",
.id_table = pci_ids,
.probe = serial_hsu_probe,
- .remove = __devexit_p(serial_hsu_remove),
+ .remove = serial_hsu_remove,
.suspend = serial_hsu_suspend,
.resume = serial_hsu_resume,
+ .driver = {
+ .pm = &serial_hsu_pm_ops,
+ },
};
static int __init hsu_pci_init(void)
@@ -1467,4 +1505,4 @@ module_init(hsu_pci_init);
module_exit(hsu_pci_exit);
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:medfield-hsu");
+MODULE_DEVICE_TABLE(pci, pci_ids);