mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-16 22:54:39 +08:00
TTY/Serial driver patches for 4.4-rc1
Here is the big tty and serial driver update for 4.4-rc1. Lots of serial driver updates and a few small tty core changes. Full details in the shortlog. All of these have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlY6f64ACgkQMUfUDdst+ykf8gCfYPjtHy5hD/TsharaeXROnVgi W8cAn16xk1Nmnde220MNNpO6zDu65G/1 =kslf -----END PGP SIGNATURE----- Merge tag 'tty-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver updates from Greg KH: "Here is the big tty and serial driver update for 4.4-rc1. Lots of serial driver updates and a few small tty core changes. Full details in the shortlog. All of these have been in linux-next for a while" * tag 'tty-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (148 commits) tty: Use unbound workqueue for all input workers tty: Abstract tty buffer work tty: Prevent tty teardown during tty_write_message() tty: core: Use correct spinlock flavor in tiocspgrp() tty: Combine SIGTTOU/SIGTTIN handling serial: amba-pl011: fix incorrect integer size in pl011_fifo_to_tty() ttyFDC: Fix build problems due to use of module_{init,exit} tty: remove unneeded return statement serial: 8250_mid: add support for DMA engine handling from UART MMIO dmaengine: hsu: remove platform data dmaengine: hsu: introduce stubs for the exported functions dmaengine: hsu: make the UART driver in control of selecting this driver serial: fix mctrl helper functions serial: 8250_pci: Intel MID UART support to its own driver serial: fsl_lpuart: add earlycon support tty: disable unbind for old 74xx based serial/mpsc console port serial: pl011: Spelling s/clocks-names/clock-names/ n_tty: Remove reader wakeups for TTY_BREAK/TTY_PARITY chars tty: synclink, fix indentation serial: at91, fix rs485 properties ...
This commit is contained in:
commit
fd0d351de7
@ -1,7 +1,8 @@
|
||||
* Ingenic SoC UART
|
||||
|
||||
Required properties:
|
||||
- compatible : "ingenic,jz4740-uart" or "ingenic,jz4780-uart"
|
||||
- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart",
|
||||
"ingenic,jz4775-uart" or "ingenic,jz4780-uart"
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : should contain uart interrupt.
|
||||
- clocks : phandles to the module & baud clocks.
|
||||
|
@ -19,7 +19,7 @@ Optional properties:
|
||||
must correspond to the PCLK clocking the internal logic
|
||||
of the block. Just listing one clock (the first one) is
|
||||
deprecated.
|
||||
- clocks-names:
|
||||
- clock-names:
|
||||
When present, the first clock listed must be named
|
||||
"uartclk" and the second clock listed must be named
|
||||
"apb_pclk"
|
||||
|
@ -26,6 +26,12 @@ Required properties:
|
||||
Optional properties:
|
||||
- dmas: Should contain dma specifiers for transmit and receive channels
|
||||
- dma-names: Should contain "tx" for transmit and "rx" for receive channels
|
||||
- qcom,tx-crci: Identificator <u32> for Client Rate Control Interface to be
|
||||
used with TX DMA channel. Required when using DMA for transmission
|
||||
with UARTDM v1.3 and bellow.
|
||||
- qcom,rx-crci: Identificator <u32> for Client Rate Control Interface to be
|
||||
used with RX DMA channel. Required when using DMA for reception
|
||||
with UARTDM v1.3 and bellow.
|
||||
|
||||
Note: Aliases may be defined to ensure the correct ordering of the UARTs.
|
||||
The alias serialN will result in the UART being assigned port N. If any
|
||||
|
@ -23,6 +23,8 @@ Required properties:
|
||||
- "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART.
|
||||
- "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART.
|
||||
- "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
|
||||
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
|
||||
- "renesas,scif" for generic SCIF compatible UART.
|
||||
|
@ -15,6 +15,9 @@ The supplying peripheral clock can also be handled, needing a second property
|
||||
Required elements: "baudclk", "apb_pclk"
|
||||
|
||||
Optional properties:
|
||||
- snps,uart-16550-compatible : reflects the value of UART_16550_COMPATIBLE
|
||||
configuration parameter. Define this if your UART does not implement the busy
|
||||
functionality.
|
||||
- resets : phandle to the parent reset controller.
|
||||
- reg-shift : quantity to shift the register offsets by. If this property is
|
||||
not present then the register offsets are not shifted.
|
||||
|
@ -1024,6 +1024,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
serial port must already be setup and configured.
|
||||
Options are not yet supported.
|
||||
|
||||
lpuart,<addr>
|
||||
lpuart32,<addr>
|
||||
Use early console provided by Freescale LP UART driver
|
||||
found on Freescale Vybrid and QorIQ LS1021A processors.
|
||||
A valid base address must be provided, and the serial
|
||||
port must already be setup and configured.
|
||||
|
||||
earlyprintk= [X86,SH,BLACKFIN,ARM,M68k]
|
||||
earlyprintk=vga
|
||||
earlyprintk=efi
|
||||
|
@ -439,11 +439,13 @@ Modem control lines via GPIO
|
||||
|
||||
Some helpers are provided in order to set/get modem control lines via GPIO.
|
||||
|
||||
mctrl_gpio_init(dev, idx):
|
||||
mctrl_gpio_init(port, idx):
|
||||
This will get the {cts,rts,...}-gpios from device tree if they are
|
||||
present and request them, set direction etc, and return an
|
||||
allocated structure. devm_* functions are used, so there's no need
|
||||
to call mctrl_gpio_free().
|
||||
As this sets up the irq handling make sure to not handle changes to the
|
||||
gpio input lines in your driver, too.
|
||||
|
||||
mctrl_gpio_free(dev, gpios):
|
||||
This will free the requested gpios in mctrl_gpio_init().
|
||||
@ -458,3 +460,9 @@ mctrl_gpio_set(gpios, mctrl):
|
||||
|
||||
mctrl_gpio_get(gpios, mctrl):
|
||||
This will update mctrl with the gpios values.
|
||||
|
||||
mctrl_gpio_enable_ms(gpios):
|
||||
Enables irqs and handling of changes to the ms lines.
|
||||
|
||||
mctrl_gpio_disable_ms(gpios):
|
||||
Disables irqs and handling of changes to the ms lines.
|
||||
|
@ -39,8 +39,13 @@ TTY side interfaces:
|
||||
open() - Called when the line discipline is attached to
|
||||
the terminal. No other call into the line
|
||||
discipline for this tty will occur until it
|
||||
completes successfully. Returning an error will
|
||||
prevent the ldisc from being attached. Can sleep.
|
||||
completes successfully. Should initialize any
|
||||
state needed by the ldisc, and set receive_room
|
||||
in the tty_struct to the maximum amount of data
|
||||
the line discipline is willing to accept from the
|
||||
driver with a single call to receive_buf().
|
||||
Returning an error will prevent the ldisc from
|
||||
being attached. Can sleep.
|
||||
|
||||
close() - This is called on a terminal when the line
|
||||
discipline is being unplugged. At the point of
|
||||
@ -52,9 +57,16 @@ hangup() - Called when the tty line is hung up.
|
||||
No further calls into the ldisc code will occur.
|
||||
The return value is ignored. Can sleep.
|
||||
|
||||
write() - A process is writing data through the line
|
||||
discipline. Multiple write calls are serialized
|
||||
by the tty layer for the ldisc. May sleep.
|
||||
read() - (optional) A process requests reading data from
|
||||
the line. Multiple read calls may occur in parallel
|
||||
and the ldisc must deal with serialization issues.
|
||||
If not defined, the process will receive an EIO
|
||||
error. May sleep.
|
||||
|
||||
write() - (optional) A process requests writing data to the
|
||||
line. Multiple write calls are serialized by the
|
||||
tty layer for the ldisc. If not defined, the
|
||||
process will receive an EIO error. May sleep.
|
||||
|
||||
flush_buffer() - (optional) May be called at any point between
|
||||
open and close, and instructs the line discipline
|
||||
@ -69,27 +81,33 @@ set_termios() - (optional) Called on termios structure changes.
|
||||
termios semaphore so allowed to sleep. Serialized
|
||||
against itself only.
|
||||
|
||||
read() - Move data from the line discipline to the user.
|
||||
Multiple read calls may occur in parallel and the
|
||||
ldisc must deal with serialization issues. May
|
||||
sleep.
|
||||
poll() - (optional) Check the status for the poll/select
|
||||
calls. Multiple poll calls may occur in parallel.
|
||||
May sleep.
|
||||
|
||||
poll() - Check the status for the poll/select calls. Multiple
|
||||
poll calls may occur in parallel. May sleep.
|
||||
ioctl() - (optional) Called when an ioctl is handed to the
|
||||
tty layer that might be for the ldisc. Multiple
|
||||
ioctl calls may occur in parallel. May sleep.
|
||||
|
||||
ioctl() - Called when an ioctl is handed to the tty layer
|
||||
that might be for the ldisc. Multiple ioctl calls
|
||||
may occur in parallel. May sleep.
|
||||
|
||||
compat_ioctl() - Called when a 32 bit ioctl is handed to the tty layer
|
||||
that might be for the ldisc. Multiple ioctl calls
|
||||
may occur in parallel. May sleep.
|
||||
compat_ioctl() - (optional) Called when a 32 bit ioctl is handed
|
||||
to the tty layer that might be for the ldisc.
|
||||
Multiple ioctl calls may occur in parallel.
|
||||
May sleep.
|
||||
|
||||
Driver Side Interfaces:
|
||||
|
||||
receive_buf() - Hand buffers of bytes from the driver to the ldisc
|
||||
for processing. Semantics currently rather
|
||||
mysterious 8(
|
||||
receive_buf() - (optional) Called by the low-level driver to hand
|
||||
a buffer of received bytes to the ldisc for
|
||||
processing. The number of bytes is guaranteed not
|
||||
to exceed the current value of tty->receive_room.
|
||||
All bytes must be processed.
|
||||
|
||||
receive_buf2() - (optional) Called by the low-level driver to hand
|
||||
a buffer of received bytes to the ldisc for
|
||||
processing. Returns the number of bytes processed.
|
||||
|
||||
If both receive_buf() and receive_buf2() are
|
||||
defined, receive_buf2() should be preferred.
|
||||
|
||||
write_wakeup() - May be called at any point between open and close.
|
||||
The TTY_DO_WRITE_WAKEUP flag indicates if a call
|
||||
|
55
arch/arm64/include/asm/dcc.h
Normal file
55
arch/arm64/include/asm/dcc.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* A call to __dcc_getchar() or __dcc_putchar() is typically followed by
|
||||
* a call to __dcc_getstatus(). We want to make sure that the CPU does
|
||||
* not speculative read the DCC status before executing the read or write
|
||||
* instruction. That's what the ISBs are for.
|
||||
*
|
||||
* The 'volatile' ensures that the compiler does not cache the status bits,
|
||||
* and instead reads the DCC register every time.
|
||||
*/
|
||||
#ifndef __ASM_DCC_H
|
||||
#define __ASM_DCC_H
|
||||
|
||||
#include <asm/barrier.h>
|
||||
|
||||
static inline u32 __dcc_getstatus(void)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
asm volatile("mrs %0, mdccsr_el0" : "=r" (ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline char __dcc_getchar(void)
|
||||
{
|
||||
char c;
|
||||
|
||||
asm volatile("mrs %0, dbgdtrrx_el0" : "=r" (c));
|
||||
isb();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline void __dcc_putchar(char c)
|
||||
{
|
||||
/*
|
||||
* The typecast is to make absolutely certain that 'c' is
|
||||
* zero-extended.
|
||||
*/
|
||||
asm volatile("msr dbgdtrtx_el0, %0"
|
||||
: : "r" ((unsigned long)(unsigned char)c));
|
||||
isb();
|
||||
}
|
||||
|
||||
#endif
|
@ -2507,15 +2507,6 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
|
||||
printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
|
||||
__FILE__, __LINE__, tty->driver->name, port->count);
|
||||
|
||||
/* If port is closing, signal caller to try again */
|
||||
if (port->flags & ASYNC_CLOSING){
|
||||
wait_event_interruptible_tty(tty, port->close_wait,
|
||||
!(port->flags & ASYNC_CLOSING));
|
||||
retval = ((port->flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
spin_lock_irqsave(&info->netlock, flags);
|
||||
|
@ -5,10 +5,5 @@ config HSU_DMA
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
|
||||
config HSU_DMA_PCI
|
||||
tristate "High Speed UART DMA PCI driver"
|
||||
depends on PCI
|
||||
select HSU_DMA
|
||||
help
|
||||
Support the High Speed UART DMA on the platfroms that
|
||||
enumerate it as a PCI device. For example, Intel Medfield
|
||||
has integrated this HSU DMA controller.
|
||||
tristate
|
||||
depends on HSU_DMA && PCI
|
||||
|
@ -146,7 +146,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
|
||||
u32 sr;
|
||||
|
||||
/* Sanity check */
|
||||
if (nr >= chip->pdata->nr_channels)
|
||||
if (nr >= chip->hsu->nr_channels)
|
||||
return IRQ_NONE;
|
||||
|
||||
hsuc = &chip->hsu->chan[nr];
|
||||
@ -375,7 +375,6 @@ static void hsu_dma_free_chan_resources(struct dma_chan *chan)
|
||||
int hsu_dma_probe(struct hsu_dma_chip *chip)
|
||||
{
|
||||
struct hsu_dma *hsu;
|
||||
struct hsu_dma_platform_data *pdata = chip->pdata;
|
||||
void __iomem *addr = chip->regs + chip->offset;
|
||||
unsigned short i;
|
||||
int ret;
|
||||
@ -386,25 +385,16 @@ int hsu_dma_probe(struct hsu_dma_chip *chip)
|
||||
|
||||
chip->hsu = hsu;
|
||||
|
||||
if (!pdata) {
|
||||
pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
/* Calculate nr_channels from the IO space length */
|
||||
hsu->nr_channels = (chip->length - chip->offset) / HSU_DMA_CHAN_LENGTH;
|
||||
|
||||
chip->pdata = pdata;
|
||||
|
||||
/* Guess nr_channels from the IO space length */
|
||||
pdata->nr_channels = (chip->length - chip->offset) /
|
||||
HSU_DMA_CHAN_LENGTH;
|
||||
}
|
||||
|
||||
hsu->chan = devm_kcalloc(chip->dev, pdata->nr_channels,
|
||||
hsu->chan = devm_kcalloc(chip->dev, hsu->nr_channels,
|
||||
sizeof(*hsu->chan), GFP_KERNEL);
|
||||
if (!hsu->chan)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&hsu->dma.channels);
|
||||
for (i = 0; i < pdata->nr_channels; i++) {
|
||||
for (i = 0; i < hsu->nr_channels; i++) {
|
||||
struct hsu_dma_chan *hsuc = &hsu->chan[i];
|
||||
|
||||
hsuc->vchan.desc_free = hsu_dma_desc_free;
|
||||
@ -440,7 +430,7 @@ int hsu_dma_probe(struct hsu_dma_chip *chip)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(chip->dev, "Found HSU DMA, %d channels\n", pdata->nr_channels);
|
||||
dev_info(chip->dev, "Found HSU DMA, %d channels\n", hsu->nr_channels);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hsu_dma_probe);
|
||||
@ -452,7 +442,7 @@ int hsu_dma_remove(struct hsu_dma_chip *chip)
|
||||
|
||||
dma_async_device_unregister(&hsu->dma);
|
||||
|
||||
for (i = 0; i < chip->pdata->nr_channels; i++) {
|
||||
for (i = 0; i < hsu->nr_channels; i++) {
|
||||
struct hsu_dma_chan *hsuc = &hsu->chan[i];
|
||||
|
||||
tasklet_kill(&hsuc->vchan.task);
|
||||
|
@ -107,6 +107,7 @@ struct hsu_dma {
|
||||
|
||||
/* channels */
|
||||
struct hsu_dma_chan *chan;
|
||||
unsigned short nr_channels;
|
||||
};
|
||||
|
||||
static inline struct hsu_dma *to_hsu_dma(struct dma_device *ddev)
|
||||
|
@ -31,7 +31,7 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
|
||||
for (i = 0; i < chip->pdata->nr_channels; i++) {
|
||||
for (i = 0; i < chip->hsu->nr_channels; i++) {
|
||||
if (dmaisr & 0x1)
|
||||
ret |= hsu_dma_irq(chip, i);
|
||||
dmaisr >>= 1;
|
||||
|
@ -1582,7 +1582,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
* line status register.
|
||||
*/
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
tty_wait_until_sent_from_close(tty, 3000); /* 30 seconds timeout */
|
||||
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
|
@ -1576,15 +1576,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
||||
current->pid, info->port.count);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the port is the middle of closing, bail out now
|
||||
*/
|
||||
if (info->port.flags & ASYNC_CLOSING) {
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start up serial port
|
||||
*/
|
||||
|
@ -81,7 +81,7 @@ config HVC_UDBG
|
||||
|
||||
config HVC_DCC
|
||||
bool "ARM JTAG DCC console"
|
||||
depends on ARM
|
||||
depends on ARM || ARM64
|
||||
select HVC_DRIVER
|
||||
help
|
||||
This console uses the JTAG DCC on ARM to create a console under the HVC
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/sysrq.h>
|
||||
@ -418,7 +418,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
||||
* there is no buffered data otherwise sleeps on a wait queue
|
||||
* waking periodically to check chars_in_buffer().
|
||||
*/
|
||||
tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
|
||||
tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
|
||||
} else {
|
||||
if (hp->port.count < 0)
|
||||
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
|
||||
@ -1005,19 +1005,3 @@ put_tty:
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This isn't particularly necessary due to this being a console driver
|
||||
* but it is nice to be thorough.
|
||||
*/
|
||||
static void __exit hvc_exit(void)
|
||||
{
|
||||
if (hvc_driver) {
|
||||
kthread_stop(hvc_task);
|
||||
|
||||
tty_unregister_driver(hvc_driver);
|
||||
/* return tty_struct instances allocated in hvc_init(). */
|
||||
put_tty_driver(hvc_driver);
|
||||
unregister_console(&hvc_console);
|
||||
}
|
||||
}
|
||||
module_exit(hvc_exit);
|
||||
|
@ -70,20 +70,27 @@ static const struct hv_ops hvc_dcc_get_put_ops = {
|
||||
|
||||
static int __init hvc_dcc_console_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!hvc_dcc_check())
|
||||
return -ENODEV;
|
||||
|
||||
hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
|
||||
return 0;
|
||||
/* Returns -1 if error */
|
||||
ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
|
||||
|
||||
return ret < 0 ? -ENODEV : 0;
|
||||
}
|
||||
console_initcall(hvc_dcc_console_init);
|
||||
|
||||
static int __init hvc_dcc_init(void)
|
||||
{
|
||||
struct hvc_struct *p;
|
||||
|
||||
if (!hvc_dcc_check())
|
||||
return -ENODEV;
|
||||
|
||||
hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
|
||||
return 0;
|
||||
p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
|
||||
|
||||
return PTR_ERR_OR_ZERO(p);
|
||||
}
|
||||
device_initcall(hvc_dcc_init);
|
||||
|
@ -1230,7 +1230,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
||||
irq = hvcsd->vdev->irq;
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
||||
tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT);
|
||||
tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
|
||||
|
||||
/*
|
||||
* This line is important because it tells hvcs_open that this
|
||||
|
@ -977,7 +977,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
|
||||
/* Try requesting the IRQ */
|
||||
if (priv->irq >= 0) {
|
||||
/*
|
||||
* IRQF_SHARED, IRQF_NO_SUSPEND: The FDC IRQ may be shared with
|
||||
* IRQF_SHARED, IRQF_COND_SUSPEND: The FDC IRQ may be shared with
|
||||
* other local interrupts such as the timer which sets
|
||||
* IRQF_TIMER (including IRQF_NO_SUSPEND).
|
||||
*
|
||||
@ -987,7 +987,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
|
||||
*/
|
||||
ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr,
|
||||
IRQF_PERCPU | IRQF_SHARED |
|
||||
IRQF_NO_THREAD | IRQF_NO_SUSPEND,
|
||||
IRQF_NO_THREAD | IRQF_COND_SUSPEND,
|
||||
priv->fdc_name, priv);
|
||||
if (ret)
|
||||
priv->irq = -1;
|
||||
@ -1048,38 +1048,6 @@ err_destroy_ports:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mips_ejtag_fdc_tty_remove(struct mips_cdmm_device *dev)
|
||||
{
|
||||
struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev);
|
||||
struct mips_ejtag_fdc_tty_port *dport;
|
||||
int nport;
|
||||
unsigned int cfg;
|
||||
|
||||
if (priv->irq >= 0) {
|
||||
raw_spin_lock_irq(&priv->lock);
|
||||
cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
|
||||
/* Disable interrupts */
|
||||
cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
|
||||
cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
|
||||
cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
|
||||
mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
|
||||
raw_spin_unlock_irq(&priv->lock);
|
||||
} else {
|
||||
priv->removing = true;
|
||||
del_timer_sync(&priv->poll_timer);
|
||||
}
|
||||
kthread_stop(priv->thread);
|
||||
if (dev->cpu == 0)
|
||||
mips_ejtag_fdc_con.tty_drv = NULL;
|
||||
tty_unregister_driver(priv->driver);
|
||||
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
|
||||
dport = &priv->ports[nport];
|
||||
tty_port_destroy(&dport->port);
|
||||
}
|
||||
put_tty_driver(priv->driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev)
|
||||
{
|
||||
struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev);
|
||||
@ -1152,12 +1120,11 @@ static struct mips_cdmm_driver mips_ejtag_fdc_tty_driver = {
|
||||
.name = "mips_ejtag_fdc",
|
||||
},
|
||||
.probe = mips_ejtag_fdc_tty_probe,
|
||||
.remove = mips_ejtag_fdc_tty_remove,
|
||||
.cpu_down = mips_ejtag_fdc_tty_cpu_down,
|
||||
.cpu_up = mips_ejtag_fdc_tty_cpu_up,
|
||||
.id_table = mips_ejtag_fdc_tty_ids,
|
||||
};
|
||||
module_mips_cdmm_driver(mips_ejtag_fdc_tty_driver);
|
||||
builtin_mips_cdmm_driver(mips_ejtag_fdc_tty_driver);
|
||||
|
||||
static int __init mips_ejtag_fdc_init_console(void)
|
||||
{
|
||||
|
@ -276,7 +276,7 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
|
||||
add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
|
||||
error_code, NULL);
|
||||
}
|
||||
wake_up_interruptible(&pInfo->read_wait);
|
||||
wake_up_interruptible(&pInfo->tty->read_wait);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pInfo->lock, flags);
|
||||
@ -542,7 +542,7 @@ static void on_receive_block(struct r3964_info *pInfo)
|
||||
pBlock);
|
||||
}
|
||||
}
|
||||
wake_up_interruptible(&pInfo->read_wait);
|
||||
wake_up_interruptible(&pInfo->tty->read_wait);
|
||||
|
||||
pInfo->state = R3964_IDLE;
|
||||
|
||||
@ -978,8 +978,8 @@ static int r3964_open(struct tty_struct *tty)
|
||||
}
|
||||
|
||||
spin_lock_init(&pInfo->lock);
|
||||
mutex_init(&pInfo->read_lock);
|
||||
pInfo->tty = tty;
|
||||
init_waitqueue_head(&pInfo->read_wait);
|
||||
pInfo->priority = R3964_MASTER;
|
||||
pInfo->rx_first = pInfo->rx_last = NULL;
|
||||
pInfo->tx_first = pInfo->tx_last = NULL;
|
||||
@ -1045,7 +1045,6 @@ static void r3964_close(struct tty_struct *tty)
|
||||
}
|
||||
|
||||
/* Free buffers: */
|
||||
wake_up_interruptible(&pInfo->read_wait);
|
||||
kfree(pInfo->rx_buf);
|
||||
TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
|
||||
kfree(pInfo->tx_buf);
|
||||
@ -1065,7 +1064,16 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||
|
||||
TRACE_L("read()");
|
||||
|
||||
tty_lock(tty);
|
||||
/*
|
||||
* Internal serialization of reads.
|
||||
*/
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (!mutex_trylock(&pInfo->read_lock))
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
if (mutex_lock_interruptible(&pInfo->read_lock))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
pClient = findClient(pInfo, task_pid(current));
|
||||
if (pClient) {
|
||||
@ -1077,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||
goto unlock;
|
||||
}
|
||||
/* block until there is a message: */
|
||||
wait_event_interruptible_tty(tty, pInfo->read_wait,
|
||||
wait_event_interruptible(tty->read_wait,
|
||||
(pMsg = remove_msg(pInfo, pClient)));
|
||||
}
|
||||
|
||||
@ -1107,7 +1115,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
ret = -EPERM;
|
||||
unlock:
|
||||
tty_unlock(tty);
|
||||
mutex_unlock(&pInfo->read_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1156,8 +1164,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
|
||||
pHeader->locks = 0;
|
||||
pHeader->owner = NULL;
|
||||
|
||||
tty_lock(tty);
|
||||
|
||||
pClient = findClient(pInfo, task_pid(current));
|
||||
if (pClient) {
|
||||
pHeader->owner = pClient;
|
||||
@ -1175,8 +1181,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
|
||||
add_tx_queue(pInfo, pHeader);
|
||||
trigger_transmit(pInfo);
|
||||
|
||||
tty_unlock(tty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1227,7 +1231,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
|
||||
|
||||
pClient = findClient(pInfo, task_pid(current));
|
||||
if (pClient) {
|
||||
poll_wait(file, &pInfo->read_wait, wait);
|
||||
poll_wait(file, &tty->read_wait, wait);
|
||||
spin_lock_irqsave(&pInfo->lock, flags);
|
||||
pMsg = pClient->first_msg;
|
||||
spin_unlock_irqrestore(&pInfo->lock, flags);
|
||||
|
@ -201,7 +201,7 @@ static void n_tty_kick_worker(struct tty_struct *tty)
|
||||
*/
|
||||
WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
|
||||
"scheduling buffer work for halted ldisc\n");
|
||||
queue_work(system_unbound_wq, &tty->port->buf.work);
|
||||
tty_buffer_restart_work(tty->port);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1179,8 +1179,6 @@ static void n_tty_receive_break(struct tty_struct *tty)
|
||||
put_tty_queue('\0', ldata);
|
||||
}
|
||||
put_tty_queue('\0', ldata);
|
||||
if (waitqueue_active(&tty->read_wait))
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1237,8 +1235,6 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
|
||||
put_tty_queue('\0', ldata);
|
||||
} else
|
||||
put_tty_queue(c, ldata);
|
||||
if (waitqueue_active(&tty->read_wait))
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2142,37 +2138,15 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
|
||||
|
||||
static int job_control(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
struct pid *pgrp;
|
||||
|
||||
/* Job control check -- must be done at start and after
|
||||
every sleep (POSIX.1 7.1.1.4). */
|
||||
/* NOTE: not yet done after every sleep pending a thorough
|
||||
check of the logic of this change. -- jlc */
|
||||
/* don't stop on /dev/console */
|
||||
if (file->f_op->write == redirected_tty_write ||
|
||||
current->signal->tty != tty)
|
||||
if (file->f_op->write == redirected_tty_write)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
pgrp = task_pgrp(current);
|
||||
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
if (!tty->pgrp)
|
||||
printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
|
||||
else if (pgrp != tty->pgrp) {
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) {
|
||||
rcu_read_unlock();
|
||||
return -EIO;
|
||||
}
|
||||
kill_pgrp(pgrp, SIGTTIN, 1);
|
||||
rcu_read_unlock();
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
return __tty_check_change(tty, SIGTTIN);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/tty.h>
|
||||
@ -501,6 +500,10 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
|
||||
}
|
||||
|
||||
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
|
||||
/*
|
||||
* not really modular, but the easiest way to keep compat with existing
|
||||
* bootargs behaviour is to continue using module_param here.
|
||||
*/
|
||||
module_param(legacy_count, int, 0);
|
||||
|
||||
/*
|
||||
@ -877,4 +880,4 @@ static int __init pty_init(void)
|
||||
unix98_pty_init();
|
||||
return 0;
|
||||
}
|
||||
module_init(pty_init);
|
||||
device_initcall(pty_init);
|
||||
|
@ -895,14 +895,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
if (port->flags & ASYNC_CLOSING) {
|
||||
retval = wait_for_completion_interruptible(&info->close_wait);
|
||||
free_page(page);
|
||||
if (retval)
|
||||
return retval;
|
||||
return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
|
||||
}
|
||||
|
||||
/*
|
||||
* We must not sleep from here until the port is marked fully in use.
|
||||
*/
|
||||
@ -1057,7 +1049,6 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
|
||||
mutex_unlock(&port->mutex);
|
||||
tty_port_tty_set(port, NULL);
|
||||
|
||||
wake_up_interruptible(&port->close_wait);
|
||||
complete_all(&info->close_wait);
|
||||
atomic_dec(&rp_num_ports_open);
|
||||
|
||||
@ -1511,10 +1502,6 @@ static void rp_hangup(struct tty_struct *tty)
|
||||
#endif
|
||||
rp_flush_buffer(tty);
|
||||
spin_lock_irqsave(&info->port.lock, flags);
|
||||
if (info->port.flags & ASYNC_CLOSING) {
|
||||
spin_unlock_irqrestore(&info->port.lock, flags);
|
||||
return;
|
||||
}
|
||||
if (info->port.count)
|
||||
atomic_dec(&rp_num_ports_open);
|
||||
clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
|
||||
|
@ -560,8 +560,8 @@ static void rs_fair_output(void)
|
||||
struct m68k_serial *info = &m68k_soft[0];
|
||||
char c;
|
||||
|
||||
if (info == 0) return;
|
||||
if (info->xmit_buf == 0) return;
|
||||
if (info == NULL) return;
|
||||
if (info->xmit_buf == NULL) return;
|
||||
|
||||
local_irq_save(flags);
|
||||
left = info->xmit_cnt;
|
||||
@ -1071,7 +1071,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
}
|
||||
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&port->close_wait);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
@ -569,6 +569,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
|
||||
for (i = 0; i < nr_uarts; i++) {
|
||||
struct uart_8250_port *up = &serial8250_ports[i];
|
||||
|
||||
if (up->port.type == PORT_8250_CIR)
|
||||
continue;
|
||||
|
||||
if (up->port.dev)
|
||||
continue;
|
||||
|
||||
@ -1027,13 +1030,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
if (up->dl_write)
|
||||
uart->dl_write = up->dl_write;
|
||||
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
&uart->capabilities);
|
||||
if (uart->port.type != PORT_8250_CIR) {
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
&uart->capabilities);
|
||||
|
||||
ret = uart_add_one_port(&serial8250_reg, &uart->port);
|
||||
if (ret == 0)
|
||||
ret = uart->port.line;
|
||||
ret = uart_add_one_port(&serial8250_reg,
|
||||
&uart->port);
|
||||
if (ret == 0)
|
||||
ret = uart->port.line;
|
||||
} else {
|
||||
dev_info(uart->port.dev,
|
||||
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
|
||||
uart->port.iobase,
|
||||
(unsigned long long)uart->port.mapbase,
|
||||
uart->port.irq);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
|
@ -54,9 +54,6 @@ static void __dma_rx_complete(void *param)
|
||||
struct dma_tx_state state;
|
||||
int count;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma->rx_running = 0;
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
|
||||
@ -152,9 +149,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
|
||||
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
|
||||
return 0;
|
||||
|
@ -63,6 +63,9 @@ struct dw8250_data {
|
||||
struct clk *pclk;
|
||||
struct reset_control *rst;
|
||||
struct uart_8250_dma dma;
|
||||
|
||||
unsigned int skip_autocfg:1;
|
||||
unsigned int uart_16550_compatible:1;
|
||||
};
|
||||
|
||||
#define BYT_PRV_CLK 0x800
|
||||
@ -244,24 +247,77 @@ out:
|
||||
serial8250_do_set_termios(p, termios, old);
|
||||
}
|
||||
|
||||
static bool dw8250_dma_filter(struct dma_chan *chan, void *param)
|
||||
/*
|
||||
* dw8250_fallback_dma_filter will prevent the UART from getting just any free
|
||||
* channel on platforms that have DMA engines, but don't have any channels
|
||||
* assigned to the UART.
|
||||
*
|
||||
* REVISIT: This is a work around for limitation in the DMA Engine API. Once the
|
||||
* core problem is fixed, this function is no longer needed.
|
||||
*/
|
||||
static bool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dw8250_setup_port(struct uart_8250_port *up)
|
||||
static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct uart_port *p = &up->port;
|
||||
u32 reg = readl(p->membase + DW_UART_UCV);
|
||||
return param == chan->device->dev->parent;
|
||||
}
|
||||
|
||||
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
||||
{
|
||||
if (p->dev->of_node) {
|
||||
struct device_node *np = p->dev->of_node;
|
||||
int id;
|
||||
|
||||
/* get index of serial line, if found in DT aliases */
|
||||
id = of_alias_get_id(np, "serial");
|
||||
if (id >= 0)
|
||||
p->line = id;
|
||||
#ifdef CONFIG_64BIT
|
||||
if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
|
||||
p->serial_in = dw8250_serial_inq;
|
||||
p->serial_out = dw8250_serial_outq;
|
||||
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
|
||||
p->type = PORT_OCTEON;
|
||||
data->usr_reg = 0x27;
|
||||
data->skip_autocfg = true;
|
||||
}
|
||||
#endif
|
||||
} else if (has_acpi_companion(p->dev)) {
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->regshift = 2;
|
||||
p->serial_in = dw8250_serial_in32;
|
||||
p->set_termios = dw8250_set_termios;
|
||||
/* So far none of there implement the Busy Functionality */
|
||||
data->uart_16550_compatible = true;
|
||||
}
|
||||
|
||||
/* Platforms with iDMA */
|
||||
if (platform_get_resource_byname(to_platform_device(p->dev),
|
||||
IORESOURCE_MEM, "lpss_priv")) {
|
||||
p->set_termios = dw8250_set_termios;
|
||||
data->dma.rx_param = p->dev->parent;
|
||||
data->dma.tx_param = p->dev->parent;
|
||||
data->dma.fn = dw8250_idma_filter;
|
||||
}
|
||||
}
|
||||
|
||||
static void dw8250_setup_port(struct uart_port *p)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* If the Component Version Register returns zero, we know that
|
||||
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
|
||||
*/
|
||||
reg = readl(p->membase + DW_UART_UCV);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
|
||||
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
|
||||
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
|
||||
|
||||
reg = readl(p->membase + DW_UART_CPR);
|
||||
@ -273,7 +329,6 @@ static void dw8250_setup_port(struct uart_8250_port *up)
|
||||
p->type = PORT_16550A;
|
||||
p->flags |= UPF_FIXED_TYPE;
|
||||
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
||||
up->tx_loadsz = p->fifosize;
|
||||
up->capabilities = UART_CAP_FIFO;
|
||||
}
|
||||
|
||||
@ -281,131 +336,15 @@ static void dw8250_setup_port(struct uart_8250_port *up)
|
||||
up->capabilities |= UART_CAP_AFE;
|
||||
}
|
||||
|
||||
static int dw8250_probe_of(struct uart_port *p,
|
||||
struct dw8250_data *data)
|
||||
{
|
||||
struct device_node *np = p->dev->of_node;
|
||||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
u32 val;
|
||||
bool has_ucv = true;
|
||||
int id;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
|
||||
p->serial_in = dw8250_serial_inq;
|
||||
p->serial_out = dw8250_serial_outq;
|
||||
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
|
||||
p->type = PORT_OCTEON;
|
||||
data->usr_reg = 0x27;
|
||||
has_ucv = false;
|
||||
} else
|
||||
#endif
|
||||
if (!of_property_read_u32(np, "reg-io-width", &val)) {
|
||||
switch (val) {
|
||||
case 1:
|
||||
break;
|
||||
case 4:
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->serial_in = dw8250_serial_in32;
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
break;
|
||||
default:
|
||||
dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (has_ucv)
|
||||
dw8250_setup_port(up);
|
||||
|
||||
/* if we have a valid fifosize, try hooking up DMA here */
|
||||
if (p->fifosize) {
|
||||
up->dma = &data->dma;
|
||||
|
||||
up->dma->rxconf.src_maxburst = p->fifosize / 4;
|
||||
up->dma->txconf.dst_maxburst = p->fifosize / 4;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "reg-shift", &val))
|
||||
p->regshift = val;
|
||||
|
||||
/* get index of serial line, if found in DT aliases */
|
||||
id = of_alias_get_id(np, "serial");
|
||||
if (id >= 0)
|
||||
p->line = id;
|
||||
|
||||
if (of_property_read_bool(np, "dcd-override")) {
|
||||
/* Always report DCD as active */
|
||||
data->msr_mask_on |= UART_MSR_DCD;
|
||||
data->msr_mask_off |= UART_MSR_DDCD;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "dsr-override")) {
|
||||
/* Always report DSR as active */
|
||||
data->msr_mask_on |= UART_MSR_DSR;
|
||||
data->msr_mask_off |= UART_MSR_DDSR;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "cts-override")) {
|
||||
/* Always report CTS as active */
|
||||
data->msr_mask_on |= UART_MSR_CTS;
|
||||
data->msr_mask_off |= UART_MSR_DCTS;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "ri-override")) {
|
||||
/* Always report Ring indicator as inactive */
|
||||
data->msr_mask_off |= UART_MSR_RI;
|
||||
data->msr_mask_off |= UART_MSR_TERI;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct device *dev = param;
|
||||
|
||||
if (dev != chan->device->dev->parent)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int dw8250_probe_acpi(struct uart_8250_port *up,
|
||||
struct dw8250_data *data)
|
||||
{
|
||||
struct uart_port *p = &up->port;
|
||||
|
||||
dw8250_setup_port(up);
|
||||
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->serial_in = dw8250_serial_in32;
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
p->regshift = 2;
|
||||
|
||||
/* Platforms with iDMA */
|
||||
if (platform_get_resource_byname(to_platform_device(up->port.dev),
|
||||
IORESOURCE_MEM, "lpss_priv")) {
|
||||
data->dma.rx_param = up->port.dev->parent;
|
||||
data->dma.tx_param = up->port.dev->parent;
|
||||
data->dma.fn = dw8250_idma_filter;
|
||||
}
|
||||
|
||||
up->dma = &data->dma;
|
||||
up->dma->rxconf.src_maxburst = p->fifosize / 4;
|
||||
up->dma->txconf.dst_maxburst = p->fifosize / 4;
|
||||
|
||||
up->port.set_termios = dw8250_set_termios;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw8250_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port uart = {};
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
struct uart_port *p = &uart.port;
|
||||
struct dw8250_data *data;
|
||||
int err;
|
||||
u32 val;
|
||||
|
||||
if (!regs) {
|
||||
dev_err(&pdev->dev, "no registers defined\n");
|
||||
@ -418,29 +357,70 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
return irq;
|
||||
}
|
||||
|
||||
spin_lock_init(&uart.port.lock);
|
||||
uart.port.mapbase = regs->start;
|
||||
uart.port.irq = irq;
|
||||
uart.port.handle_irq = dw8250_handle_irq;
|
||||
uart.port.pm = dw8250_do_pm;
|
||||
uart.port.type = PORT_8250;
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
|
||||
uart.port.dev = &pdev->dev;
|
||||
spin_lock_init(&p->lock);
|
||||
p->mapbase = regs->start;
|
||||
p->irq = irq;
|
||||
p->handle_irq = dw8250_handle_irq;
|
||||
p->pm = dw8250_do_pm;
|
||||
p->type = PORT_8250;
|
||||
p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
|
||||
p->dev = &pdev->dev;
|
||||
p->iotype = UPIO_MEM;
|
||||
p->serial_in = dw8250_serial_in;
|
||||
p->serial_out = dw8250_serial_out;
|
||||
|
||||
uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
|
||||
resource_size(regs));
|
||||
if (!uart.port.membase)
|
||||
p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
|
||||
if (!p->membase)
|
||||
return -ENOMEM;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->dma.fn = dw8250_fallback_dma_filter;
|
||||
data->usr_reg = DW_UART_USR;
|
||||
p->private_data = data;
|
||||
|
||||
data->uart_16550_compatible = device_property_read_bool(p->dev,
|
||||
"snps,uart-16550-compatible");
|
||||
|
||||
err = device_property_read_u32(p->dev, "reg-shift", &val);
|
||||
if (!err)
|
||||
p->regshift = val;
|
||||
|
||||
err = device_property_read_u32(p->dev, "reg-io-width", &val);
|
||||
if (!err && val == 4) {
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->serial_in = dw8250_serial_in32;
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
}
|
||||
|
||||
if (device_property_read_bool(p->dev, "dcd-override")) {
|
||||
/* Always report DCD as active */
|
||||
data->msr_mask_on |= UART_MSR_DCD;
|
||||
data->msr_mask_off |= UART_MSR_DDCD;
|
||||
}
|
||||
|
||||
if (device_property_read_bool(p->dev, "dsr-override")) {
|
||||
/* Always report DSR as active */
|
||||
data->msr_mask_on |= UART_MSR_DSR;
|
||||
data->msr_mask_off |= UART_MSR_DDSR;
|
||||
}
|
||||
|
||||
if (device_property_read_bool(p->dev, "cts-override")) {
|
||||
/* Always report CTS as active */
|
||||
data->msr_mask_on |= UART_MSR_CTS;
|
||||
data->msr_mask_off |= UART_MSR_DCTS;
|
||||
}
|
||||
|
||||
if (device_property_read_bool(p->dev, "ri-override")) {
|
||||
/* Always report Ring indicator as inactive */
|
||||
data->msr_mask_off |= UART_MSR_RI;
|
||||
data->msr_mask_off |= UART_MSR_TERI;
|
||||
}
|
||||
|
||||
/* Always ask for fixed clock rate from a property. */
|
||||
device_property_read_u32(&pdev->dev, "clock-frequency",
|
||||
&uart.port.uartclk);
|
||||
device_property_read_u32(p->dev, "clock-frequency", &p->uartclk);
|
||||
|
||||
/* If there is separate baudclk, get the rate from it. */
|
||||
data->clk = devm_clk_get(&pdev->dev, "baudclk");
|
||||
@ -454,11 +434,11 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
|
||||
err);
|
||||
else
|
||||
uart.port.uartclk = clk_get_rate(data->clk);
|
||||
p->uartclk = clk_get_rate(data->clk);
|
||||
}
|
||||
|
||||
/* If no clock rate is defined, fail. */
|
||||
if (!uart.port.uartclk) {
|
||||
if (!p->uartclk) {
|
||||
dev_err(&pdev->dev, "clock rate not defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -484,26 +464,22 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
if (!IS_ERR(data->rst))
|
||||
reset_control_deassert(data->rst);
|
||||
|
||||
data->dma.rx_param = data;
|
||||
data->dma.tx_param = data;
|
||||
data->dma.fn = dw8250_dma_filter;
|
||||
dw8250_quirks(p, data);
|
||||
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.serial_in = dw8250_serial_in;
|
||||
uart.port.serial_out = dw8250_serial_out;
|
||||
uart.port.private_data = data;
|
||||
/* If the Busy Functionality is not implemented, don't handle it */
|
||||
if (data->uart_16550_compatible) {
|
||||
p->serial_out = NULL;
|
||||
p->handle_irq = NULL;
|
||||
}
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
err = dw8250_probe_of(&uart.port, data);
|
||||
if (err)
|
||||
goto err_reset;
|
||||
} else if (ACPI_HANDLE(&pdev->dev)) {
|
||||
err = dw8250_probe_acpi(&uart, data);
|
||||
if (err)
|
||||
goto err_reset;
|
||||
} else {
|
||||
err = -ENODEV;
|
||||
goto err_reset;
|
||||
if (!data->skip_autocfg)
|
||||
dw8250_setup_port(p);
|
||||
|
||||
/* If we have a valid fifosize, try hooking up DMA */
|
||||
if (p->fifosize) {
|
||||
data->dma.rxconf.src_maxburst = p->fifosize / 4;
|
||||
data->dma.txconf.dst_maxburst = p->fifosize / 4;
|
||||
uart.dma = &data->dma;
|
||||
}
|
||||
|
||||
data->line = serial8250_register_8250_port(&uart);
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <linux/tty.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_8250.h>
|
||||
@ -152,3 +154,5 @@ int __init early_serial8250_setup(struct earlycon_device *device,
|
||||
}
|
||||
EARLYCON_DECLARE(uart8250, early_serial8250_setup);
|
||||
EARLYCON_DECLARE(uart, early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
|
||||
|
@ -21,19 +21,33 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
/** ingenic_uart_config: SOC specific config data. */
|
||||
struct ingenic_uart_config {
|
||||
int tx_loadsz;
|
||||
int fifosize;
|
||||
};
|
||||
|
||||
struct ingenic_uart_data {
|
||||
struct clk *clk_module;
|
||||
struct clk *clk_baud;
|
||||
int line;
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match[];
|
||||
|
||||
#define UART_FCR_UME BIT(4)
|
||||
|
||||
#define UART_MCR_MDCE BIT(7)
|
||||
#define UART_MCR_FCM BIT(6)
|
||||
|
||||
static struct earlycon_device *early_device;
|
||||
|
||||
static uint8_t __init early_in(struct uart_port *port, int offset)
|
||||
@ -129,6 +143,8 @@ OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
|
||||
|
||||
static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
int ier;
|
||||
|
||||
switch (offset) {
|
||||
case UART_FCR:
|
||||
/* UART module enable */
|
||||
@ -136,9 +152,22 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||
break;
|
||||
|
||||
case UART_IER:
|
||||
/* Enable receive timeout interrupt with the
|
||||
* receive line status interrupt */
|
||||
value |= (value & 0x4) << 2;
|
||||
break;
|
||||
|
||||
case UART_MCR:
|
||||
/* If we have enabled modem status IRQs we should enable modem
|
||||
* mode. */
|
||||
ier = p->serial_in(p, UART_IER);
|
||||
|
||||
if (ier & UART_IER_MSI)
|
||||
value |= UART_MCR_MDCE | UART_MCR_FCM;
|
||||
else
|
||||
value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -146,14 +175,45 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||
writeb(value, p->membase + (offset << p->regshift));
|
||||
}
|
||||
|
||||
static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = readb(p->membase + (offset << p->regshift));
|
||||
|
||||
/* Hide non-16550 compliant bits from higher levels */
|
||||
switch (offset) {
|
||||
case UART_FCR:
|
||||
value &= ~UART_FCR_UME;
|
||||
break;
|
||||
|
||||
case UART_MCR:
|
||||
value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int ingenic_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port uart = {};
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct ingenic_uart_data *data;
|
||||
const struct ingenic_uart_config *cdata;
|
||||
const struct of_device_id *match;
|
||||
int err, line;
|
||||
|
||||
match = of_match_device(of_match, &pdev->dev);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
cdata = match->data;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "no registers/irq defined\n");
|
||||
return -EINVAL;
|
||||
@ -164,14 +224,18 @@ static int ingenic_uart_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&uart.port.lock);
|
||||
uart.port.type = PORT_16550;
|
||||
uart.port.type = PORT_16550A;
|
||||
uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.mapbase = regs->start;
|
||||
uart.port.regshift = 2;
|
||||
uart.port.serial_out = ingenic_uart_serial_out;
|
||||
uart.port.serial_in = ingenic_uart_serial_in;
|
||||
uart.port.irq = irq->start;
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.fifosize = cdata->fifosize;
|
||||
uart.tx_loadsz = cdata->tx_loadsz;
|
||||
uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;
|
||||
|
||||
/* Check for a fixed line number */
|
||||
line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
@ -241,10 +305,26 @@ static int ingenic_uart_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ingenic_uart_config jz4740_uart_config = {
|
||||
.tx_loadsz = 8,
|
||||
.fifosize = 16,
|
||||
};
|
||||
|
||||
static const struct ingenic_uart_config jz4760_uart_config = {
|
||||
.tx_loadsz = 16,
|
||||
.fifosize = 32,
|
||||
};
|
||||
|
||||
static const struct ingenic_uart_config jz4780_uart_config = {
|
||||
.tx_loadsz = 32,
|
||||
.fifosize = 64,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match[] = {
|
||||
{ .compatible = "ingenic,jz4740-uart" },
|
||||
{ .compatible = "ingenic,jz4775-uart" },
|
||||
{ .compatible = "ingenic,jz4780-uart" },
|
||||
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
|
||||
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
|
||||
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
|
||||
{ .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_match);
|
||||
|
326
drivers/tty/serial/8250/8250_mid.c
Normal file
326
drivers/tty/serial/8250/8250_mid.c
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* 8250_mid.c - Driver for UART on Intel Penwell and various other Intel SOCs
|
||||
*
|
||||
* Copyright (C) 2015 Intel Corporation
|
||||
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/rational.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <linux/dma/hsu.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b
|
||||
#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c
|
||||
#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d
|
||||
#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191
|
||||
#define PCI_DEVICE_ID_INTEL_DNV_UART 0x19d8
|
||||
|
||||
/* Intel MID Specific registers */
|
||||
#define INTEL_MID_UART_PS 0x30
|
||||
#define INTEL_MID_UART_MUL 0x34
|
||||
#define INTEL_MID_UART_DIV 0x38
|
||||
|
||||
struct mid8250;
|
||||
|
||||
struct mid8250_board {
|
||||
unsigned long freq;
|
||||
unsigned int base_baud;
|
||||
int (*setup)(struct mid8250 *, struct uart_port *p);
|
||||
void (*exit)(struct mid8250 *);
|
||||
};
|
||||
|
||||
struct mid8250 {
|
||||
int line;
|
||||
int dma_index;
|
||||
struct pci_dev *dma_dev;
|
||||
struct uart_8250_dma dma;
|
||||
struct mid8250_board *board;
|
||||
struct hsu_dma_chip dma_chip;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int pnw_setup(struct mid8250 *mid, struct uart_port *p)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(p->dev);
|
||||
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_PNW_UART1:
|
||||
mid->dma_index = 0;
|
||||
break;
|
||||
case PCI_DEVICE_ID_INTEL_PNW_UART2:
|
||||
mid->dma_index = 1;
|
||||
break;
|
||||
case PCI_DEVICE_ID_INTEL_PNW_UART3:
|
||||
mid->dma_index = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mid->dma_dev = pci_get_slot(pdev->bus,
|
||||
PCI_DEVFN(PCI_SLOT(pdev->devfn), 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tng_setup(struct mid8250 *mid, struct uart_port *p)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(p->dev);
|
||||
int index = PCI_FUNC(pdev->devfn);
|
||||
|
||||
/* Currently no support for HSU port0 */
|
||||
if (index-- == 0)
|
||||
return -ENODEV;
|
||||
|
||||
mid->dma_index = index;
|
||||
mid->dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnv_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct mid8250 *mid = p->private_data;
|
||||
int ret;
|
||||
|
||||
ret = hsu_dma_irq(&mid->dma_chip, 0);
|
||||
ret |= hsu_dma_irq(&mid->dma_chip, 1);
|
||||
|
||||
/* For now, letting the HW generate separate interrupt for the UART */
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
|
||||
}
|
||||
|
||||
#define DNV_DMA_CHAN_OFFSET 0x80
|
||||
|
||||
static int dnv_setup(struct mid8250 *mid, struct uart_port *p)
|
||||
{
|
||||
struct hsu_dma_chip *chip = &mid->dma_chip;
|
||||
struct pci_dev *pdev = to_pci_dev(p->dev);
|
||||
int ret;
|
||||
|
||||
chip->dev = &pdev->dev;
|
||||
chip->irq = pdev->irq;
|
||||
chip->regs = p->membase;
|
||||
chip->length = pci_resource_len(pdev, 0);
|
||||
chip->offset = DNV_DMA_CHAN_OFFSET;
|
||||
|
||||
/* Falling back to PIO mode if DMA probing fails */
|
||||
ret = hsu_dma_probe(chip);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
mid->dma_dev = pdev;
|
||||
|
||||
p->handle_irq = dnv_handle_irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dnv_exit(struct mid8250 *mid)
|
||||
{
|
||||
if (!mid->dma_dev)
|
||||
return;
|
||||
hsu_dma_remove(&mid->dma_chip);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void mid8250_set_termios(struct uart_port *p,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud = tty_termios_baud_rate(termios);
|
||||
struct mid8250 *mid = p->private_data;
|
||||
unsigned short ps = 16;
|
||||
unsigned long fuart = baud * ps;
|
||||
unsigned long w = BIT(24) - 1;
|
||||
unsigned long mul, div;
|
||||
|
||||
if (mid->board->freq < fuart) {
|
||||
/* Find prescaler value that satisfies Fuart < Fref */
|
||||
if (mid->board->freq > baud)
|
||||
ps = mid->board->freq / baud; /* baud rate too high */
|
||||
else
|
||||
ps = 1; /* PLL case */
|
||||
fuart = baud * ps;
|
||||
} else {
|
||||
/* Get Fuart closer to Fref */
|
||||
fuart *= rounddown_pow_of_two(mid->board->freq / fuart);
|
||||
}
|
||||
|
||||
rational_best_approximation(fuart, mid->board->freq, w, w, &mul, &div);
|
||||
p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */
|
||||
|
||||
writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
|
||||
writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
|
||||
writel(div, p->membase + INTEL_MID_UART_DIV);
|
||||
|
||||
serial8250_do_set_termios(p, termios, old);
|
||||
}
|
||||
|
||||
static bool mid8250_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct hsu_dma_slave *s = param;
|
||||
|
||||
if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id)
|
||||
return false;
|
||||
|
||||
chan->private = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int mid8250_dma_setup(struct mid8250 *mid, struct uart_8250_port *port)
|
||||
{
|
||||
struct uart_8250_dma *dma = &mid->dma;
|
||||
struct device *dev = port->port.dev;
|
||||
struct hsu_dma_slave *rx_param;
|
||||
struct hsu_dma_slave *tx_param;
|
||||
|
||||
if (!mid->dma_dev)
|
||||
return 0;
|
||||
|
||||
rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
|
||||
if (!rx_param)
|
||||
return -ENOMEM;
|
||||
|
||||
tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
|
||||
if (!tx_param)
|
||||
return -ENOMEM;
|
||||
|
||||
rx_param->chan_id = mid->dma_index * 2 + 1;
|
||||
tx_param->chan_id = mid->dma_index * 2;
|
||||
|
||||
dma->rxconf.src_maxburst = 64;
|
||||
dma->txconf.dst_maxburst = 64;
|
||||
|
||||
rx_param->dma_dev = &mid->dma_dev->dev;
|
||||
tx_param->dma_dev = &mid->dma_dev->dev;
|
||||
|
||||
dma->fn = mid8250_dma_filter;
|
||||
dma->rx_param = rx_param;
|
||||
dma->tx_param = tx_param;
|
||||
|
||||
port->dma = dma;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct uart_8250_port uart;
|
||||
struct mid8250 *mid;
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
mid = devm_kzalloc(&pdev->dev, sizeof(*mid), GFP_KERNEL);
|
||||
if (!mid)
|
||||
return -ENOMEM;
|
||||
|
||||
mid->board = (struct mid8250_board *)id->driver_data;
|
||||
|
||||
memset(&uart, 0, sizeof(struct uart_8250_port));
|
||||
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.irq = pdev->irq;
|
||||
uart.port.private_data = mid;
|
||||
uart.port.type = PORT_16750;
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.uartclk = mid->board->base_baud * 16;
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
uart.port.set_termios = mid8250_set_termios;
|
||||
|
||||
uart.port.mapbase = pci_resource_start(pdev, 0);
|
||||
uart.port.membase = pcim_iomap(pdev, 0, 0);
|
||||
if (!uart.port.membase)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mid->board->setup) {
|
||||
ret = mid->board->setup(mid, &uart.port);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mid8250_dma_setup(mid, &uart);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = serial8250_register_8250_port(&uart);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
mid->line = ret;
|
||||
|
||||
pci_set_drvdata(pdev, mid);
|
||||
return 0;
|
||||
err:
|
||||
if (mid->board->exit)
|
||||
mid->board->exit(mid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mid8250_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct mid8250 *mid = pci_get_drvdata(pdev);
|
||||
|
||||
if (mid->board->exit)
|
||||
mid->board->exit(mid);
|
||||
|
||||
serial8250_unregister_port(mid->line);
|
||||
}
|
||||
|
||||
static const struct mid8250_board pnw_board = {
|
||||
.freq = 50000000,
|
||||
.base_baud = 115200,
|
||||
.setup = pnw_setup,
|
||||
};
|
||||
|
||||
static const struct mid8250_board tng_board = {
|
||||
.freq = 38400000,
|
||||
.base_baud = 1843200,
|
||||
.setup = tng_setup,
|
||||
};
|
||||
|
||||
static const struct mid8250_board dnv_board = {
|
||||
.freq = 133333333,
|
||||
.base_baud = 115200,
|
||||
.setup = dnv_setup,
|
||||
.exit = dnv_exit,
|
||||
};
|
||||
|
||||
#define MID_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
|
||||
|
||||
static const struct pci_device_id pci_ids[] = {
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART1, pnw_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART2, pnw_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART3, pnw_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_TNG_UART, tng_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_DNV_UART, dnv_board),
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||
|
||||
static struct pci_driver mid8250_pci_driver = {
|
||||
.name = "8250_mid",
|
||||
.id_table = pci_ids,
|
||||
.probe = mid8250_probe,
|
||||
.remove = mid8250_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(mid8250_pci_driver);
|
||||
|
||||
MODULE_AUTHOR("Intel Corporation");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Intel MID UART driver");
|
@ -439,7 +439,6 @@ static void omap_8250_set_termios(struct uart_port *port,
|
||||
priv->xoff = termios->c_cc[VSTOP];
|
||||
|
||||
priv->efr = 0;
|
||||
up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
|
||||
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
|
||||
|
||||
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
|
||||
@ -726,6 +725,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
struct dma_tx_state state;
|
||||
int count;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
@ -741,8 +741,10 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
|
||||
count = dma->rx_size - state.residue;
|
||||
|
||||
tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||
p->port.icount.rx += count;
|
||||
ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||
|
||||
p->port.icount.rx += ret;
|
||||
p->port.icount.buf_overrun += count - ret;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
|
||||
|
@ -28,7 +28,6 @@
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/platform_data/dma-dw.h>
|
||||
#include <linux/platform_data/dma-hsu.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
@ -1508,167 +1507,6 @@ byt_serial_setup(struct serial_private *priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define INTEL_MID_UART_PS 0x30
|
||||
#define INTEL_MID_UART_MUL 0x34
|
||||
#define INTEL_MID_UART_DIV 0x38
|
||||
|
||||
static void intel_mid_set_termios(struct uart_port *p,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old,
|
||||
unsigned long fref)
|
||||
{
|
||||
unsigned int baud = tty_termios_baud_rate(termios);
|
||||
unsigned short ps = 16;
|
||||
unsigned long fuart = baud * ps;
|
||||
unsigned long w = BIT(24) - 1;
|
||||
unsigned long mul, div;
|
||||
|
||||
if (fref < fuart) {
|
||||
/* Find prescaler value that satisfies Fuart < Fref */
|
||||
if (fref > baud)
|
||||
ps = fref / baud; /* baud rate too high */
|
||||
else
|
||||
ps = 1; /* PLL case */
|
||||
fuart = baud * ps;
|
||||
} else {
|
||||
/* Get Fuart closer to Fref */
|
||||
fuart *= rounddown_pow_of_two(fref / fuart);
|
||||
}
|
||||
|
||||
rational_best_approximation(fuart, fref, w, w, &mul, &div);
|
||||
p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */
|
||||
|
||||
writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
|
||||
writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
|
||||
writel(div, p->membase + INTEL_MID_UART_DIV);
|
||||
|
||||
serial8250_do_set_termios(p, termios, old);
|
||||
}
|
||||
|
||||
static void intel_mid_set_termios_38_4M(struct uart_port *p,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
intel_mid_set_termios(p, termios, old, 38400000);
|
||||
}
|
||||
|
||||
static void intel_mid_set_termios_50M(struct uart_port *p,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
/*
|
||||
* The uart clk is 50Mhz, and the baud rate come from:
|
||||
* baud = 50M * MUL / (DIV * PS * DLAB)
|
||||
*/
|
||||
intel_mid_set_termios(p, termios, old, 50000000);
|
||||
}
|
||||
|
||||
static bool intel_mid_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct hsu_dma_slave *s = param;
|
||||
|
||||
if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id)
|
||||
return false;
|
||||
|
||||
chan->private = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int intel_mid_serial_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx,
|
||||
int index, struct pci_dev *dma_dev)
|
||||
{
|
||||
struct device *dev = port->port.dev;
|
||||
struct uart_8250_dma *dma;
|
||||
struct hsu_dma_slave *tx_param, *rx_param;
|
||||
|
||||
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma)
|
||||
return -ENOMEM;
|
||||
|
||||
tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
|
||||
if (!tx_param)
|
||||
return -ENOMEM;
|
||||
|
||||
rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
|
||||
if (!rx_param)
|
||||
return -ENOMEM;
|
||||
|
||||
rx_param->chan_id = index * 2 + 1;
|
||||
tx_param->chan_id = index * 2;
|
||||
|
||||
dma->rxconf.src_maxburst = 64;
|
||||
dma->txconf.dst_maxburst = 64;
|
||||
|
||||
rx_param->dma_dev = &dma_dev->dev;
|
||||
tx_param->dma_dev = &dma_dev->dev;
|
||||
|
||||
dma->fn = intel_mid_dma_filter;
|
||||
dma->rx_param = rx_param;
|
||||
dma->tx_param = tx_param;
|
||||
|
||||
port->port.type = PORT_16750;
|
||||
port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
port->dma = dma;
|
||||
|
||||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b
|
||||
#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c
|
||||
#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d
|
||||
|
||||
static int pnw_serial_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
struct pci_dev *pdev = priv->dev;
|
||||
struct pci_dev *dma_dev;
|
||||
int index;
|
||||
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_PNW_UART1:
|
||||
index = 0;
|
||||
break;
|
||||
case PCI_DEVICE_ID_INTEL_PNW_UART2:
|
||||
index = 1;
|
||||
break;
|
||||
case PCI_DEVICE_ID_INTEL_PNW_UART3:
|
||||
index = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3));
|
||||
|
||||
port->port.set_termios = intel_mid_set_termios_50M;
|
||||
|
||||
return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
|
||||
}
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191
|
||||
|
||||
static int tng_serial_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
struct pci_dev *pdev = priv->dev;
|
||||
struct pci_dev *dma_dev;
|
||||
int index = PCI_FUNC(pdev->devfn);
|
||||
|
||||
/* Currently no support for HSU port0 */
|
||||
if (index-- == 0)
|
||||
return -ENODEV;
|
||||
|
||||
dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0));
|
||||
|
||||
port->port.set_termios = intel_mid_set_termios_38_4M;
|
||||
|
||||
return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_omegapci_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
@ -2210,34 +2048,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = byt_serial_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_PNW_UART1,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pnw_serial_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_PNW_UART2,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pnw_serial_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_PNW_UART3,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pnw_serial_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_TNG_UART,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = tng_serial_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = PCI_DEVICE_ID_INTEL_BSW_UART1,
|
||||
@ -3119,8 +2929,6 @@ enum pci_board_num_t {
|
||||
pbn_ADDIDATA_PCIe_8_3906250,
|
||||
pbn_ce4100_1_115200,
|
||||
pbn_byt,
|
||||
pbn_pnw,
|
||||
pbn_tng,
|
||||
pbn_qrk,
|
||||
pbn_omegapci,
|
||||
pbn_NETMOS9900_2s_115200,
|
||||
@ -3907,16 +3715,6 @@ static struct pciserial_board pci_boards[] = {
|
||||
.uart_offset = 0x80,
|
||||
.reg_shift = 2,
|
||||
},
|
||||
[pbn_pnw] = {
|
||||
.flags = FL_BASE0,
|
||||
.num_ports = 1,
|
||||
.base_baud = 115200,
|
||||
},
|
||||
[pbn_tng] = {
|
||||
.flags = FL_BASE0,
|
||||
.num_ports = 1,
|
||||
.base_baud = 1843200,
|
||||
},
|
||||
[pbn_qrk] = {
|
||||
.flags = FL_BASE0,
|
||||
.num_ports = 1,
|
||||
@ -4005,6 +3803,13 @@ static const struct pci_device_id blacklist[] = {
|
||||
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
|
||||
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
|
||||
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
|
||||
|
||||
/* Intel platforms with MID UART */
|
||||
{ PCI_VDEVICE(INTEL, 0x081b), },
|
||||
{ PCI_VDEVICE(INTEL, 0x081c), },
|
||||
{ PCI_VDEVICE(INTEL, 0x081d), },
|
||||
{ PCI_VDEVICE(INTEL, 0x1191), },
|
||||
{ PCI_VDEVICE(INTEL, 0x19d8), },
|
||||
};
|
||||
|
||||
/*
|
||||
@ -5701,26 +5506,6 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||||
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
|
||||
pbn_byt },
|
||||
|
||||
/*
|
||||
* Intel Penwell
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_pnw},
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_pnw},
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_pnw},
|
||||
|
||||
/*
|
||||
* Intel Tangier
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TNG_UART,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_tng},
|
||||
|
||||
/*
|
||||
* Intel Quark x1000
|
||||
*/
|
||||
|
@ -284,7 +284,7 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
serial_out(up, UART_DLM, value >> 8 & 0xff);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
|
||||
#ifdef CONFIG_SERIAL_8250_RT288X
|
||||
|
||||
/* Au1x00/RT288x UART hardware has a weird register layout */
|
||||
static const s8 au_io_in_map[8] = {
|
||||
@ -435,7 +435,7 @@ static void set_io_from_upio(struct uart_port *p)
|
||||
p->serial_out = mem32be_serial_out;
|
||||
break;
|
||||
|
||||
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
|
||||
#ifdef CONFIG_SERIAL_8250_RT288X
|
||||
case UPIO_AU:
|
||||
p->serial_in = au_serial_in;
|
||||
p->serial_out = au_serial_out;
|
||||
@ -1246,6 +1246,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
||||
inb_p(ICP);
|
||||
}
|
||||
|
||||
if (uart_console(port))
|
||||
console_lock();
|
||||
|
||||
/* forget possible initially masked and pending IRQ */
|
||||
probe_irq_off(probe_irq_on());
|
||||
save_mcr = serial_in(up, UART_MCR);
|
||||
@ -1277,6 +1280,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
||||
if (port->flags & UPF_FOURPORT)
|
||||
outb_p(save_ICP, ICP);
|
||||
|
||||
if (uart_console(port))
|
||||
console_unlock();
|
||||
|
||||
port->irq = (irq > 0) ? irq : 0;
|
||||
}
|
||||
|
||||
@ -1807,9 +1813,6 @@ int serial8250_do_startup(struct uart_port *port)
|
||||
unsigned char lsr, iir;
|
||||
int retval;
|
||||
|
||||
if (port->type == PORT_8250_CIR)
|
||||
return -ENODEV;
|
||||
|
||||
if (!port->fifosize)
|
||||
port->fifosize = uart_config[port->type].fifo_size;
|
||||
if (!up->tx_loadsz)
|
||||
@ -2230,6 +2233,23 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
serial_port_out(port, 0x2, quot_frac);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int tolerance = port->uartclk / 100;
|
||||
|
||||
/*
|
||||
* Ask the core to calculate the divisor for us.
|
||||
* Allow 1% tolerance at the upper limit so uart clks marginally
|
||||
* slower than nominal still match standard baud rates without
|
||||
* causing transmission errors.
|
||||
*/
|
||||
return uart_get_baud_rate(port, termios, old,
|
||||
port->uartclk / 16 / 0xffff,
|
||||
(port->uartclk + tolerance) / 16);
|
||||
}
|
||||
|
||||
void
|
||||
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
@ -2241,12 +2261,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
|
||||
cval = serial8250_compute_lcr(up, termios->c_cflag);
|
||||
|
||||
/*
|
||||
* Ask the core to calculate the divisor for us.
|
||||
*/
|
||||
baud = uart_get_baud_rate(port, termios, old,
|
||||
port->uartclk / 16 / 0xffff,
|
||||
port->uartclk / 16);
|
||||
baud = serial8250_get_baud_rate(port, termios, old);
|
||||
quot = serial8250_get_divisor(up, baud, &frac);
|
||||
|
||||
/*
|
||||
@ -2513,14 +2528,8 @@ static void serial8250_release_port(struct uart_port *port)
|
||||
static int serial8250_request_port(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
int ret;
|
||||
|
||||
if (port->type == PORT_8250_CIR)
|
||||
return -ENODEV;
|
||||
|
||||
ret = serial8250_request_std_resource(up);
|
||||
|
||||
return ret;
|
||||
return serial8250_request_std_resource(up);
|
||||
}
|
||||
|
||||
static int fcr_get_rxtrig_bytes(struct uart_8250_port *up)
|
||||
@ -2668,9 +2677,6 @@ static void serial8250_config_port(struct uart_port *port, int flags)
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
int ret;
|
||||
|
||||
if (port->type == PORT_8250_CIR)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Find the region that we can probe for. This in turn
|
||||
* tells us whether we can probe for the type of port.
|
||||
@ -2804,6 +2810,27 @@ static void serial8250_console_putchar(struct uart_port *port, int ch)
|
||||
serial_port_out(port, UART_TX, ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore serial console when h/w power-off detected
|
||||
*/
|
||||
static void serial8250_console_restore(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
struct ktermios termios;
|
||||
unsigned int baud, quot, frac = 0;
|
||||
|
||||
termios.c_cflag = port->cons->cflag;
|
||||
if (port->state->port.tty && termios.c_cflag == 0)
|
||||
termios.c_cflag = port->state->port.tty->termios.c_cflag;
|
||||
|
||||
baud = serial8250_get_baud_rate(port, &termios, NULL);
|
||||
quot = serial8250_get_divisor(up, baud, &frac);
|
||||
|
||||
serial8250_set_divisor(port, baud, quot, frac);
|
||||
serial_port_out(port, UART_LCR, up->lcr);
|
||||
serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a string to the serial port trying not to disturb
|
||||
* any possible real use of the port...
|
||||
@ -2841,22 +2868,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
||||
|
||||
/* check scratch reg to see if port powered off during system sleep */
|
||||
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
|
||||
struct ktermios termios;
|
||||
unsigned int baud, quot, frac = 0;
|
||||
|
||||
termios.c_cflag = port->cons->cflag;
|
||||
if (port->state->port.tty && termios.c_cflag == 0)
|
||||
termios.c_cflag = port->state->port.tty->termios.c_cflag;
|
||||
|
||||
baud = uart_get_baud_rate(port, &termios, NULL,
|
||||
port->uartclk / 16 / 0xffff,
|
||||
port->uartclk / 16);
|
||||
quot = serial8250_get_divisor(up, baud, &frac);
|
||||
|
||||
serial8250_set_divisor(port, baud, quot, frac);
|
||||
serial_port_out(port, UART_LCR, up->lcr);
|
||||
serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
|
||||
|
||||
serial8250_console_restore(up);
|
||||
up->canary = 0;
|
||||
}
|
||||
|
||||
|
@ -274,8 +274,8 @@ config SERIAL_8250_ACORN
|
||||
|
||||
config SERIAL_8250_FSL
|
||||
bool
|
||||
depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550
|
||||
default PPC
|
||||
depends on SERIAL_8250_CONSOLE
|
||||
default PPC || ARM || ARM64
|
||||
|
||||
config SERIAL_8250_DW
|
||||
tristate "Support for Synopsys DesignWare 8250 quirks"
|
||||
@ -294,11 +294,12 @@ config SERIAL_8250_EM
|
||||
|
||||
config SERIAL_8250_RT288X
|
||||
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
|
||||
depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620)
|
||||
depends on SERIAL_8250
|
||||
default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
|
||||
help
|
||||
If you have a Ralink RT288x/RT305x SoC based board and want to use the
|
||||
serial port, say Y to this option. The driver can handle up to 2 serial
|
||||
ports. If unsure, say N.
|
||||
Selecting this option will add support for the alternate register
|
||||
layout used by Ralink RT288x/RT305x, Alchemy Au1xxx, and some others.
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_OMAP
|
||||
tristate "Support for OMAP internal UART (8250 based driver)"
|
||||
@ -337,7 +338,7 @@ config SERIAL_8250_FINTEK
|
||||
through the PNP driver. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_LPC18XX
|
||||
bool "NXP LPC18xx/43xx serial port support"
|
||||
tristate "NXP LPC18xx/43xx serial port support"
|
||||
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
|
||||
default ARCH_LPC18XX
|
||||
help
|
||||
@ -366,3 +367,13 @@ config SERIAL_8250_INGENIC
|
||||
help
|
||||
If you have a system using an Ingenic SoC and wish to make use of
|
||||
its UARTs, say Y to this option. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_MID
|
||||
tristate "Support for serial ports on Intel MID platforms"
|
||||
depends on SERIAL_8250 && PCI
|
||||
select HSU_DMA if SERIAL_8250_DMA
|
||||
select HSU_DMA_PCI if X86_INTEL_MID
|
||||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present on the UART found on Intel Medfield SOC and various other
|
||||
Intel platforms.
|
||||
|
@ -27,5 +27,6 @@ obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
|
||||
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
|
||||
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
|
||||
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
|
||||
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
|
||||
|
||||
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
|
||||
|
@ -115,9 +115,9 @@ config SERIAL_SB1250_DUART_CONSOLE
|
||||
|
||||
config SERIAL_ATMEL
|
||||
bool "AT91 / AT32 on-chip serial port support"
|
||||
depends on ARCH_AT91 || AVR32
|
||||
depends on ARCH_AT91 || AVR32 || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
help
|
||||
This enables the driver for the on-chip UARTs of the Atmel
|
||||
AT91 and AT32 processors.
|
||||
@ -571,7 +571,7 @@ config BFIN_UART3_CTSRTS
|
||||
|
||||
config SERIAL_IMX
|
||||
tristate "IMX serial port support"
|
||||
depends on ARCH_MXC
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
select RATIONAL
|
||||
help
|
||||
@ -582,6 +582,7 @@ config SERIAL_IMX_CONSOLE
|
||||
bool "Console on IMX serial port"
|
||||
depends on SERIAL_IMX=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON if OF
|
||||
help
|
||||
If you have enabled the serial port on the Freescale IMX
|
||||
CPU you can make it the console by answering Y to this option.
|
||||
@ -743,7 +744,7 @@ config SERIAL_SH_SCI_CONSOLE
|
||||
|
||||
config SERIAL_SH_SCI_DMA
|
||||
bool "DMA support"
|
||||
depends on SERIAL_SH_SCI && SH_DMAE
|
||||
depends on SERIAL_SH_SCI && DMA_ENGINE
|
||||
|
||||
config SERIAL_PNX8XXX
|
||||
bool "Enable PNX8XXX SoCs' UART Support"
|
||||
@ -1408,7 +1409,7 @@ config SERIAL_PCH_UART_CONSOLE
|
||||
warnings and which allows logins in single user mode).
|
||||
|
||||
config SERIAL_MXS_AUART
|
||||
depends on ARCH_MXS
|
||||
depends on ARCH_MXS || COMPILE_TEST
|
||||
tristate "MXS AUART support"
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
@ -1538,6 +1539,7 @@ config SERIAL_FSL_LPUART
|
||||
tristate "Freescale lpuart serial port support"
|
||||
depends on HAS_DMA
|
||||
select SERIAL_CORE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Support for the on-chip lpuart on some Freescale SOCs.
|
||||
|
||||
|
@ -508,29 +508,6 @@ static struct uart_driver altera_uart_driver = {
|
||||
.cons = ALTERA_UART_CONSOLE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int altera_uart_get_of_uartclk(struct platform_device *pdev,
|
||||
struct uart_port *port)
|
||||
{
|
||||
int len;
|
||||
const __be32 *clk;
|
||||
|
||||
clk = of_get_property(pdev->dev.of_node, "clock-frequency", &len);
|
||||
if (!clk || len < sizeof(__be32))
|
||||
return -ENODEV;
|
||||
|
||||
port->uartclk = be32_to_cpup(clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int altera_uart_get_of_uartclk(struct platform_device *pdev,
|
||||
struct uart_port *port)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int altera_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev);
|
||||
@ -570,7 +547,8 @@ static int altera_uart_probe(struct platform_device *pdev)
|
||||
if (platp)
|
||||
port->uartclk = platp->uartclk;
|
||||
else {
|
||||
ret = altera_uart_get_of_uartclk(pdev, port);
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||
&port->uartclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -191,8 +191,8 @@ struct uart_amba_port {
|
||||
*/
|
||||
static int pl011_fifo_to_tty(struct uart_amba_port *uap)
|
||||
{
|
||||
u16 status, ch;
|
||||
unsigned int flag, max_count = 256;
|
||||
u16 status;
|
||||
unsigned int ch, flag, max_count = 256;
|
||||
int fifotaken = 0;
|
||||
|
||||
while (max_count--) {
|
||||
|
@ -581,6 +581,7 @@ static const struct of_device_id apbuart_match[] = {
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, apbuart_match);
|
||||
|
||||
static struct platform_driver grlib_apbuart_of_driver = {
|
||||
.probe = apbuart_probe,
|
||||
|
@ -111,6 +111,12 @@ struct atmel_uart_char {
|
||||
|
||||
#define ATMEL_SERIAL_RINGSIZE 1024
|
||||
|
||||
/*
|
||||
* at91: 6 USARTs and one DBGU port (SAM9260)
|
||||
* avr32: 4
|
||||
*/
|
||||
#define ATMEL_MAX_UART 7
|
||||
|
||||
/*
|
||||
* We wrap our port structure around the generic uart_port.
|
||||
*/
|
||||
@ -921,7 +927,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
|
||||
sg_set_page(&atmel_port->sg_tx,
|
||||
virt_to_page(port->state->xmit.buf),
|
||||
UART_XMIT_SIZE,
|
||||
(int)port->state->xmit.buf & ~PAGE_MASK);
|
||||
(unsigned long)port->state->xmit.buf & ~PAGE_MASK);
|
||||
nent = dma_map_sg(port->dev,
|
||||
&atmel_port->sg_tx,
|
||||
1,
|
||||
@ -931,10 +937,10 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
|
||||
dev_dbg(port->dev, "need to release resource of dma\n");
|
||||
goto chan_err;
|
||||
} else {
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
|
||||
sg_dma_len(&atmel_port->sg_tx),
|
||||
port->state->xmit.buf,
|
||||
sg_dma_address(&atmel_port->sg_tx));
|
||||
&sg_dma_address(&atmel_port->sg_tx));
|
||||
}
|
||||
|
||||
/* Configure the slave DMA */
|
||||
@ -1103,7 +1109,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
||||
sg_set_page(&atmel_port->sg_rx,
|
||||
virt_to_page(ring->buf),
|
||||
sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
|
||||
(int)ring->buf & ~PAGE_MASK);
|
||||
(unsigned long)ring->buf & ~PAGE_MASK);
|
||||
nent = dma_map_sg(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
@ -1113,10 +1119,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
||||
dev_dbg(port->dev, "need to release resource of dma\n");
|
||||
goto chan_err;
|
||||
} else {
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
|
||||
sg_dma_len(&atmel_port->sg_rx),
|
||||
ring->buf,
|
||||
sg_dma_address(&atmel_port->sg_rx));
|
||||
&sg_dma_address(&atmel_port->sg_rx));
|
||||
}
|
||||
|
||||
/* Configure the slave DMA */
|
||||
@ -1676,15 +1682,15 @@ static void atmel_init_rs485(struct uart_port *port,
|
||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (np) {
|
||||
struct serial_rs485 *rs485conf = &port->rs485;
|
||||
u32 rs485_delay[2];
|
||||
/* rs485 properties */
|
||||
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
||||
rs485_delay, 2) == 0) {
|
||||
struct serial_rs485 *rs485conf = &port->rs485;
|
||||
|
||||
rs485conf->delay_rts_before_send = rs485_delay[0];
|
||||
rs485conf->delay_rts_after_send = rs485_delay[1];
|
||||
rs485conf->flags = 0;
|
||||
}
|
||||
|
||||
if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||
@ -1692,7 +1698,6 @@ static void atmel_init_rs485(struct uart_port *port,
|
||||
if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
|
||||
NULL))
|
||||
rs485conf->flags |= SER_RS485_ENABLED;
|
||||
}
|
||||
} else {
|
||||
port->rs485 = pdata->rs485;
|
||||
}
|
||||
@ -2296,7 +2301,7 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
ret = -EINVAL;
|
||||
if (port->uartclk / 16 != ser->baud_base)
|
||||
ret = -EINVAL;
|
||||
if ((void *)port->mapbase != ser->iomem_base)
|
||||
if (port->mapbase != (unsigned long)ser->iomem_base)
|
||||
ret = -EINVAL;
|
||||
if (port->iobase != ser->port)
|
||||
ret = -EINVAL;
|
||||
@ -2686,7 +2691,7 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
|
||||
enum mctrl_gpio_idx i;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
p->gpios = mctrl_gpio_init(dev, 0);
|
||||
p->gpios = mctrl_gpio_init_noauto(dev, 0);
|
||||
if (IS_ERR(p->gpios))
|
||||
return PTR_ERR(p->gpios);
|
||||
|
||||
|
@ -500,7 +500,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, s);
|
||||
|
||||
s->gpios = mctrl_gpio_init(&pdev->dev, 0);
|
||||
s->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0);
|
||||
if (IS_ERR(s->gpios))
|
||||
return PTR_ERR(s->gpios);
|
||||
|
||||
|
@ -1450,6 +1450,7 @@ static const struct of_device_id cpm_uart_match[] = {
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cpm_uart_match);
|
||||
|
||||
static struct platform_driver cpm_uart_driver = {
|
||||
.driver = {
|
||||
|
@ -3655,7 +3655,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&info->port.close_wait);
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* port closed */
|
||||
@ -3758,23 +3757,6 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
int retval;
|
||||
int do_clocal = 0;
|
||||
|
||||
/*
|
||||
* If the device is in the middle of being closed, then block
|
||||
* until it's done, and then try again.
|
||||
*/
|
||||
if (info->port.flags & ASYNC_CLOSING) {
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->port.flags & ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -ERESTARTSYS;
|
||||
#else
|
||||
return -EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* If non-blocking mode is set, or the port is not enabled,
|
||||
* then make the check up front and then exit.
|
||||
@ -3825,7 +3807,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)
|
||||
if (do_clocal)
|
||||
/* && (do_clocal || DCD_IS_ASSERTED) */
|
||||
break;
|
||||
if (signal_pending(current)) {
|
||||
@ -3894,20 +3876,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
||||
|
||||
info->port.low_latency = !!(info->port.flags & ASYNC_LOW_LATENCY);
|
||||
|
||||
/*
|
||||
* If the port is in the middle of closing, bail out now
|
||||
*/
|
||||
if (info->port.flags & ASYNC_CLOSING) {
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
return ((info->port.flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
#else
|
||||
return -EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* If DMA is enabled try to allocate the irq's.
|
||||
*/
|
||||
|
@ -1746,6 +1746,45 @@ static struct console lpuart32_console = {
|
||||
.data = &lpuart_reg,
|
||||
};
|
||||
|
||||
static void lpuart_early_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, lpuart_console_putchar);
|
||||
}
|
||||
|
||||
static void lpuart32_early_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, lpuart32_console_putchar);
|
||||
}
|
||||
|
||||
static int __init lpuart_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = lpuart_early_write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init lpuart32_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = lpuart32_early_write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
|
||||
|
||||
#define LPUART_CONSOLE (&lpuart_console)
|
||||
#define LPUART32_CONSOLE (&lpuart32_console)
|
||||
#else
|
||||
|
@ -139,6 +139,7 @@
|
||||
#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
|
||||
#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
|
||||
#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
|
||||
#define USR1_AGTIM (1<<8) /* Ageing timer interrupt flag */
|
||||
#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
|
||||
#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
|
||||
#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
|
||||
@ -728,11 +729,15 @@ static void imx_dma_rxint(struct imx_port *sport)
|
||||
if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
|
||||
sport->dma_is_rxing = 1;
|
||||
|
||||
/* disable the `Recerver Ready Interrrupt` */
|
||||
/* disable the receiver ready and aging timer interrupts */
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
temp &= ~(UCR1_RRDYEN);
|
||||
writel(temp, sport->port.membase + UCR1);
|
||||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp &= ~(UCR2_ATEN);
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
/* tell the DMA to receive the data. */
|
||||
start_rx_dma(sport);
|
||||
}
|
||||
@ -749,7 +754,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
|
||||
sts = readl(sport->port.membase + USR1);
|
||||
sts2 = readl(sport->port.membase + USR2);
|
||||
|
||||
if (sts & USR1_RRDY) {
|
||||
if (sts & (USR1_RRDY | USR1_AGTIM)) {
|
||||
if (sport->dma_is_enabled)
|
||||
imx_dma_rxint(sport);
|
||||
else
|
||||
@ -852,19 +857,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
#define TXTL 2 /* reset default */
|
||||
#define RXTL 1 /* reset default */
|
||||
|
||||
static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
/* set receiver / transmitter trigger level */
|
||||
val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
|
||||
val |= TXTL << UFCR_TXTL_SHF | RXTL;
|
||||
writel(val, sport->port.membase + UFCR);
|
||||
}
|
||||
|
||||
#define RX_BUF_SIZE (PAGE_SIZE)
|
||||
static void imx_rx_dma_done(struct imx_port *sport)
|
||||
{
|
||||
@ -873,11 +865,15 @@ static void imx_rx_dma_done(struct imx_port *sport)
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
/* Enable this interrupt when the RXFIFO is empty. */
|
||||
/* re-enable interrupts to get notified when new symbols are incoming */
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
temp |= UCR1_RRDYEN;
|
||||
writel(temp, sport->port.membase + UCR1);
|
||||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp |= UCR2_ATEN;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
sport->dma_is_rxing = 0;
|
||||
|
||||
/* Is the shutdown waiting for us? */
|
||||
@ -888,14 +884,12 @@ static void imx_rx_dma_done(struct imx_port *sport)
|
||||
}
|
||||
|
||||
/*
|
||||
* There are three kinds of RX DMA interrupts(such as in the MX6Q):
|
||||
* There are two kinds of RX DMA interrupts(such as in the MX6Q):
|
||||
* [1] the RX DMA buffer is full.
|
||||
* [2] the Aging timer expires(wait for 8 bytes long)
|
||||
* [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
|
||||
* [2] the aging timer expires
|
||||
*
|
||||
* The [2] is trigger when a character was been sitting in the FIFO
|
||||
* meanwhile [3] can wait for 32 bytes long when the RX line is
|
||||
* on IDLE state and RxFIFO is empty.
|
||||
* Condition [2] is triggered when a character has been sitting in the FIFO
|
||||
* for at least 8 byte durations.
|
||||
*/
|
||||
static void dma_rx_callback(void *data)
|
||||
{
|
||||
@ -913,13 +907,6 @@ static void dma_rx_callback(void *data)
|
||||
status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
|
||||
count = RX_BUF_SIZE - state.residue;
|
||||
|
||||
if (readl(sport->port.membase + USR2) & USR2_IDLE) {
|
||||
/* In condition [3] the SDMA counted up too early */
|
||||
count--;
|
||||
|
||||
writel(USR2_IDLE, sport->port.membase + USR2);
|
||||
}
|
||||
|
||||
dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
|
||||
|
||||
if (count) {
|
||||
@ -931,23 +918,21 @@ static void dma_rx_callback(void *data)
|
||||
sport->port.icount.buf_overrun++;
|
||||
}
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
start_rx_dma(sport);
|
||||
} else if (readl(sport->port.membase + USR2) & USR2_RDR) {
|
||||
/*
|
||||
* start rx_dma directly once data in RXFIFO, more efficient
|
||||
* than before:
|
||||
* 1. call imx_rx_dma_done to stop dma if no data received
|
||||
* 2. wait next RDR interrupt to start dma transfer.
|
||||
*/
|
||||
start_rx_dma(sport);
|
||||
} else {
|
||||
/*
|
||||
* stop dma to prevent too many IDLE event trigged if no data
|
||||
* in RXFIFO
|
||||
*/
|
||||
imx_rx_dma_done(sport);
|
||||
sport->port.icount.rx += count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restart RX DMA directly if more data is available in order to skip
|
||||
* the roundtrip through the IRQ handler. If there is some data already
|
||||
* in the FIFO, DMA needs to be restarted soon anyways.
|
||||
*
|
||||
* Otherwise stop the DMA and reactivate FIFO IRQs to restart DMA once
|
||||
* data starts to arrive again.
|
||||
*/
|
||||
if (readl(sport->port.membase + USR2) & USR2_RDR)
|
||||
start_rx_dma(sport);
|
||||
else
|
||||
imx_rx_dma_done(sport);
|
||||
}
|
||||
|
||||
static int start_rx_dma(struct imx_port *sport)
|
||||
@ -980,6 +965,22 @@ static int start_rx_dma(struct imx_port *sport)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TXTL_DEFAULT 2 /* reset default */
|
||||
#define RXTL_DEFAULT 1 /* reset default */
|
||||
#define TXTL_DMA 8 /* DMA burst setting */
|
||||
#define RXTL_DMA 9 /* DMA burst setting */
|
||||
|
||||
static void imx_setup_ufcr(struct imx_port *sport,
|
||||
unsigned char txwl, unsigned char rxwl)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
/* set receiver / transmitter trigger level */
|
||||
val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
|
||||
val |= txwl << UFCR_TXTL_SHF | rxwl;
|
||||
writel(val, sport->port.membase + UFCR);
|
||||
}
|
||||
|
||||
static void imx_uart_dma_exit(struct imx_port *sport)
|
||||
{
|
||||
if (sport->dma_chan_rx) {
|
||||
@ -1015,7 +1016,8 @@ static int imx_uart_dma_init(struct imx_port *sport)
|
||||
slave_config.direction = DMA_DEV_TO_MEM;
|
||||
slave_config.src_addr = sport->port.mapbase + URXD0;
|
||||
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave_config.src_maxburst = RXTL;
|
||||
/* one byte less than the watermark level to enable the aging timer */
|
||||
slave_config.src_maxburst = RXTL_DMA - 1;
|
||||
ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
|
||||
if (ret) {
|
||||
dev_err(dev, "error in RX dma configuration.\n");
|
||||
@ -1039,7 +1041,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
|
||||
slave_config.direction = DMA_MEM_TO_DEV;
|
||||
slave_config.dst_addr = sport->port.mapbase + URTX0;
|
||||
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave_config.dst_maxburst = TXTL;
|
||||
slave_config.dst_maxburst = TXTL_DMA;
|
||||
ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
|
||||
if (ret) {
|
||||
dev_err(dev, "error in TX dma configuration.");
|
||||
@ -1062,15 +1064,14 @@ static void imx_enable_dma(struct imx_port *sport)
|
||||
|
||||
/* set UCR1 */
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
|
||||
/* wait for 32 idle frames for IDDMA interrupt */
|
||||
UCR1_ICD_REG(3);
|
||||
temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
|
||||
writel(temp, sport->port.membase + UCR1);
|
||||
|
||||
/* set UCR4 */
|
||||
temp = readl(sport->port.membase + UCR4);
|
||||
temp |= UCR4_IDDMAEN;
|
||||
writel(temp, sport->port.membase + UCR4);
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp |= UCR2_ATEN;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA);
|
||||
|
||||
sport->dma_is_enabled = 1;
|
||||
}
|
||||
@ -1086,13 +1087,10 @@ static void imx_disable_dma(struct imx_port *sport)
|
||||
|
||||
/* clear UCR2 */
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp &= ~(UCR2_CTSC | UCR2_CTS);
|
||||
temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
/* clear UCR4 */
|
||||
temp = readl(sport->port.membase + UCR4);
|
||||
temp &= ~UCR4_IDDMAEN;
|
||||
writel(temp, sport->port.membase + UCR4);
|
||||
imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
||||
|
||||
sport->dma_is_enabled = 0;
|
||||
}
|
||||
@ -1115,7 +1113,7 @@ static int imx_startup(struct uart_port *port)
|
||||
return retval;
|
||||
}
|
||||
|
||||
imx_setup_ufcr(sport, 0);
|
||||
imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
||||
|
||||
/* disable the DREN bit (Data Ready interrupt enable) before
|
||||
* requesting IRQs
|
||||
@ -1128,6 +1126,11 @@ static int imx_startup(struct uart_port *port)
|
||||
|
||||
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
|
||||
|
||||
/* Can we enable the DMA support? */
|
||||
if (is_imx6q_uart(sport) && !uart_console(port) &&
|
||||
!sport->dma_is_inited)
|
||||
imx_uart_dma_init(sport);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
/* Reset fifo's and state machines */
|
||||
i = 100;
|
||||
@ -1145,6 +1148,9 @@ static int imx_startup(struct uart_port *port)
|
||||
writel(USR1_RTSD, sport->port.membase + USR1);
|
||||
writel(USR2_ORE, sport->port.membase + USR2);
|
||||
|
||||
if (sport->dma_is_inited && !sport->dma_is_enabled)
|
||||
imx_enable_dma(sport);
|
||||
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
|
||||
|
||||
@ -1278,7 +1284,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
unsigned long flags;
|
||||
unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
|
||||
unsigned int ucr2, old_ucr1, old_ucr2, baud, quot;
|
||||
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
|
||||
unsigned int div, ufcr;
|
||||
unsigned long num, denom;
|
||||
@ -1315,11 +1321,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
} else {
|
||||
ucr2 |= UCR2_CTSC;
|
||||
}
|
||||
|
||||
/* Can we enable the DMA support? */
|
||||
if (is_imx6q_uart(sport) && !uart_console(port)
|
||||
&& !sport->dma_is_inited)
|
||||
imx_uart_dma_init(sport);
|
||||
} else {
|
||||
termios->c_cflag &= ~CRTSCTS;
|
||||
}
|
||||
@ -1387,10 +1388,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
barrier();
|
||||
|
||||
/* then, disable everything */
|
||||
old_txrxen = readl(sport->port.membase + UCR2);
|
||||
writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN),
|
||||
old_ucr2 = readl(sport->port.membase + UCR2);
|
||||
writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN),
|
||||
sport->port.membase + UCR2);
|
||||
old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
|
||||
old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
|
||||
|
||||
/* custom-baudrate handling */
|
||||
div = sport->port.uartclk / (baud * 16);
|
||||
@ -1431,13 +1432,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
writel(old_ucr1, sport->port.membase + UCR1);
|
||||
|
||||
/* set the parity, stop bits and data size */
|
||||
writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
|
||||
writel(ucr2 | old_ucr2, sport->port.membase + UCR2);
|
||||
|
||||
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
|
||||
imx_enable_ms(&sport->port);
|
||||
|
||||
if (sport->dma_is_inited && !sport->dma_is_enabled)
|
||||
imx_enable_dma(sport);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
@ -1503,7 +1502,7 @@ static int imx_poll_init(struct uart_port *port)
|
||||
if (retval)
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
|
||||
imx_setup_ufcr(sport, 0);
|
||||
imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
@ -1773,7 +1772,7 @@ imx_console_setup(struct console *co, char *options)
|
||||
else
|
||||
imx_console_get_options(sport, &baud, &parity, &bits);
|
||||
|
||||
imx_setup_ufcr(sport, 0);
|
||||
imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
||||
|
||||
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
|
||||
|
||||
@ -1803,6 +1802,38 @@ static struct console imx_console = {
|
||||
};
|
||||
|
||||
#define IMX_CONSOLE &imx_console
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static void imx_console_early_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL)
|
||||
cpu_relax();
|
||||
|
||||
writel_relaxed(ch, port->membase + URTX0);
|
||||
}
|
||||
|
||||
static void imx_console_early_write(struct console *con, const char *s,
|
||||
unsigned count)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, count, imx_console_early_putchar);
|
||||
}
|
||||
|
||||
static int __init
|
||||
imx_console_early_setup(struct earlycon_device *dev, const char *opt)
|
||||
{
|
||||
if (!dev->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
dev->con->write = imx_console_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
|
||||
OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define IMX_CONSOLE NULL
|
||||
#endif
|
||||
|
@ -691,12 +691,13 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev)
|
||||
p->port.mapbase = res->start;
|
||||
p->port.membase = NULL;
|
||||
|
||||
p->port.irq = platform_get_irq(pdev, 0);
|
||||
if (p->port.irq < 0) {
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
|
||||
uarts_registered);
|
||||
return p->port.irq;
|
||||
return ret;
|
||||
}
|
||||
p->port.irq = ret;
|
||||
|
||||
p->port.iotype = UPIO_MEM32;
|
||||
p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
|
||||
|
@ -35,8 +35,6 @@
|
||||
#define MEN_Z135_BAUD_REG 0x810
|
||||
#define MEN_Z135_TIMEOUT 0x814
|
||||
|
||||
#define MEN_Z135_MEM_SIZE 0x818
|
||||
|
||||
#define IRQ_ID(x) ((x) & 0x1f)
|
||||
|
||||
#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
|
||||
@ -124,6 +122,7 @@ MODULE_PARM_DESC(rx_timeout, "RX timeout. "
|
||||
struct men_z135_port {
|
||||
struct uart_port port;
|
||||
struct mcb_device *mdev;
|
||||
struct resource *mem;
|
||||
unsigned char *rxbuf;
|
||||
u32 stat_reg;
|
||||
spinlock_t lock;
|
||||
@ -734,22 +733,30 @@ static const char *men_z135_type(struct uart_port *port)
|
||||
|
||||
static void men_z135_release_port(struct uart_port *port)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
|
||||
iounmap(port->membase);
|
||||
port->membase = NULL;
|
||||
|
||||
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
|
||||
mcb_release_mem(uart->mem);
|
||||
}
|
||||
|
||||
static int men_z135_request_port(struct uart_port *port)
|
||||
{
|
||||
int size = MEN_Z135_MEM_SIZE;
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
struct mcb_device *mdev = uart->mdev;
|
||||
struct resource *mem;
|
||||
|
||||
if (!request_mem_region(port->mapbase, size, "men_z135_port"))
|
||||
return -EBUSY;
|
||||
mem = mcb_request_mem(uart->mdev, dev_name(&mdev->dev));
|
||||
if (IS_ERR(mem))
|
||||
return PTR_ERR(mem);
|
||||
|
||||
port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE);
|
||||
port->mapbase = mem->start;
|
||||
uart->mem = mem;
|
||||
|
||||
port->membase = ioremap(mem->start, resource_size(mem));
|
||||
if (port->membase == NULL) {
|
||||
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
|
||||
mcb_release_mem(mem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -1135,6 +1135,13 @@ mpc52xx_uart_startup(struct uart_port *port)
|
||||
psc_ops->command(port, MPC52xx_PSC_RST_RX);
|
||||
psc_ops->command(port, MPC52xx_PSC_RST_TX);
|
||||
|
||||
/*
|
||||
* According to Freescale's support the RST_TX command can produce a
|
||||
* spike on the TX pin. So they recommend to delay "for one character".
|
||||
* One millisecond should be enough for everyone.
|
||||
*/
|
||||
msleep(1);
|
||||
|
||||
psc_ops->set_sicr(port, 0); /* UART mode DCD ignored */
|
||||
|
||||
psc_ops->fifo_init(port);
|
||||
|
@ -55,8 +55,6 @@
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/ioport.h>
|
||||
@ -755,7 +753,7 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
|
||||
pi->port.line);
|
||||
|
||||
if (!pi->dma_region) {
|
||||
if (!dma_supported(pi->port.dev, 0xffffffff)) {
|
||||
if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
|
||||
printk(KERN_ERR "MPSC: Inadequate DMA support\n");
|
||||
rc = -ENXIO;
|
||||
} else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
|
||||
@ -2108,26 +2106,11 @@ static int mpsc_drv_probe(struct platform_device *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mpsc_drv_remove(struct platform_device *dev)
|
||||
{
|
||||
pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
|
||||
|
||||
if (dev->id < MPSC_NUM_CTLRS) {
|
||||
uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
|
||||
mpsc_release_port((struct uart_port *)
|
||||
&mpsc_ports[dev->id].port);
|
||||
mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
|
||||
return 0;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
static struct platform_driver mpsc_driver = {
|
||||
.probe = mpsc_drv_probe,
|
||||
.remove = mpsc_drv_remove,
|
||||
.driver = {
|
||||
.name = MPSC_CTLR_NAME,
|
||||
.name = MPSC_CTLR_NAME,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2156,22 +2139,10 @@ static int __init mpsc_drv_init(void)
|
||||
|
||||
return rc;
|
||||
}
|
||||
device_initcall(mpsc_drv_init);
|
||||
|
||||
static void __exit mpsc_drv_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mpsc_driver);
|
||||
platform_driver_unregister(&mpsc_shared_driver);
|
||||
uart_unregister_driver(&mpsc_reg);
|
||||
memset(mpsc_ports, 0, sizeof(mpsc_ports));
|
||||
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
|
||||
}
|
||||
|
||||
module_init(mpsc_drv_init);
|
||||
module_exit(mpsc_drv_exit);
|
||||
|
||||
/*
|
||||
MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
|
||||
MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
|
||||
MODULE_VERSION(MPSC_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
|
||||
MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
|
||||
*/
|
||||
|
@ -20,6 +20,8 @@
|
||||
#endif
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
@ -31,6 +33,7 @@
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
@ -39,6 +42,11 @@
|
||||
|
||||
#include "msm_serial.h"
|
||||
|
||||
#define UARTDM_BURST_SIZE 16 /* in bytes */
|
||||
#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */
|
||||
#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */
|
||||
#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4)
|
||||
|
||||
enum {
|
||||
UARTDM_1P1 = 1,
|
||||
UARTDM_1P2,
|
||||
@ -46,6 +54,17 @@ enum {
|
||||
UARTDM_1P4,
|
||||
};
|
||||
|
||||
struct msm_dma {
|
||||
struct dma_chan *chan;
|
||||
enum dma_data_direction dir;
|
||||
dma_addr_t phys;
|
||||
unsigned char *virt;
|
||||
dma_cookie_t cookie;
|
||||
u32 enable_bit;
|
||||
unsigned int count;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
};
|
||||
|
||||
struct msm_port {
|
||||
struct uart_port uart;
|
||||
char name[16];
|
||||
@ -55,9 +74,153 @@ struct msm_port {
|
||||
int is_uartdm;
|
||||
unsigned int old_snap_state;
|
||||
bool break_detected;
|
||||
struct msm_dma tx_dma;
|
||||
struct msm_dma rx_dma;
|
||||
};
|
||||
|
||||
static inline void wait_for_xmitr(struct uart_port *port)
|
||||
static void msm_handle_tx(struct uart_port *port);
|
||||
static void msm_start_rx_dma(struct msm_port *msm_port);
|
||||
|
||||
void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
unsigned int mapped;
|
||||
u32 val;
|
||||
|
||||
mapped = dma->count;
|
||||
dma->count = 0;
|
||||
|
||||
dmaengine_terminate_all(dma->chan);
|
||||
|
||||
/*
|
||||
* DMA Stall happens if enqueue and flush command happens concurrently.
|
||||
* For example before changing the baud rate/protocol configuration and
|
||||
* sending flush command to ADM, disable the channel of UARTDM.
|
||||
* Note: should not reset the receiver here immediately as it is not
|
||||
* suggested to do disable/reset or reset/disable at the same time.
|
||||
*/
|
||||
val = msm_read(port, UARTDM_DMEN);
|
||||
val &= ~dma->enable_bit;
|
||||
msm_write(port, val, UARTDM_DMEN);
|
||||
|
||||
if (mapped)
|
||||
dma_unmap_single(dev, dma->phys, mapped, dma->dir);
|
||||
}
|
||||
|
||||
static void msm_release_dma(struct msm_port *msm_port)
|
||||
{
|
||||
struct msm_dma *dma;
|
||||
|
||||
dma = &msm_port->tx_dma;
|
||||
if (dma->chan) {
|
||||
msm_stop_dma(&msm_port->uart, dma);
|
||||
dma_release_channel(dma->chan);
|
||||
}
|
||||
|
||||
memset(dma, 0, sizeof(*dma));
|
||||
|
||||
dma = &msm_port->rx_dma;
|
||||
if (dma->chan) {
|
||||
msm_stop_dma(&msm_port->uart, dma);
|
||||
dma_release_channel(dma->chan);
|
||||
kfree(dma->virt);
|
||||
}
|
||||
|
||||
memset(dma, 0, sizeof(*dma));
|
||||
}
|
||||
|
||||
static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base)
|
||||
{
|
||||
struct device *dev = msm_port->uart.dev;
|
||||
struct dma_slave_config conf;
|
||||
struct msm_dma *dma;
|
||||
u32 crci = 0;
|
||||
int ret;
|
||||
|
||||
dma = &msm_port->tx_dma;
|
||||
|
||||
/* allocate DMA resources, if available */
|
||||
dma->chan = dma_request_slave_channel_reason(dev, "tx");
|
||||
if (IS_ERR(dma->chan))
|
||||
goto no_tx;
|
||||
|
||||
of_property_read_u32(dev->of_node, "qcom,tx-crci", &crci);
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
conf.direction = DMA_MEM_TO_DEV;
|
||||
conf.device_fc = true;
|
||||
conf.dst_addr = base + UARTDM_TF;
|
||||
conf.dst_maxburst = UARTDM_BURST_SIZE;
|
||||
conf.slave_id = crci;
|
||||
|
||||
ret = dmaengine_slave_config(dma->chan, &conf);
|
||||
if (ret)
|
||||
goto rel_tx;
|
||||
|
||||
dma->dir = DMA_TO_DEVICE;
|
||||
|
||||
if (msm_port->is_uartdm < UARTDM_1P4)
|
||||
dma->enable_bit = UARTDM_DMEN_TX_DM_ENABLE;
|
||||
else
|
||||
dma->enable_bit = UARTDM_DMEN_TX_BAM_ENABLE;
|
||||
|
||||
return;
|
||||
|
||||
rel_tx:
|
||||
dma_release_channel(dma->chan);
|
||||
no_tx:
|
||||
memset(dma, 0, sizeof(*dma));
|
||||
}
|
||||
|
||||
static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
|
||||
{
|
||||
struct device *dev = msm_port->uart.dev;
|
||||
struct dma_slave_config conf;
|
||||
struct msm_dma *dma;
|
||||
u32 crci = 0;
|
||||
int ret;
|
||||
|
||||
dma = &msm_port->rx_dma;
|
||||
|
||||
/* allocate DMA resources, if available */
|
||||
dma->chan = dma_request_slave_channel_reason(dev, "rx");
|
||||
if (IS_ERR(dma->chan))
|
||||
goto no_rx;
|
||||
|
||||
of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
|
||||
|
||||
dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
|
||||
if (!dma->virt)
|
||||
goto rel_rx;
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
conf.direction = DMA_DEV_TO_MEM;
|
||||
conf.device_fc = true;
|
||||
conf.src_addr = base + UARTDM_RF;
|
||||
conf.src_maxburst = UARTDM_BURST_SIZE;
|
||||
conf.slave_id = crci;
|
||||
|
||||
ret = dmaengine_slave_config(dma->chan, &conf);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dma->dir = DMA_FROM_DEVICE;
|
||||
|
||||
if (msm_port->is_uartdm < UARTDM_1P4)
|
||||
dma->enable_bit = UARTDM_DMEN_RX_DM_ENABLE;
|
||||
else
|
||||
dma->enable_bit = UARTDM_DMEN_RX_BAM_ENABLE;
|
||||
|
||||
return;
|
||||
err:
|
||||
kfree(dma->virt);
|
||||
rel_rx:
|
||||
dma_release_channel(dma->chan);
|
||||
no_rx:
|
||||
memset(dma, 0, sizeof(*dma));
|
||||
}
|
||||
|
||||
static inline void msm_wait_for_xmitr(struct uart_port *port)
|
||||
{
|
||||
while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
|
||||
if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
|
||||
@ -78,17 +241,277 @@ static void msm_stop_tx(struct uart_port *port)
|
||||
static void msm_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
|
||||
/* Already started in DMA mode */
|
||||
if (dma->count)
|
||||
return;
|
||||
|
||||
msm_port->imr |= UART_IMR_TXLEV;
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
}
|
||||
|
||||
static void msm_reset_dm_count(struct uart_port *port, int count)
|
||||
{
|
||||
msm_wait_for_xmitr(port);
|
||||
msm_write(port, count, UARTDM_NCF_TX);
|
||||
msm_read(port, UARTDM_NCF_TX);
|
||||
}
|
||||
|
||||
static void msm_complete_tx_dma(void *args)
|
||||
{
|
||||
struct msm_port *msm_port = args;
|
||||
struct uart_port *port = &msm_port->uart;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
struct dma_tx_state state;
|
||||
enum dma_status status;
|
||||
unsigned long flags;
|
||||
unsigned int count;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Already stopped */
|
||||
if (!dma->count)
|
||||
goto done;
|
||||
|
||||
status = dmaengine_tx_status(dma->chan, dma->cookie, &state);
|
||||
|
||||
dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir);
|
||||
|
||||
val = msm_read(port, UARTDM_DMEN);
|
||||
val &= ~dma->enable_bit;
|
||||
msm_write(port, val, UARTDM_DMEN);
|
||||
|
||||
if (msm_port->is_uartdm > UARTDM_1P3) {
|
||||
msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
|
||||
msm_write(port, UART_CR_TX_ENABLE, UART_CR);
|
||||
}
|
||||
|
||||
count = dma->count - state.residue;
|
||||
port->icount.tx += count;
|
||||
dma->count = 0;
|
||||
|
||||
xmit->tail += count;
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
|
||||
/* Restore "Tx FIFO below watermark" interrupt */
|
||||
msm_port->imr |= UART_IMR_TXLEV;
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
msm_handle_tx(port);
|
||||
done:
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
||||
{
|
||||
struct circ_buf *xmit = &msm_port->uart.state->xmit;
|
||||
struct uart_port *port = &msm_port->uart;
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
void *cpu_addr;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
cpu_addr = &xmit->buf[xmit->tail];
|
||||
|
||||
dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir);
|
||||
ret = dma_mapping_error(port->dev, dma->phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
|
||||
count, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT |
|
||||
DMA_PREP_FENCE);
|
||||
if (!dma->desc) {
|
||||
ret = -EIO;
|
||||
goto unmap;
|
||||
}
|
||||
|
||||
dma->desc->callback = msm_complete_tx_dma;
|
||||
dma->desc->callback_param = msm_port;
|
||||
|
||||
dma->cookie = dmaengine_submit(dma->desc);
|
||||
ret = dma_submit_error(dma->cookie);
|
||||
if (ret)
|
||||
goto unmap;
|
||||
|
||||
/*
|
||||
* Using DMA complete for Tx FIFO reload, no need for
|
||||
* "Tx FIFO below watermark" one, disable it
|
||||
*/
|
||||
msm_port->imr &= ~UART_IMR_TXLEV;
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
|
||||
dma->count = count;
|
||||
|
||||
val = msm_read(port, UARTDM_DMEN);
|
||||
val |= dma->enable_bit;
|
||||
|
||||
if (msm_port->is_uartdm < UARTDM_1P4)
|
||||
msm_write(port, val, UARTDM_DMEN);
|
||||
|
||||
msm_reset_dm_count(port, count);
|
||||
|
||||
if (msm_port->is_uartdm > UARTDM_1P3)
|
||||
msm_write(port, val, UARTDM_DMEN);
|
||||
|
||||
dma_async_issue_pending(dma->chan);
|
||||
return 0;
|
||||
unmap:
|
||||
dma_unmap_single(port->dev, dma->phys, count, dma->dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void msm_complete_rx_dma(void *args)
|
||||
{
|
||||
struct msm_port *msm_port = args;
|
||||
struct uart_port *port = &msm_port->uart;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct msm_dma *dma = &msm_port->rx_dma;
|
||||
int count = 0, i, sysrq;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Already stopped */
|
||||
if (!dma->count)
|
||||
goto done;
|
||||
|
||||
val = msm_read(port, UARTDM_DMEN);
|
||||
val &= ~dma->enable_bit;
|
||||
msm_write(port, val, UARTDM_DMEN);
|
||||
|
||||
/* Restore interrupts */
|
||||
msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE;
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
|
||||
if (msm_read(port, UART_SR) & UART_SR_OVERRUN) {
|
||||
port->icount.overrun++;
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
|
||||
}
|
||||
|
||||
count = msm_read(port, UARTDM_RX_TOTAL_SNAP);
|
||||
|
||||
port->icount.rx += count;
|
||||
|
||||
dma->count = 0;
|
||||
|
||||
dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
char flag = TTY_NORMAL;
|
||||
|
||||
if (msm_port->break_detected && dma->virt[i] == 0) {
|
||||
port->icount.brk++;
|
||||
flag = TTY_BREAK;
|
||||
msm_port->break_detected = false;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(port->read_status_mask & UART_SR_RX_BREAK))
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
sysrq = uart_handle_sysrq_char(port, dma->virt[i]);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (!sysrq)
|
||||
tty_insert_flip_char(tport, dma->virt[i], flag);
|
||||
}
|
||||
|
||||
msm_start_rx_dma(msm_port);
|
||||
done:
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (count)
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static void msm_start_rx_dma(struct msm_port *msm_port)
|
||||
{
|
||||
struct msm_dma *dma = &msm_port->rx_dma;
|
||||
struct uart_port *uart = &msm_port->uart;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!dma->chan)
|
||||
return;
|
||||
|
||||
dma->phys = dma_map_single(uart->dev, dma->virt,
|
||||
UARTDM_RX_SIZE, dma->dir);
|
||||
ret = dma_mapping_error(uart->dev, dma->phys);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
|
||||
UARTDM_RX_SIZE, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!dma->desc)
|
||||
goto unmap;
|
||||
|
||||
dma->desc->callback = msm_complete_rx_dma;
|
||||
dma->desc->callback_param = msm_port;
|
||||
|
||||
dma->cookie = dmaengine_submit(dma->desc);
|
||||
ret = dma_submit_error(dma->cookie);
|
||||
if (ret)
|
||||
goto unmap;
|
||||
/*
|
||||
* Using DMA for FIFO off-load, no need for "Rx FIFO over
|
||||
* watermark" or "stale" interrupts, disable them
|
||||
*/
|
||||
msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
|
||||
|
||||
/*
|
||||
* Well, when DMA is ADM3 engine(implied by <= UARTDM v1.3),
|
||||
* we need RXSTALE to flush input DMA fifo to memory
|
||||
*/
|
||||
if (msm_port->is_uartdm < UARTDM_1P4)
|
||||
msm_port->imr |= UART_IMR_RXSTALE;
|
||||
|
||||
msm_write(uart, msm_port->imr, UART_IMR);
|
||||
|
||||
dma->count = UARTDM_RX_SIZE;
|
||||
|
||||
dma_async_issue_pending(dma->chan);
|
||||
|
||||
msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR);
|
||||
msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
|
||||
|
||||
val = msm_read(uart, UARTDM_DMEN);
|
||||
val |= dma->enable_bit;
|
||||
|
||||
if (msm_port->is_uartdm < UARTDM_1P4)
|
||||
msm_write(uart, val, UARTDM_DMEN);
|
||||
|
||||
msm_write(uart, UARTDM_RX_SIZE, UARTDM_DMRX);
|
||||
|
||||
if (msm_port->is_uartdm > UARTDM_1P3)
|
||||
msm_write(uart, val, UARTDM_DMEN);
|
||||
|
||||
return;
|
||||
unmap:
|
||||
dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
|
||||
}
|
||||
|
||||
static void msm_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
struct msm_dma *dma = &msm_port->rx_dma;
|
||||
|
||||
msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
|
||||
if (dma->chan)
|
||||
msm_stop_dma(port, dma);
|
||||
}
|
||||
|
||||
static void msm_enable_ms(struct uart_port *port)
|
||||
@ -99,7 +522,7 @@ static void msm_enable_ms(struct uart_port *port)
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
}
|
||||
|
||||
static void handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int sr;
|
||||
@ -169,9 +592,12 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
|
||||
msm_write(port, 0xFFFFFF, UARTDM_DMRX);
|
||||
msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
|
||||
|
||||
/* Try to use DMA */
|
||||
msm_start_rx_dma(msm_port);
|
||||
}
|
||||
|
||||
static void handle_rx(struct uart_port *port)
|
||||
static void msm_handle_rx(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int sr;
|
||||
@ -224,18 +650,11 @@ static void handle_rx(struct uart_port *port)
|
||||
spin_lock(&port->lock);
|
||||
}
|
||||
|
||||
static void reset_dm_count(struct uart_port *port, int count)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
msm_write(port, count, UARTDM_NCF_TX);
|
||||
msm_read(port, UARTDM_NCF_TX);
|
||||
}
|
||||
|
||||
static void handle_tx(struct uart_port *port)
|
||||
static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
unsigned int tx_count, num_chars;
|
||||
unsigned int num_chars;
|
||||
unsigned int tf_pointer = 0;
|
||||
void __iomem *tf;
|
||||
|
||||
@ -244,20 +663,8 @@ static void handle_tx(struct uart_port *port)
|
||||
else
|
||||
tf = port->membase + UART_TF;
|
||||
|
||||
tx_count = uart_circ_chars_pending(xmit);
|
||||
tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail,
|
||||
port->fifosize);
|
||||
|
||||
if (port->x_char) {
|
||||
if (msm_port->is_uartdm)
|
||||
reset_dm_count(port, tx_count + 1);
|
||||
|
||||
iowrite8_rep(tf, &port->x_char, 1);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
} else if (tx_count && msm_port->is_uartdm) {
|
||||
reset_dm_count(port, tx_count);
|
||||
}
|
||||
if (tx_count && msm_port->is_uartdm)
|
||||
msm_reset_dm_count(port, tx_count);
|
||||
|
||||
while (tf_pointer < tx_count) {
|
||||
int i;
|
||||
@ -290,20 +697,76 @@ static void handle_tx(struct uart_port *port)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
static void handle_delta_cts(struct uart_port *port)
|
||||
static void msm_handle_tx(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
struct circ_buf *xmit = &msm_port->uart.state->xmit;
|
||||
struct msm_dma *dma = &msm_port->tx_dma;
|
||||
unsigned int pio_count, dma_count, dma_min;
|
||||
void __iomem *tf;
|
||||
int err = 0;
|
||||
|
||||
if (port->x_char) {
|
||||
if (msm_port->is_uartdm)
|
||||
tf = port->membase + UARTDM_TF;
|
||||
else
|
||||
tf = port->membase + UART_TF;
|
||||
|
||||
if (msm_port->is_uartdm)
|
||||
msm_reset_dm_count(port, 1);
|
||||
|
||||
iowrite8_rep(tf, &port->x_char, 1);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
msm_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
|
||||
dma_min = 1; /* Always DMA */
|
||||
if (msm_port->is_uartdm > UARTDM_1P3) {
|
||||
dma_count = UARTDM_TX_AIGN(dma_count);
|
||||
dma_min = UARTDM_BURST_SIZE;
|
||||
} else {
|
||||
if (dma_count > UARTDM_TX_MAX)
|
||||
dma_count = UARTDM_TX_MAX;
|
||||
}
|
||||
|
||||
if (pio_count > port->fifosize)
|
||||
pio_count = port->fifosize;
|
||||
|
||||
if (!dma->chan || dma_count < dma_min)
|
||||
msm_handle_tx_pio(port, pio_count);
|
||||
else
|
||||
err = msm_handle_tx_dma(msm_port, dma_count);
|
||||
|
||||
if (err) /* fall back to PIO mode */
|
||||
msm_handle_tx_pio(port, pio_count);
|
||||
}
|
||||
|
||||
static void msm_handle_delta_cts(struct uart_port *port)
|
||||
{
|
||||
msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
|
||||
port->icount.cts++;
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
static irqreturn_t msm_irq(int irq, void *dev_id)
|
||||
static irqreturn_t msm_uart_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
struct msm_dma *dma = &msm_port->rx_dma;
|
||||
unsigned long flags;
|
||||
unsigned int misr;
|
||||
u32 val;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
misr = msm_read(port, UART_MISR);
|
||||
msm_write(port, 0, UART_IMR); /* disable interrupt */
|
||||
|
||||
@ -313,18 +776,29 @@ static irqreturn_t msm_irq(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
|
||||
if (msm_port->is_uartdm)
|
||||
handle_rx_dm(port, misr);
|
||||
else
|
||||
handle_rx(port);
|
||||
if (dma->count) {
|
||||
val = UART_CR_CMD_STALE_EVENT_DISABLE;
|
||||
msm_write(port, val, UART_CR);
|
||||
val = UART_CR_CMD_RESET_STALE_INT;
|
||||
msm_write(port, val, UART_CR);
|
||||
/*
|
||||
* Flush DMA input fifo to memory, this will also
|
||||
* trigger DMA RX completion
|
||||
*/
|
||||
dmaengine_terminate_all(dma->chan);
|
||||
} else if (msm_port->is_uartdm) {
|
||||
msm_handle_rx_dm(port, misr);
|
||||
} else {
|
||||
msm_handle_rx(port);
|
||||
}
|
||||
}
|
||||
if (misr & UART_IMR_TXLEV)
|
||||
handle_tx(port);
|
||||
msm_handle_tx(port);
|
||||
if (misr & UART_IMR_DELTA_CTS)
|
||||
handle_delta_cts(port);
|
||||
msm_handle_delta_cts(port);
|
||||
|
||||
msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
|
||||
spin_unlock(&port->lock);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -408,6 +882,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud)
|
||||
{ 3, 0xdd, 8 },
|
||||
{ 2, 0xee, 16 },
|
||||
{ 1, 0xff, 31 },
|
||||
{ 0, 0xff, 31 },
|
||||
};
|
||||
|
||||
divisor = uart_get_divisor(port, baud);
|
||||
@ -419,21 +894,41 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud)
|
||||
return entry; /* Default to smallest divider */
|
||||
}
|
||||
|
||||
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
|
||||
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
|
||||
unsigned long *saved_flags)
|
||||
{
|
||||
unsigned int rxstale, watermark;
|
||||
unsigned int rxstale, watermark, mask;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
const struct msm_baud_map *entry;
|
||||
unsigned long flags;
|
||||
|
||||
entry = msm_find_best_baud(port, baud);
|
||||
|
||||
msm_write(port, entry->code, UART_CSR);
|
||||
|
||||
if (baud > 460800)
|
||||
port->uartclk = baud * 16;
|
||||
|
||||
flags = *saved_flags;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
clk_set_rate(msm_port->clk, port->uartclk);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
*saved_flags = flags;
|
||||
|
||||
/* RX stale watermark */
|
||||
rxstale = entry->rxstale;
|
||||
watermark = UART_IPR_STALE_LSB & rxstale;
|
||||
watermark |= UART_IPR_RXSTALE_LAST;
|
||||
watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
|
||||
if (msm_port->is_uartdm) {
|
||||
mask = UART_DM_IPR_STALE_TIMEOUT_MSB;
|
||||
} else {
|
||||
watermark |= UART_IPR_RXSTALE_LAST;
|
||||
mask = UART_IPR_STALE_TIMEOUT_MSB;
|
||||
}
|
||||
|
||||
watermark |= mask & (rxstale << 2);
|
||||
|
||||
msm_write(port, watermark, UART_IPR);
|
||||
|
||||
/* set RX watermark */
|
||||
@ -476,13 +971,13 @@ static void msm_init_clock(struct uart_port *port)
|
||||
static int msm_startup(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
unsigned int data, rfr_level;
|
||||
unsigned int data, rfr_level, mask;
|
||||
int ret;
|
||||
|
||||
snprintf(msm_port->name, sizeof(msm_port->name),
|
||||
"msm_serial%d", port->line);
|
||||
|
||||
ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
|
||||
ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
|
||||
msm_port->name, port);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
@ -496,11 +991,23 @@ static int msm_startup(struct uart_port *port)
|
||||
|
||||
/* set automatic RFR level */
|
||||
data = msm_read(port, UART_MR1);
|
||||
data &= ~UART_MR1_AUTO_RFR_LEVEL1;
|
||||
|
||||
if (msm_port->is_uartdm)
|
||||
mask = UART_DM_MR1_AUTO_RFR_LEVEL1;
|
||||
else
|
||||
mask = UART_MR1_AUTO_RFR_LEVEL1;
|
||||
|
||||
data &= ~mask;
|
||||
data &= ~UART_MR1_AUTO_RFR_LEVEL0;
|
||||
data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
|
||||
data |= mask & (rfr_level << 2);
|
||||
data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
|
||||
msm_write(port, data, UART_MR1);
|
||||
|
||||
if (msm_port->is_uartdm) {
|
||||
msm_request_tx_dma(msm_port, msm_port->uart.mapbase);
|
||||
msm_request_rx_dma(msm_port, msm_port->uart.mapbase);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -511,6 +1018,9 @@ static void msm_shutdown(struct uart_port *port)
|
||||
msm_port->imr = 0;
|
||||
msm_write(port, 0, UART_IMR); /* disable interrupts */
|
||||
|
||||
if (msm_port->is_uartdm)
|
||||
msm_release_dma(msm_port);
|
||||
|
||||
clk_disable_unprepare(msm_port->clk);
|
||||
|
||||
free_irq(port->irq, port);
|
||||
@ -519,14 +1029,19 @@ static void msm_shutdown(struct uart_port *port)
|
||||
static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
struct msm_dma *dma = &msm_port->rx_dma;
|
||||
unsigned long flags;
|
||||
unsigned int baud, mr;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
if (dma->chan) /* Terminate if any */
|
||||
msm_stop_dma(port, dma);
|
||||
|
||||
/* calculate and set baud rate */
|
||||
baud = uart_get_baud_rate(port, termios, old, 300, 115200);
|
||||
baud = msm_set_baud_rate(port, baud);
|
||||
baud = uart_get_baud_rate(port, termios, old, 300, 4000000);
|
||||
baud = msm_set_baud_rate(port, baud, &flags);
|
||||
if (tty_termios_baud_rate(termios))
|
||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
|
||||
@ -588,6 +1103,9 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
/* Try to use DMA */
|
||||
msm_start_rx_dma(msm_port);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
@ -765,7 +1283,7 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
msm_write(port, 0, UART_IMR);
|
||||
|
||||
if (msm_port->is_uartdm)
|
||||
reset_dm_count(port, 1);
|
||||
msm_reset_dm_count(port, 1);
|
||||
|
||||
/* Wait until FIFO is empty */
|
||||
while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
|
||||
@ -839,7 +1357,7 @@ static struct msm_port msm_uart_ports[] = {
|
||||
|
||||
#define UART_NR ARRAY_SIZE(msm_uart_ports)
|
||||
|
||||
static inline struct uart_port *get_port_from_line(unsigned int line)
|
||||
static inline struct uart_port *msm_get_port_from_line(unsigned int line)
|
||||
{
|
||||
return &msm_uart_ports[line].uart;
|
||||
}
|
||||
@ -866,7 +1384,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
|
||||
|
||||
spin_lock(&port->lock);
|
||||
if (is_uartdm)
|
||||
reset_dm_count(port, count);
|
||||
msm_reset_dm_count(port, count);
|
||||
|
||||
i = 0;
|
||||
while (i < count) {
|
||||
@ -911,7 +1429,7 @@ static void msm_console_write(struct console *co, const char *s,
|
||||
|
||||
BUG_ON(co->index < 0 || co->index >= UART_NR);
|
||||
|
||||
port = get_port_from_line(co->index);
|
||||
port = msm_get_port_from_line(co->index);
|
||||
msm_port = UART_TO_MSM(port);
|
||||
|
||||
__msm_console_write(port, s, count, msm_port->is_uartdm);
|
||||
@ -928,7 +1446,7 @@ static int __init msm_console_setup(struct console *co, char *options)
|
||||
if (unlikely(co->index >= UART_NR || co->index < 0))
|
||||
return -ENXIO;
|
||||
|
||||
port = get_port_from_line(co->index);
|
||||
port = msm_get_port_from_line(co->index);
|
||||
|
||||
if (unlikely(!port->membase))
|
||||
return -ENXIO;
|
||||
@ -1043,7 +1561,7 @@ static int msm_serial_probe(struct platform_device *pdev)
|
||||
|
||||
dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line);
|
||||
|
||||
port = get_port_from_line(line);
|
||||
port = msm_get_port_from_line(line);
|
||||
port->dev = &pdev->dev;
|
||||
msm_port = UART_TO_MSM(port);
|
||||
|
||||
|
@ -20,11 +20,12 @@
|
||||
|
||||
#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
|
||||
#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
|
||||
#define UART_MR1_RX_RDY_CTL (1 << 7)
|
||||
#define UART_MR1_CTS_CTL (1 << 6)
|
||||
#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
|
||||
#define UART_MR1_RX_RDY_CTL BIT(7)
|
||||
#define UART_MR1_CTS_CTL BIT(6)
|
||||
|
||||
#define UART_MR2 0x0004
|
||||
#define UART_MR2_ERROR_MODE (1 << 6)
|
||||
#define UART_MR2_ERROR_MODE BIT(6)
|
||||
#define UART_MR2_BITS_PER_CHAR 0x30
|
||||
#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
|
||||
#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
|
||||
@ -58,26 +59,28 @@
|
||||
#define UART_CR_CMD_SET_RFR (13 << 4)
|
||||
#define UART_CR_CMD_RESET_RFR (14 << 4)
|
||||
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
|
||||
#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8)
|
||||
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
|
||||
#define UART_CR_CMD_FORCE_STALE (4 << 8)
|
||||
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
|
||||
#define UART_CR_TX_DISABLE (1 << 3)
|
||||
#define UART_CR_TX_ENABLE (1 << 2)
|
||||
#define UART_CR_RX_DISABLE (1 << 1)
|
||||
#define UART_CR_RX_ENABLE (1 << 0)
|
||||
#define UART_CR_TX_DISABLE BIT(3)
|
||||
#define UART_CR_TX_ENABLE BIT(2)
|
||||
#define UART_CR_RX_DISABLE BIT(1)
|
||||
#define UART_CR_RX_ENABLE BIT(0)
|
||||
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
|
||||
|
||||
#define UART_IMR 0x0014
|
||||
#define UART_IMR_TXLEV (1 << 0)
|
||||
#define UART_IMR_RXSTALE (1 << 3)
|
||||
#define UART_IMR_RXLEV (1 << 4)
|
||||
#define UART_IMR_DELTA_CTS (1 << 5)
|
||||
#define UART_IMR_CURRENT_CTS (1 << 6)
|
||||
#define UART_IMR_RXBREAK_START (1 << 10)
|
||||
#define UART_IMR_TXLEV BIT(0)
|
||||
#define UART_IMR_RXSTALE BIT(3)
|
||||
#define UART_IMR_RXLEV BIT(4)
|
||||
#define UART_IMR_DELTA_CTS BIT(5)
|
||||
#define UART_IMR_CURRENT_CTS BIT(6)
|
||||
#define UART_IMR_RXBREAK_START BIT(10)
|
||||
|
||||
#define UART_IPR_RXSTALE_LAST 0x20
|
||||
#define UART_IPR_STALE_LSB 0x1F
|
||||
#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
|
||||
#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
|
||||
|
||||
#define UART_IPR 0x0018
|
||||
#define UART_TFWR 0x001C
|
||||
@ -96,20 +99,20 @@
|
||||
#define UART_TEST_CTRL 0x0050
|
||||
|
||||
#define UART_SR 0x0008
|
||||
#define UART_SR_HUNT_CHAR (1 << 7)
|
||||
#define UART_SR_RX_BREAK (1 << 6)
|
||||
#define UART_SR_PAR_FRAME_ERR (1 << 5)
|
||||
#define UART_SR_OVERRUN (1 << 4)
|
||||
#define UART_SR_TX_EMPTY (1 << 3)
|
||||
#define UART_SR_TX_READY (1 << 2)
|
||||
#define UART_SR_RX_FULL (1 << 1)
|
||||
#define UART_SR_RX_READY (1 << 0)
|
||||
#define UART_SR_HUNT_CHAR BIT(7)
|
||||
#define UART_SR_RX_BREAK BIT(6)
|
||||
#define UART_SR_PAR_FRAME_ERR BIT(5)
|
||||
#define UART_SR_OVERRUN BIT(4)
|
||||
#define UART_SR_TX_EMPTY BIT(3)
|
||||
#define UART_SR_TX_READY BIT(2)
|
||||
#define UART_SR_RX_FULL BIT(1)
|
||||
#define UART_SR_RX_READY BIT(0)
|
||||
|
||||
#define UART_RF 0x000C
|
||||
#define UARTDM_RF 0x0070
|
||||
#define UART_MISR 0x0010
|
||||
#define UART_ISR 0x0014
|
||||
#define UART_ISR_TX_READY (1 << 7)
|
||||
#define UART_ISR_TX_READY BIT(7)
|
||||
|
||||
#define UARTDM_RXFS 0x50
|
||||
#define UARTDM_RXFS_BUF_SHIFT 0x7
|
||||
@ -119,6 +122,12 @@
|
||||
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
|
||||
#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
|
||||
|
||||
#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */
|
||||
#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */
|
||||
|
||||
#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */
|
||||
#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */
|
||||
|
||||
#define UARTDM_DMRX 0x34
|
||||
#define UARTDM_NCF_TX 0x40
|
||||
#define UARTDM_RX_TOTAL_SNAP 0x38
|
||||
|
@ -1196,7 +1196,7 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
|
||||
enum mctrl_gpio_idx i;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
s->gpios = mctrl_gpio_init(dev, 0);
|
||||
s->gpios = mctrl_gpio_init_noauto(dev, 0);
|
||||
if (IS_ERR(s->gpios))
|
||||
return PTR_ERR(s->gpios);
|
||||
|
||||
|
@ -21,6 +21,10 @@
|
||||
#include <linux/nwpserial.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_MODULE
|
||||
#define CONFIG_SERIAL_8250 CONFIG_SERIAL_8250_MODULE
|
||||
#endif
|
||||
|
||||
#include "8250/8250.h"
|
||||
|
||||
struct of_serial_info {
|
||||
@ -150,6 +154,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_SERIAL_8250_FSL) &&
|
||||
(of_device_is_compatible(np, "fsl,ns16550") ||
|
||||
of_device_is_compatible(np, "fsl,16550-FIFO64")))
|
||||
port->handle_irq = fsl8250_handle_irq;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if (info->clk)
|
||||
@ -350,6 +359,7 @@ static const struct of_device_id of_platform_serial_table[] = {
|
||||
#endif
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_platform_serial_table);
|
||||
|
||||
static struct platform_driver of_platform_serial_driver = {
|
||||
.driver = {
|
||||
|
@ -199,6 +199,7 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
|
||||
serial_out(up, UART_FCR, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
|
||||
{
|
||||
struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
|
||||
@ -219,6 +220,7 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
|
||||
|
||||
pdata->enable_wakeup(up->dev, enable);
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*
|
||||
* Calculate the absolute difference between the desired and actual baud
|
||||
|
@ -385,32 +385,6 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
|
||||
}
|
||||
}
|
||||
|
||||
static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
|
||||
unsigned long ufstat);
|
||||
|
||||
static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct tty_port *tty = &port->state->port;
|
||||
unsigned int ch, ufstat;
|
||||
unsigned int count;
|
||||
|
||||
ufstat = rd_regl(port, S3C2410_UFSTAT);
|
||||
count = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
while (count-- > 0) {
|
||||
ch = rd_regb(port, S3C2410_URXH);
|
||||
|
||||
ourport->port.icount.rx++;
|
||||
tty_insert_flip_char(tty, ch, TTY_NORMAL);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
|
||||
static void s3c24xx_serial_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
@ -573,7 +547,9 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
|
||||
ourport->rx_mode = S3C24XX_RX_PIO;
|
||||
}
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
|
||||
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
|
||||
{
|
||||
unsigned int utrstat, ufstat, received;
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
@ -606,7 +582,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
|
||||
enable_rx_pio(ourport);
|
||||
}
|
||||
|
||||
uart_rx_drain_fifo(ourport);
|
||||
s3c24xx_serial_rx_drain_fifo(ourport);
|
||||
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(t);
|
||||
@ -621,16 +597,12 @@ finish:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
|
||||
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
unsigned int ufcon, ch, flag, ufstat, uerstat;
|
||||
unsigned long flags;
|
||||
int max_count = port->fifosize;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
while (max_count-- > 0) {
|
||||
ufcon = rd_regl(port, S3C2410_UFCON);
|
||||
ufstat = rd_regl(port, S3C2410_UFSTAT);
|
||||
@ -654,9 +626,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
|
||||
ufcon |= S3C2410_UFCON_RESETRX;
|
||||
wr_regl(port, S3C2410_UFCON, ufcon);
|
||||
rx_enabled(port) = 1;
|
||||
spin_unlock_irqrestore(&port->lock,
|
||||
flags);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -676,7 +646,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
|
||||
dbg("break!\n");
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
goto ignore_char;
|
||||
continue; /* Ignore character */
|
||||
}
|
||||
|
||||
if (uerstat & S3C2410_UERSTAT_FRAME)
|
||||
@ -696,19 +666,25 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
goto ignore_char;
|
||||
continue; /* Ignore character */
|
||||
|
||||
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
|
||||
ch, flag);
|
||||
|
||||
ignore_char:
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
s3c24xx_serial_rx_drain_fifo(ourport);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -718,8 +694,8 @@ static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
|
||||
if (ourport->dma && ourport->dma->rx_chan)
|
||||
return s3c24xx_serial_rx_chars_dma(irq, dev_id);
|
||||
return s3c24xx_serial_rx_chars_pio(irq, dev_id);
|
||||
return s3c24xx_serial_rx_chars_dma(dev_id);
|
||||
return s3c24xx_serial_rx_chars_pio(dev_id);
|
||||
}
|
||||
|
||||
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
|
||||
|
@ -1321,6 +1321,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi)
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(sc16is7xx_dt_ids, &spi->dev);
|
||||
|
||||
if (!of_id)
|
||||
return -ENODEV;
|
||||
|
||||
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
||||
} else {
|
||||
const struct spi_device_id *id_entry = spi_get_device_id(spi);
|
||||
@ -1380,6 +1383,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(sc16is7xx_dt_ids, &i2c->dev);
|
||||
|
||||
if (!of_id)
|
||||
return -ENODEV;
|
||||
|
||||
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
||||
} else {
|
||||
devtype = (struct sc16is7xx_devtype *)id->driver_data;
|
||||
@ -1420,7 +1426,6 @@ static struct i2c_driver sc16is7xx_i2c_uart_driver = {
|
||||
.id_table = sc16is7xx_i2c_id_table,
|
||||
};
|
||||
|
||||
MODULE_ALIAS("i2c:sc16is7xx");
|
||||
#endif
|
||||
|
||||
static int __init sc16is7xx_init(void)
|
||||
|
@ -186,7 +186,6 @@ static void set_rts(struct tegra_uart_port *tup, bool active)
|
||||
tegra_uart_write(tup, mcr, UART_MCR);
|
||||
tup->mcr_shadow = mcr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void set_dtr(struct tegra_uart_port *tup, bool active)
|
||||
@ -202,7 +201,6 @@ static void set_dtr(struct tegra_uart_port *tup, bool active)
|
||||
tegra_uart_write(tup, mcr, UART_MCR);
|
||||
tup->mcr_shadow = mcr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
|
||||
@ -217,7 +215,6 @@ static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
|
||||
|
||||
dtr_enable = !!(mctrl & TIOCM_DTR);
|
||||
set_dtr(tup, dtr_enable);
|
||||
return;
|
||||
}
|
||||
|
||||
static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl)
|
||||
@ -511,7 +508,6 @@ static void tegra_uart_stop_tx(struct uart_port *u)
|
||||
async_tx_ack(tup->tx_dma_desc);
|
||||
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
||||
tup->tx_in_progress = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
|
||||
@ -523,7 +519,6 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&tup->uport);
|
||||
tegra_uart_start_next_tx(tup);
|
||||
return;
|
||||
}
|
||||
|
||||
static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
|
||||
@ -545,8 +540,6 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
|
||||
if (!uart_handle_sysrq_char(&tup->uport, ch) && tty)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
} while (1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
|
||||
@ -576,13 +569,30 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
|
||||
TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup,
|
||||
unsigned int residue)
|
||||
{
|
||||
struct tty_port *port = &tup->uport.state->port;
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
unsigned int count;
|
||||
|
||||
async_tx_ack(tup->rx_dma_desc);
|
||||
count = tup->rx_bytes_requested - residue;
|
||||
|
||||
/* If we are here, DMA is stopped */
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
|
||||
tegra_uart_handle_rx_pio(tup, port);
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(port);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
static void tegra_uart_rx_dma_complete(void *args)
|
||||
{
|
||||
struct tegra_uart_port *tup = args;
|
||||
struct uart_port *u = &tup->uport;
|
||||
unsigned int count = tup->rx_bytes_requested;
|
||||
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
|
||||
struct tty_port *port = &u->state->port;
|
||||
unsigned long flags;
|
||||
struct dma_tx_state state;
|
||||
enum dma_status status;
|
||||
@ -596,22 +606,11 @@ static void tegra_uart_rx_dma_complete(void *args)
|
||||
goto done;
|
||||
}
|
||||
|
||||
async_tx_ack(tup->rx_dma_desc);
|
||||
|
||||
/* Deactivate flow control to stop sender */
|
||||
if (tup->rts_active)
|
||||
set_rts(tup, false);
|
||||
|
||||
/* If we are here, DMA is stopped */
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
|
||||
tegra_uart_handle_rx_pio(tup, port);
|
||||
if (tty) {
|
||||
spin_unlock_irqrestore(&u->lock, flags);
|
||||
tty_flip_buffer_push(port);
|
||||
spin_lock_irqsave(&u->lock, flags);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tegra_uart_rx_buffer_push(tup, 0);
|
||||
tegra_uart_start_rx_dma(tup);
|
||||
|
||||
/* Activate flow control to start transfer */
|
||||
@ -622,34 +621,17 @@ done:
|
||||
spin_unlock_irqrestore(&u->lock, flags);
|
||||
}
|
||||
|
||||
static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
|
||||
unsigned long *flags)
|
||||
static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
|
||||
{
|
||||
struct dma_tx_state state;
|
||||
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
|
||||
struct tty_port *port = &tup->uport.state->port;
|
||||
struct uart_port *u = &tup->uport;
|
||||
unsigned int count;
|
||||
|
||||
/* Deactivate flow control to stop sender */
|
||||
if (tup->rts_active)
|
||||
set_rts(tup, false);
|
||||
|
||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||
async_tx_ack(tup->rx_dma_desc);
|
||||
count = tup->rx_bytes_requested - state.residue;
|
||||
|
||||
/* If we are here, DMA is stopped */
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
|
||||
tegra_uart_handle_rx_pio(tup, port);
|
||||
if (tty) {
|
||||
spin_unlock_irqrestore(&u->lock, *flags);
|
||||
tty_flip_buffer_push(port);
|
||||
spin_lock_irqsave(&u->lock, *flags);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||
tegra_uart_rx_buffer_push(tup, state.residue);
|
||||
tegra_uart_start_rx_dma(tup);
|
||||
|
||||
if (tup->rts_active)
|
||||
@ -697,7 +679,6 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u)
|
||||
/* Will start/stop_tx accordingly */
|
||||
if (msr & UART_MSR_DCTS)
|
||||
uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
|
||||
return;
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_uart_isr(int irq, void *data)
|
||||
@ -714,7 +695,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
|
||||
iir = tegra_uart_read(tup, UART_IIR);
|
||||
if (iir & UART_IIR_NO_INT) {
|
||||
if (is_rx_int) {
|
||||
tegra_uart_handle_rx_dma(tup, &flags);
|
||||
tegra_uart_handle_rx_dma(tup);
|
||||
if (tup->rx_in_progress) {
|
||||
ier = tup->ier_shadow;
|
||||
ier |= (UART_IER_RLSI | UART_IER_RTOIE |
|
||||
@ -769,11 +750,8 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
|
||||
static void tegra_uart_stop_rx(struct uart_port *u)
|
||||
{
|
||||
struct tegra_uart_port *tup = to_tegra_uport(u);
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port = &u->state->port;
|
||||
struct dma_tx_state state;
|
||||
unsigned long ier;
|
||||
int count;
|
||||
|
||||
if (tup->rts_active)
|
||||
set_rts(tup, false);
|
||||
@ -781,8 +759,6 @@ static void tegra_uart_stop_rx(struct uart_port *u)
|
||||
if (!tup->rx_in_progress)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&tup->uport.state->port);
|
||||
|
||||
tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */
|
||||
|
||||
ier = tup->ier_shadow;
|
||||
@ -791,21 +767,9 @@ static void tegra_uart_stop_rx(struct uart_port *u)
|
||||
tup->ier_shadow = ier;
|
||||
tegra_uart_write(tup, ier, UART_IER);
|
||||
tup->rx_in_progress = 0;
|
||||
if (tup->rx_dma_chan) {
|
||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||
async_tx_ack(tup->rx_dma_desc);
|
||||
count = tup->rx_bytes_requested - state.residue;
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
tegra_uart_handle_rx_pio(tup, port);
|
||||
} else {
|
||||
tegra_uart_handle_rx_pio(tup, port);
|
||||
}
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(port);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
return;
|
||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||
tegra_uart_rx_buffer_push(tup, state.residue);
|
||||
}
|
||||
|
||||
static void tegra_uart_hw_deinit(struct tegra_uart_port *tup)
|
||||
@ -1083,7 +1047,6 @@ static void tegra_uart_flush_buffer(struct uart_port *u)
|
||||
tup->tx_bytes = 0;
|
||||
if (tup->tx_dma_chan)
|
||||
dmaengine_terminate_all(tup->tx_dma_chan);
|
||||
return;
|
||||
}
|
||||
|
||||
static void tegra_uart_shutdown(struct uart_port *u)
|
||||
@ -1223,7 +1186,6 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
||||
tegra_uart_read(tup, UART_IER);
|
||||
|
||||
spin_unlock_irqrestore(&u->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
static const char *tegra_uart_type(struct uart_port *u)
|
||||
|
@ -1437,7 +1437,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
||||
clear_bit(ASYNCB_CLOSING, &port->flags);
|
||||
spin_unlock_irq(&port->lock);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
wake_up_interruptible(&port->close_wait);
|
||||
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
@ -1819,8 +1818,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
|
||||
* @options: ptr for <options> field; NULL if not present (out)
|
||||
*
|
||||
* Decodes earlycon kernel command line parameters of the form
|
||||
* earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
|
||||
* console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
|
||||
* earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||
* console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||
*
|
||||
* The optional form
|
||||
* earlycon=<name>,0x<addr>,<options>
|
||||
@ -1841,6 +1840,10 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
|
||||
} else if (strncmp(p, "mmio32be,", 9) == 0) {
|
||||
*iotype = UPIO_MEM32BE;
|
||||
p += 9;
|
||||
} else if (strncmp(p, "mmio32native,", 13) == 0) {
|
||||
*iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
|
||||
UPIO_MEM32BE : UPIO_MEM32;
|
||||
p += 13;
|
||||
} else if (strncmp(p, "io,", 3) == 0) {
|
||||
*iotype = UPIO_PORT;
|
||||
p += 3;
|
||||
|
@ -12,18 +12,23 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
struct mctrl_gpios {
|
||||
struct uart_port *port;
|
||||
struct gpio_desc *gpio[UART_GPIO_MAX];
|
||||
int irq[UART_GPIO_MAX];
|
||||
unsigned int mctrl_prev;
|
||||
bool mctrl_on;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
@ -82,7 +87,7 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_get);
|
||||
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
|
||||
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
|
||||
{
|
||||
struct mctrl_gpios *gpios;
|
||||
enum mctrl_gpio_idx i;
|
||||
@ -110,15 +115,135 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
|
||||
|
||||
return gpios;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
|
||||
|
||||
#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
|
||||
static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
|
||||
{
|
||||
struct mctrl_gpios *gpios = context;
|
||||
struct uart_port *port = gpios->port;
|
||||
u32 mctrl = gpios->mctrl_prev;
|
||||
u32 mctrl_diff;
|
||||
|
||||
mctrl_gpio_get(gpios, &mctrl);
|
||||
|
||||
mctrl_diff = mctrl ^ gpios->mctrl_prev;
|
||||
gpios->mctrl_prev = mctrl;
|
||||
|
||||
if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
|
||||
if ((mctrl_diff & mctrl) & TIOCM_RI)
|
||||
port->icount.rng++;
|
||||
|
||||
if ((mctrl_diff & mctrl) & TIOCM_DSR)
|
||||
port->icount.dsr++;
|
||||
|
||||
if (mctrl_diff & TIOCM_CD)
|
||||
uart_handle_dcd_change(port, mctrl & TIOCM_CD);
|
||||
|
||||
if (mctrl_diff & TIOCM_CTS)
|
||||
uart_handle_cts_change(port, mctrl & TIOCM_CTS);
|
||||
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
|
||||
{
|
||||
struct mctrl_gpios *gpios;
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
gpios = mctrl_gpio_init_noauto(port->dev, idx);
|
||||
if (IS_ERR(gpios))
|
||||
return gpios;
|
||||
|
||||
gpios->port = port;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; ++i) {
|
||||
int ret;
|
||||
|
||||
if (!gpios->gpio[i] || mctrl_gpios_desc[i].dir_out)
|
||||
continue;
|
||||
|
||||
ret = gpiod_to_irq(gpios->gpio[i]);
|
||||
if (ret <= 0) {
|
||||
dev_err(port->dev,
|
||||
"failed to find corresponding irq for %s (idx=%d, err=%d)\n",
|
||||
mctrl_gpios_desc[i].name, idx, ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
gpios->irq[i] = ret;
|
||||
|
||||
/* irqs should only be enabled in .enable_ms */
|
||||
irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
|
||||
|
||||
ret = devm_request_irq(port->dev, gpios->irq[i],
|
||||
mctrl_gpio_irq_handle,
|
||||
IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
|
||||
gpios);
|
||||
if (ret) {
|
||||
/* alternatively implement polling */
|
||||
dev_err(port->dev,
|
||||
"failed to request irq for %s (idx=%d, err=%d)\n",
|
||||
mctrl_gpios_desc[i].name, idx, ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
return gpios;
|
||||
}
|
||||
|
||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
if (gpios->irq[i])
|
||||
devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
|
||||
|
||||
if (gpios->gpio[i])
|
||||
devm_gpiod_put(dev, gpios->gpio[i]);
|
||||
}
|
||||
devm_kfree(dev, gpios);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_free);
|
||||
|
||||
void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
/* .enable_ms may be called multiple times */
|
||||
if (gpios->mctrl_on)
|
||||
return;
|
||||
|
||||
gpios->mctrl_on = true;
|
||||
|
||||
/* get initial status of modem lines GPIOs */
|
||||
mctrl_gpio_get(gpios, &gpios->mctrl_prev);
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; ++i) {
|
||||
if (!gpios->irq[i])
|
||||
continue;
|
||||
|
||||
enable_irq(gpios->irq[i]);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
|
||||
|
||||
void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (!gpios->mctrl_on)
|
||||
return;
|
||||
|
||||
gpios->mctrl_on = false;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; ++i) {
|
||||
if (!gpios->irq[i])
|
||||
continue;
|
||||
|
||||
disable_irq(gpios->irq[i]);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
struct uart_port;
|
||||
|
||||
enum mctrl_gpio_idx {
|
||||
UART_GPIO_CTS,
|
||||
UART_GPIO_DSR,
|
||||
@ -59,13 +61,23 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
|
||||
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
enum mctrl_gpio_idx gidx);
|
||||
|
||||
/*
|
||||
* Request and set direction of modem control lines GPIOs and sets up irq
|
||||
* handling.
|
||||
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
|
||||
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
||||
* allocation error.
|
||||
*/
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx);
|
||||
|
||||
/*
|
||||
* Request and set direction of modem control lines GPIOs.
|
||||
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
|
||||
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
||||
* allocation error.
|
||||
*/
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
|
||||
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
|
||||
unsigned int idx);
|
||||
|
||||
/*
|
||||
* Free the mctrl_gpios structure.
|
||||
@ -74,6 +86,16 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
|
||||
*/
|
||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
|
||||
|
||||
/*
|
||||
* Enable gpio interrupts to report status line changes.
|
||||
*/
|
||||
void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
|
||||
|
||||
/*
|
||||
* Disable gpio interrupts to report status line changes.
|
||||
*/
|
||||
void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
|
||||
|
||||
#else /* GPIOLIB */
|
||||
|
||||
static inline
|
||||
@ -95,7 +117,13 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
}
|
||||
|
||||
static inline
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
@ -105,6 +133,14 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* GPIOLIB */
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -54,10 +54,10 @@ enum {
|
||||
|
||||
#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
|
||||
|
||||
#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF)
|
||||
#define SCI_ERROR_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
|
||||
#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE)
|
||||
#define SCI_BREAK_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
|
||||
#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF))
|
||||
#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
|
||||
#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
|
||||
#define SCI_BREAK_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
|
||||
|
||||
/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
|
||||
#define SCIF_ER BIT(7) /* Receive Error */
|
||||
@ -76,10 +76,10 @@ enum {
|
||||
|
||||
#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
|
||||
|
||||
#define SCIF_RDxF_CLEAR ~(SCIF_DR | SCIF_RDF)
|
||||
#define SCIF_ERROR_CLEAR ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER)
|
||||
#define SCIF_TDxE_CLEAR ~(SCIF_TDFE)
|
||||
#define SCIF_BREAK_CLEAR ~(SCIF_PER | SCIF_FER | SCIF_BRK)
|
||||
#define SCIF_RDxF_CLEAR (u32)(~(SCIF_DR | SCIF_RDF))
|
||||
#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
|
||||
#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE))
|
||||
#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
|
||||
|
||||
/* SCFCR (FIFO Control Register) */
|
||||
#define SCFCR_MCE BIT(3) /* Modem Control Enable */
|
||||
@ -119,28 +119,11 @@ enum {
|
||||
|
||||
#define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask)
|
||||
|
||||
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
|
||||
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
|
||||
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
|
||||
defined(CONFIG_ARCH_SH73A0) || \
|
||||
defined(CONFIG_ARCH_R8A7740)
|
||||
|
||||
# define SCxSR_RDxF_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR)
|
||||
# define SCxSR_ERROR_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR)
|
||||
# define SCxSR_TDxE_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR)
|
||||
# define SCxSR_BREAK_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR)
|
||||
#else
|
||||
# define SCxSR_RDxF_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff)
|
||||
# define SCxSR_ERROR_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff)
|
||||
# define SCxSR_TDxE_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff)
|
||||
# define SCxSR_BREAK_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff)
|
||||
#endif
|
||||
|
||||
#define SCxSR_RDxF_CLEAR(port) \
|
||||
(((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
|
||||
#define SCxSR_ERROR_CLEAR(port) \
|
||||
(to_sci_port(port)->error_clear)
|
||||
#define SCxSR_TDxE_CLEAR(port) \
|
||||
(((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
|
||||
#define SCxSR_BREAK_CLEAR(port) \
|
||||
(((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR)
|
||||
|
@ -782,6 +782,7 @@ static const struct of_device_id serial_ids[] = {
|
||||
{.compatible = "sprd,sc9836-uart",},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, serial_ids);
|
||||
|
||||
static struct platform_driver sprd_platform_driver = {
|
||||
.probe = sprd_probe,
|
||||
|
@ -430,7 +430,7 @@ static void asc_break_ctl(struct uart_port *port, int break_state)
|
||||
*/
|
||||
static int asc_startup(struct uart_port *port)
|
||||
{
|
||||
if (request_irq(port->irq, asc_interrupt, IRQF_NO_SUSPEND,
|
||||
if (request_irq(port->irq, asc_interrupt, 0,
|
||||
asc_port_name(port), port)) {
|
||||
dev_err(port->dev, "cannot allocate irq.\n");
|
||||
return -ENODEV;
|
||||
|
@ -322,8 +322,7 @@ static int stm32_startup(struct uart_port *port)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
|
||||
name, port);
|
||||
ret = request_irq(port->irq, stm32_interrupt, 0, name, port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -3314,12 +3314,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
-EAGAIN : -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
dcd = tty_port_carrier_raised(&info->port);
|
||||
|
||||
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd))
|
||||
break;
|
||||
|
||||
if (do_clocal || dcd)
|
||||
break;
|
||||
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
@ -3398,15 +3397,6 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
|
||||
printk("%s(%d):mgsl_open(%s), old ref count = %d\n",
|
||||
__FILE__,__LINE__,tty->driver->name, info->port.count);
|
||||
|
||||
/* If port is closing, signal caller to try again */
|
||||
if (info->port.flags & ASYNC_CLOSING){
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
spin_lock_irqsave(&info->netlock, flags);
|
||||
@ -6635,7 +6625,7 @@ static bool mgsl_get_rx_frame(struct mgsl_struct *info)
|
||||
unsigned char *ptmp = info->intermediate_rxbuffer;
|
||||
|
||||
if ( !(status & RXSTATUS_CRC_ERROR))
|
||||
info->icount.rxok++;
|
||||
info->icount.rxok++;
|
||||
|
||||
while(copy_count) {
|
||||
int partial_count;
|
||||
|
@ -672,15 +672,6 @@ static int open(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count));
|
||||
|
||||
/* If port is closing, signal caller to try again */
|
||||
if (info->port.flags & ASYNC_CLOSING){
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mutex_lock(&info->port.mutex);
|
||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
@ -3320,9 +3311,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
}
|
||||
|
||||
cd = tty_port_carrier_raised(port);
|
||||
|
||||
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd ))
|
||||
break;
|
||||
if (do_clocal || cd)
|
||||
break;
|
||||
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
|
@ -752,15 +752,6 @@ static int open(struct tty_struct *tty, struct file *filp)
|
||||
printk("%s(%d):%s open(), old ref count = %d\n",
|
||||
__FILE__,__LINE__,tty->driver->name, info->port.count);
|
||||
|
||||
/* If port is closing, signal caller to try again */
|
||||
if (info->port.flags & ASYNC_CLOSING){
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
spin_lock_irqsave(&info->netlock, flags);
|
||||
@ -3341,9 +3332,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
}
|
||||
|
||||
cd = tty_port_carrier_raised(port);
|
||||
|
||||
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd))
|
||||
break;
|
||||
if (do_clocal || cd)
|
||||
break;
|
||||
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
|
@ -1003,6 +1003,10 @@ static const struct kernel_param_ops param_ops_sysrq_reset_seq = {
|
||||
#define param_check_sysrq_reset_seq(name, p) \
|
||||
__param_check(name, p, unsigned short)
|
||||
|
||||
/*
|
||||
* not really modular, but the easiest way to keep compat with existing
|
||||
* bootargs behaviour is to continue using module_param here.
|
||||
*/
|
||||
module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
|
||||
&sysrq_reset_seq_len, 0644);
|
||||
|
||||
@ -1119,4 +1123,4 @@ static int __init sysrq_init(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(sysrq_init);
|
||||
device_initcall(sysrq_init);
|
||||
|
@ -403,7 +403,7 @@ void tty_schedule_flip(struct tty_port *port)
|
||||
* flush_to_ldisc() sees buffer data.
|
||||
*/
|
||||
smp_store_release(&buf->tail->commit, buf->tail->used);
|
||||
schedule_work(&buf->work);
|
||||
queue_work(system_unbound_wq, &buf->work);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_schedule_flip);
|
||||
|
||||
@ -587,3 +587,13 @@ void tty_buffer_set_lock_subclass(struct tty_port *port)
|
||||
{
|
||||
lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
|
||||
}
|
||||
|
||||
bool tty_buffer_restart_work(struct tty_port *port)
|
||||
{
|
||||
return queue_work(system_unbound_wq, &port->buf.work);
|
||||
}
|
||||
|
||||
bool tty_buffer_cancel_work(struct tty_port *port)
|
||||
{
|
||||
return cancel_work_sync(&port->buf.work);
|
||||
}
|
||||
|
@ -390,10 +390,10 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver);
|
||||
* Locking: ctrl_lock
|
||||
*/
|
||||
|
||||
int tty_check_change(struct tty_struct *tty)
|
||||
int __tty_check_change(struct tty_struct *tty, int sig)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct pid *pgrp;
|
||||
struct pid *pgrp, *tty_pgrp;
|
||||
int ret = 0;
|
||||
|
||||
if (current->signal->tty != tty)
|
||||
@ -403,33 +403,35 @@ int tty_check_change(struct tty_struct *tty)
|
||||
pgrp = task_pgrp(current);
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
|
||||
if (!tty->pgrp) {
|
||||
printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
if (pgrp == tty->pgrp)
|
||||
goto out_unlock;
|
||||
tty_pgrp = tty->pgrp;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
|
||||
if (is_ignored(SIGTTOU))
|
||||
goto out_rcuunlock;
|
||||
if (is_current_pgrp_orphaned()) {
|
||||
ret = -EIO;
|
||||
goto out_rcuunlock;
|
||||
if (tty_pgrp && pgrp != tty->pgrp) {
|
||||
if (is_ignored(sig)) {
|
||||
if (sig == SIGTTIN)
|
||||
ret = -EIO;
|
||||
} else if (is_current_pgrp_orphaned())
|
||||
ret = -EIO;
|
||||
else {
|
||||
kill_pgrp(pgrp, sig, 1);
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
ret = -ERESTARTSYS;
|
||||
}
|
||||
}
|
||||
kill_pgrp(pgrp, SIGTTOU, 1);
|
||||
rcu_read_unlock();
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
ret = -ERESTARTSYS;
|
||||
return ret;
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
out_rcuunlock:
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!tty_pgrp) {
|
||||
pr_warn("%s: tty_check_change: sig=%d, tty->pgrp == NULL!\n",
|
||||
tty_name(tty), sig);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tty_check_change(struct tty_struct *tty)
|
||||
{
|
||||
return __tty_check_change(tty, SIGTTOU);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_check_change);
|
||||
|
||||
static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
|
||||
@ -1198,11 +1200,9 @@ void tty_write_message(struct tty_struct *tty, char *msg)
|
||||
if (tty) {
|
||||
mutex_lock(&tty->atomic_write_lock);
|
||||
tty_lock(tty);
|
||||
if (tty->ops->write && tty->count > 0) {
|
||||
tty_unlock(tty);
|
||||
if (tty->ops->write && tty->count > 0)
|
||||
tty->ops->write(tty, msg, strlen(msg));
|
||||
} else
|
||||
tty_unlock(tty);
|
||||
tty_unlock(tty);
|
||||
tty_write_unlock(tty);
|
||||
}
|
||||
return;
|
||||
@ -1689,7 +1689,7 @@ static void release_tty(struct tty_struct *tty, int idx)
|
||||
tty->port->itty = NULL;
|
||||
if (tty->link)
|
||||
tty->link->port->itty = NULL;
|
||||
cancel_work_sync(&tty->port->buf.work);
|
||||
tty_buffer_cancel_work(tty->port);
|
||||
|
||||
tty_kref_put(tty->link);
|
||||
tty_kref_put(tty);
|
||||
@ -2569,7 +2569,6 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
|
||||
struct pid *pgrp;
|
||||
pid_t pgrp_nr;
|
||||
int retval = tty_check_change(real_tty);
|
||||
unsigned long flags;
|
||||
|
||||
if (retval == -EIO)
|
||||
return -ENOTTY;
|
||||
@ -2592,10 +2591,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
|
||||
if (session_of_pgrp(pgrp) != task_session(current))
|
||||
goto out_unlock;
|
||||
retval = 0;
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
put_pid(real_tty->pgrp);
|
||||
real_tty->pgrp = get_pid(pgrp);
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
return retval;
|
||||
|
@ -319,7 +319,7 @@ __tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
|
||||
|
||||
static inline void __tty_ldisc_unlock(struct tty_struct *tty)
|
||||
{
|
||||
return ldsem_up_write(&tty->ldisc_sem);
|
||||
ldsem_up_write(&tty->ldisc_sem);
|
||||
}
|
||||
|
||||
static int __lockfunc
|
||||
|
@ -22,7 +22,6 @@ void tty_port_init(struct tty_port *port)
|
||||
memset(port, 0, sizeof(*port));
|
||||
tty_buffer_init(port);
|
||||
init_waitqueue_head(&port->open_wait);
|
||||
init_waitqueue_head(&port->close_wait);
|
||||
init_waitqueue_head(&port->delta_msr_wait);
|
||||
mutex_init(&port->mutex);
|
||||
mutex_init(&port->buf_mutex);
|
||||
@ -131,7 +130,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf);
|
||||
*/
|
||||
void tty_port_destroy(struct tty_port *port)
|
||||
{
|
||||
cancel_work_sync(&port->buf.work);
|
||||
tty_buffer_cancel_work(port);
|
||||
tty_buffer_free_all(port);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_destroy);
|
||||
@ -363,16 +362,6 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
unsigned long flags;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
/* block if port is in the process of being closed */
|
||||
if (port->flags & ASYNC_CLOSING) {
|
||||
wait_event_interruptible_tty(tty, port->close_wait,
|
||||
!(port->flags & ASYNC_CLOSING));
|
||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
/* if non-blocking mode is set we can pass directly to open unless
|
||||
the port has just hung up or is in another error state */
|
||||
if (tty->flags & (1 << TTY_IO_ERROR)) {
|
||||
@ -423,8 +412,7 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
* Never ask drivers if CLOCAL is set, this causes troubles
|
||||
* on some hardware.
|
||||
*/
|
||||
if (!(port->flags & ASYNC_CLOSING) &&
|
||||
(do_clocal || tty_port_carrier_raised(port)))
|
||||
if (do_clocal || tty_port_carrier_raised(port))
|
||||
break;
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
@ -463,10 +451,7 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
|
||||
schedule_timeout_interruptible(timeout);
|
||||
}
|
||||
|
||||
/* Caller holds tty lock.
|
||||
* NB: may drop and reacquire tty lock (in tty_wait_until_sent_from_close())
|
||||
* so tty and tty port may have changed state (but not hung up or reopened).
|
||||
*/
|
||||
/* Caller holds tty lock. */
|
||||
int tty_port_close_start(struct tty_port *port,
|
||||
struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
@ -502,7 +487,7 @@ int tty_port_close_start(struct tty_port *port,
|
||||
if (tty->flow_stopped)
|
||||
tty_driver_flush_buffer(tty);
|
||||
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent_from_close(tty, port->closing_wait);
|
||||
tty_wait_until_sent(tty, port->closing_wait);
|
||||
if (port->drain_delay)
|
||||
tty_port_drain_delay(port, tty);
|
||||
}
|
||||
@ -534,7 +519,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
}
|
||||
port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
|
||||
wake_up_interruptible(&port->close_wait);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_close_end);
|
||||
@ -543,10 +527,6 @@ EXPORT_SYMBOL(tty_port_close_end);
|
||||
* tty_port_close
|
||||
*
|
||||
* Caller holds tty lock
|
||||
*
|
||||
* NB: may drop and reacquire tty lock (in tty_port_close_start()->
|
||||
* tty_wait_until_sent_from_close()) so tty and tty_port may have changed
|
||||
* state (but not hung up or reopened).
|
||||
*/
|
||||
void tty_port_close(struct tty_port *port, struct tty_struct *tty,
|
||||
struct file *filp)
|
||||
|
@ -114,6 +114,7 @@ struct gs_port {
|
||||
struct gs_buf port_write_buf;
|
||||
wait_queue_head_t drain_wait; /* wait while writes drain */
|
||||
bool write_busy;
|
||||
wait_queue_head_t close_wait;
|
||||
|
||||
/* REVISIT this state ... */
|
||||
struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
|
||||
@ -883,7 +884,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
||||
pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
|
||||
port->port_num, tty, file);
|
||||
|
||||
wake_up(&port->port.close_wait);
|
||||
wake_up(&port->close_wait);
|
||||
exit:
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
}
|
||||
@ -1043,6 +1044,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
|
||||
tty_port_init(&port->port);
|
||||
spin_lock_init(&port->port_lock);
|
||||
init_waitqueue_head(&port->drain_wait);
|
||||
init_waitqueue_head(&port->close_wait);
|
||||
|
||||
tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
|
||||
|
||||
@ -1073,7 +1075,7 @@ static void gserial_free_port(struct gs_port *port)
|
||||
{
|
||||
tasklet_kill(&port->push);
|
||||
/* wait for old opens to finish */
|
||||
wait_event(port->port.close_wait, gs_closed(port));
|
||||
wait_event(port->close_wait, gs_closed(port));
|
||||
WARN_ON(port->port_usb != NULL);
|
||||
tty_port_destroy(&port->port);
|
||||
kfree(port);
|
||||
|
@ -35,14 +35,23 @@ struct hsu_dma_chip {
|
||||
unsigned int length;
|
||||
unsigned int offset;
|
||||
struct hsu_dma *hsu;
|
||||
struct hsu_dma_platform_data *pdata;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_HSU_DMA)
|
||||
/* Export to the internal users */
|
||||
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr);
|
||||
|
||||
/* Export to the platform drivers */
|
||||
int hsu_dma_probe(struct hsu_dma_chip *chip);
|
||||
int hsu_dma_remove(struct hsu_dma_chip *chip);
|
||||
#else
|
||||
static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip,
|
||||
unsigned short nr)
|
||||
{
|
||||
return IRQ_NONE;
|
||||
}
|
||||
static inline int hsu_dma_probe(struct hsu_dma_chip *chip) { return -ENODEV; }
|
||||
static inline int hsu_dma_remove(struct hsu_dma_chip *chip) { return 0; }
|
||||
#endif /* CONFIG_HSU_DMA */
|
||||
|
||||
#endif /* _DMA_HSU_H */
|
||||
|
@ -152,9 +152,6 @@ struct r3964_info {
|
||||
unsigned char *rx_buf; /* ring buffer */
|
||||
unsigned char *tx_buf;
|
||||
|
||||
wait_queue_head_t read_wait;
|
||||
//struct wait_queue *read_wait;
|
||||
|
||||
struct r3964_block_header *rx_first;
|
||||
struct r3964_block_header *rx_last;
|
||||
struct r3964_block_header *tx_first;
|
||||
@ -164,8 +161,9 @@ struct r3964_info {
|
||||
unsigned char last_rx;
|
||||
unsigned char bcc;
|
||||
unsigned int blocks_in_rx_queue;
|
||||
|
||||
|
||||
|
||||
struct mutex read_lock; /* serialize r3964_read */
|
||||
|
||||
struct r3964_client_info *firstClient;
|
||||
unsigned int state;
|
||||
unsigned int flags;
|
||||
|
@ -19,12 +19,6 @@
|
||||
#include <linux/serial.h>
|
||||
#include <linux/platform_data/macb.h>
|
||||
|
||||
/*
|
||||
* at91: 6 USARTs and one DBGU port (SAM9260)
|
||||
* avr32: 4
|
||||
*/
|
||||
#define ATMEL_MAX_UART 7
|
||||
|
||||
/* Compact Flash */
|
||||
struct at91_cf_data {
|
||||
int irq_pin; /* I/O IRQ */
|
||||
|
@ -18,8 +18,4 @@ struct hsu_dma_slave {
|
||||
int chan_id;
|
||||
};
|
||||
|
||||
struct hsu_dma_platform_data {
|
||||
unsigned short nr_channels;
|
||||
};
|
||||
|
||||
#endif /* _PLATFORM_DATA_DMA_HSU_H */
|
||||
|
@ -227,7 +227,6 @@ struct tty_port {
|
||||
int blocked_open; /* Waiting to open */
|
||||
int count; /* Usage count */
|
||||
wait_queue_head_t open_wait; /* Open waiters */
|
||||
wait_queue_head_t close_wait; /* Close waiters */
|
||||
wait_queue_head_t delta_msr_wait; /* Modem status change */
|
||||
unsigned long flags; /* TTY flags ASY_*/
|
||||
unsigned char console:1, /* port is a console */
|
||||
@ -424,6 +423,7 @@ extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
|
||||
const char *routine);
|
||||
extern const char *tty_name(const struct tty_struct *tty);
|
||||
extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
|
||||
extern int __tty_check_change(struct tty_struct *tty, int sig);
|
||||
extern int tty_check_change(struct tty_struct *tty);
|
||||
extern void __stop_tty(struct tty_struct *tty);
|
||||
extern void stop_tty(struct tty_struct *tty);
|
||||
@ -467,6 +467,8 @@ extern void tty_buffer_free_all(struct tty_port *port);
|
||||
extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
|
||||
extern void tty_buffer_init(struct tty_port *port);
|
||||
extern void tty_buffer_set_lock_subclass(struct tty_port *port);
|
||||
extern bool tty_buffer_restart_work(struct tty_port *port);
|
||||
extern bool tty_buffer_cancel_work(struct tty_port *port);
|
||||
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
|
||||
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
|
||||
extern void tty_termios_encode_baud_rate(struct ktermios *termios,
|
||||
@ -656,50 +658,6 @@ extern void __lockfunc tty_unlock(struct tty_struct *tty);
|
||||
extern void __lockfunc tty_lock_slave(struct tty_struct *tty);
|
||||
extern void __lockfunc tty_unlock_slave(struct tty_struct *tty);
|
||||
extern void tty_set_lock_subclass(struct tty_struct *tty);
|
||||
/*
|
||||
* this shall be called only from where BTM is held (like close)
|
||||
*
|
||||
* We need this to ensure nobody waits for us to finish while we are waiting.
|
||||
* Without this we were encountering system stalls.
|
||||
*
|
||||
* This should be indeed removed with BTM removal later.
|
||||
*
|
||||
* Locking: BTM required. Nobody is allowed to hold port->mutex.
|
||||
*/
|
||||
static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
|
||||
long timeout)
|
||||
{
|
||||
tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
|
||||
tty_wait_until_sent(tty, timeout);
|
||||
tty_lock(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
* wait_event_interruptible_tty -- wait for a condition with the tty lock held
|
||||
*
|
||||
* The condition we are waiting for might take a long time to
|
||||
* become true, or might depend on another thread taking the
|
||||
* BTM. In either case, we need to drop the BTM to guarantee
|
||||
* forward progress. This is a leftover from the conversion
|
||||
* from the BKL and should eventually get removed as the BTM
|
||||
* falls out of use.
|
||||
*
|
||||
* Do not use in new code.
|
||||
*/
|
||||
#define wait_event_interruptible_tty(tty, wq, condition) \
|
||||
({ \
|
||||
int __ret = 0; \
|
||||
if (!(condition)) \
|
||||
__ret = __wait_event_interruptible_tty(tty, wq, \
|
||||
condition); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define __wait_event_interruptible_tty(tty, wq, condition) \
|
||||
___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \
|
||||
tty_unlock(tty); \
|
||||
schedule(); \
|
||||
tty_lock(tty))
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern void proc_tty_register_driver(struct tty_driver *);
|
||||
|
@ -335,8 +335,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
|
||||
* specified, we cannot return before the IrCOMM link is
|
||||
* ready
|
||||
*/
|
||||
if (!test_bit(ASYNCB_CLOSING, &port->flags) &&
|
||||
(do_clocal || tty_port_carrier_raised(port)) &&
|
||||
if ((do_clocal || tty_port_carrier_raised(port)) &&
|
||||
self->state == IRCOMM_TTY_READY)
|
||||
{
|
||||
break;
|
||||
@ -443,34 +442,6 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
/* Not really used by us, but lets do it anyway */
|
||||
self->port.low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* If the port is the middle of closing, bail out now
|
||||
*/
|
||||
if (test_bit(ASYNCB_CLOSING, &self->port.flags)) {
|
||||
|
||||
/* Hm, why are we blocking on ASYNC_CLOSING if we
|
||||
* do return -EAGAIN/-ERESTARTSYS below anyway?
|
||||
* IMHO it's either not needed in the first place
|
||||
* or for some reason we need to make sure the async
|
||||
* closing has been finished - if so, wouldn't we
|
||||
* probably better sleep uninterruptible?
|
||||
*/
|
||||
|
||||
if (wait_event_interruptible(self->port.close_wait,
|
||||
!test_bit(ASYNCB_CLOSING, &self->port.flags))) {
|
||||
net_warn_ratelimited("%s - got signal while blocking on ASYNC_CLOSING!\n",
|
||||
__func__);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
return (self->port.flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS;
|
||||
#else
|
||||
return -EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if this is a "normal" ircomm device, or an irlpt device */
|
||||
if (self->line < 0x10) {
|
||||
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
|
||||
|
Loading…
Reference in New Issue
Block a user