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
Documentation
arch/arm64/include/asm
drivers
char/pcmcia
dma/hsu
isdn/i4l
tty
cyclades.c
hvc
mips_ejtag_fdc.cn_r3964.cn_tty.cpty.crocket.cserial
68328serial.c
synclink.csynclink_gt.csynclinkmp.csysrq.ctty_buffer.ctty_io.ctty_ldisc.ctty_port.c8250
8250_core.c8250_dma.c8250_dw.c8250_early.c8250_ingenic.c8250_mid.c8250_omap.c8250_pci.c8250_port.cKconfigMakefile
Kconfigaltera_uart.camba-pl011.capbuart.catmel_serial.cclps711x.ccpm_uart
crisv10.cfsl_lpuart.cimx.clpc32xx_hs.cmen_z135_uart.cmpc52xx_uart.cmpsc.cmsm_serial.cmsm_serial.hmxs-auart.cof_serial.comap-serial.csamsung.csc16is7xx.cserial-tegra.cserial_core.cserial_mctrl_gpio.cserial_mctrl_gpio.hsh-sci.csh-sci.hsprd_serial.cst-asc.cstm32-usart.cusb/gadget/function
include/linux
net/irda/ircomm
|
@ -1,7 +1,8 @@
|
||||||
* Ingenic SoC UART
|
* Ingenic SoC UART
|
||||||
|
|
||||||
Required properties:
|
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.
|
- reg : offset and length of the register set for the device.
|
||||||
- interrupts : should contain uart interrupt.
|
- interrupts : should contain uart interrupt.
|
||||||
- clocks : phandles to the module & baud clocks.
|
- clocks : phandles to the module & baud clocks.
|
||||||
|
|
|
@ -19,7 +19,7 @@ Optional properties:
|
||||||
must correspond to the PCLK clocking the internal logic
|
must correspond to the PCLK clocking the internal logic
|
||||||
of the block. Just listing one clock (the first one) is
|
of the block. Just listing one clock (the first one) is
|
||||||
deprecated.
|
deprecated.
|
||||||
- clocks-names:
|
- clock-names:
|
||||||
When present, the first clock listed must be named
|
When present, the first clock listed must be named
|
||||||
"uartclk" and the second clock listed must be named
|
"uartclk" and the second clock listed must be named
|
||||||
"apb_pclk"
|
"apb_pclk"
|
||||||
|
|
|
@ -26,6 +26,12 @@ Required properties:
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- dmas: Should contain dma specifiers for transmit and receive channels
|
- dmas: Should contain dma specifiers for transmit and receive channels
|
||||||
- dma-names: Should contain "tx" for transmit and "rx" for 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.
|
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
|
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,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART.
|
||||||
- "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB 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,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,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||||
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
|
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
|
||||||
- "renesas,scif" for generic SCIF 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"
|
Required elements: "baudclk", "apb_pclk"
|
||||||
|
|
||||||
Optional properties:
|
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.
|
- resets : phandle to the parent reset controller.
|
||||||
- reg-shift : quantity to shift the register offsets by. If this property is
|
- reg-shift : quantity to shift the register offsets by. If this property is
|
||||||
not present then the register offsets are not shifted.
|
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.
|
serial port must already be setup and configured.
|
||||||
Options are not yet supported.
|
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= [X86,SH,BLACKFIN,ARM,M68k]
|
||||||
earlyprintk=vga
|
earlyprintk=vga
|
||||||
earlyprintk=efi
|
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.
|
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
|
This will get the {cts,rts,...}-gpios from device tree if they are
|
||||||
present and request them, set direction etc, and return an
|
present and request them, set direction etc, and return an
|
||||||
allocated structure. devm_* functions are used, so there's no need
|
allocated structure. devm_* functions are used, so there's no need
|
||||||
to call mctrl_gpio_free().
|
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):
|
mctrl_gpio_free(dev, gpios):
|
||||||
This will free the requested gpios in mctrl_gpio_init().
|
This will free the requested gpios in mctrl_gpio_init().
|
||||||
|
@ -458,3 +460,9 @@ mctrl_gpio_set(gpios, mctrl):
|
||||||
|
|
||||||
mctrl_gpio_get(gpios, mctrl):
|
mctrl_gpio_get(gpios, mctrl):
|
||||||
This will update mctrl with the gpios values.
|
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
|
open() - Called when the line discipline is attached to
|
||||||
the terminal. No other call into the line
|
the terminal. No other call into the line
|
||||||
discipline for this tty will occur until it
|
discipline for this tty will occur until it
|
||||||
completes successfully. Returning an error will
|
completes successfully. Should initialize any
|
||||||
prevent the ldisc from being attached. Can sleep.
|
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
|
close() - This is called on a terminal when the line
|
||||||
discipline is being unplugged. At the point of
|
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.
|
No further calls into the ldisc code will occur.
|
||||||
The return value is ignored. Can sleep.
|
The return value is ignored. Can sleep.
|
||||||
|
|
||||||
write() - A process is writing data through the line
|
read() - (optional) A process requests reading data from
|
||||||
discipline. Multiple write calls are serialized
|
the line. Multiple read calls may occur in parallel
|
||||||
by the tty layer for the ldisc. May sleep.
|
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
|
flush_buffer() - (optional) May be called at any point between
|
||||||
open and close, and instructs the line discipline
|
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
|
termios semaphore so allowed to sleep. Serialized
|
||||||
against itself only.
|
against itself only.
|
||||||
|
|
||||||
read() - Move data from the line discipline to the user.
|
poll() - (optional) Check the status for the poll/select
|
||||||
Multiple read calls may occur in parallel and the
|
calls. Multiple poll calls may occur in parallel.
|
||||||
ldisc must deal with serialization issues. May
|
May sleep.
|
||||||
sleep.
|
|
||||||
|
|
||||||
poll() - Check the status for the poll/select calls. Multiple
|
ioctl() - (optional) Called when an ioctl is handed to the
|
||||||
poll calls may occur in parallel. May sleep.
|
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
|
compat_ioctl() - (optional) Called when a 32 bit ioctl is handed
|
||||||
that might be for the ldisc. Multiple ioctl calls
|
to the tty layer that might be for the ldisc.
|
||||||
may occur in parallel. May sleep.
|
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.
|
|
||||||
|
|
||||||
Driver Side Interfaces:
|
Driver Side Interfaces:
|
||||||
|
|
||||||
receive_buf() - Hand buffers of bytes from the driver to the ldisc
|
receive_buf() - (optional) Called by the low-level driver to hand
|
||||||
for processing. Semantics currently rather
|
a buffer of received bytes to the ldisc for
|
||||||
mysterious 8(
|
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.
|
write_wakeup() - May be called at any point between open and close.
|
||||||
The TTY_DO_WRITE_WAKEUP flag indicates if a call
|
The TTY_DO_WRITE_WAKEUP flag indicates if a call
|
||||||
|
|
|
@ -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",
|
printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
|
||||||
__FILE__, __LINE__, tty->driver->name, port->count);
|
__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;
|
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&info->netlock, flags);
|
spin_lock_irqsave(&info->netlock, flags);
|
||||||
|
|
|
@ -5,10 +5,5 @@ config HSU_DMA
|
||||||
select DMA_VIRTUAL_CHANNELS
|
select DMA_VIRTUAL_CHANNELS
|
||||||
|
|
||||||
config HSU_DMA_PCI
|
config HSU_DMA_PCI
|
||||||
tristate "High Speed UART DMA PCI driver"
|
tristate
|
||||||
depends on PCI
|
depends on HSU_DMA && 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.
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
|
||||||
u32 sr;
|
u32 sr;
|
||||||
|
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
if (nr >= chip->pdata->nr_channels)
|
if (nr >= chip->hsu->nr_channels)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
hsuc = &chip->hsu->chan[nr];
|
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)
|
int hsu_dma_probe(struct hsu_dma_chip *chip)
|
||||||
{
|
{
|
||||||
struct hsu_dma *hsu;
|
struct hsu_dma *hsu;
|
||||||
struct hsu_dma_platform_data *pdata = chip->pdata;
|
|
||||||
void __iomem *addr = chip->regs + chip->offset;
|
void __iomem *addr = chip->regs + chip->offset;
|
||||||
unsigned short i;
|
unsigned short i;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -386,25 +385,16 @@ int hsu_dma_probe(struct hsu_dma_chip *chip)
|
||||||
|
|
||||||
chip->hsu = hsu;
|
chip->hsu = hsu;
|
||||||
|
|
||||||
if (!pdata) {
|
/* Calculate nr_channels from the IO space length */
|
||||||
pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
|
hsu->nr_channels = (chip->length - chip->offset) / HSU_DMA_CHAN_LENGTH;
|
||||||
if (!pdata)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
chip->pdata = pdata;
|
hsu->chan = devm_kcalloc(chip->dev, hsu->nr_channels,
|
||||||
|
|
||||||
/* 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,
|
|
||||||
sizeof(*hsu->chan), GFP_KERNEL);
|
sizeof(*hsu->chan), GFP_KERNEL);
|
||||||
if (!hsu->chan)
|
if (!hsu->chan)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&hsu->dma.channels);
|
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];
|
struct hsu_dma_chan *hsuc = &hsu->chan[i];
|
||||||
|
|
||||||
hsuc->vchan.desc_free = hsu_dma_desc_free;
|
hsuc->vchan.desc_free = hsu_dma_desc_free;
|
||||||
|
@ -440,7 +430,7 @@ int hsu_dma_probe(struct hsu_dma_chip *chip)
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hsu_dma_probe);
|
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);
|
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];
|
struct hsu_dma_chan *hsuc = &hsu->chan[i];
|
||||||
|
|
||||||
tasklet_kill(&hsuc->vchan.task);
|
tasklet_kill(&hsuc->vchan.task);
|
||||||
|
|
|
@ -107,6 +107,7 @@ struct hsu_dma {
|
||||||
|
|
||||||
/* channels */
|
/* channels */
|
||||||
struct hsu_dma_chan *chan;
|
struct hsu_dma_chan *chan;
|
||||||
|
unsigned short nr_channels;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct hsu_dma *to_hsu_dma(struct dma_device *ddev)
|
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;
|
irqreturn_t ret = IRQ_NONE;
|
||||||
|
|
||||||
dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
|
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)
|
if (dmaisr & 0x1)
|
||||||
ret |= hsu_dma_irq(chip, i);
|
ret |= hsu_dma_irq(chip, i);
|
||||||
dmaisr >>= 1;
|
dmaisr >>= 1;
|
||||||
|
|
|
@ -1582,7 +1582,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
||||||
* line status register.
|
* line status register.
|
||||||
*/
|
*/
|
||||||
if (port->flags & ASYNC_INITIALIZED) {
|
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
|
* Before we drop DTR, make sure the UART transmitter
|
||||||
* has completely drained; this is especially
|
* 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);
|
current->pid, info->port.count);
|
||||||
#endif
|
#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
|
* Start up serial port
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -81,7 +81,7 @@ config HVC_UDBG
|
||||||
|
|
||||||
config HVC_DCC
|
config HVC_DCC
|
||||||
bool "ARM JTAG DCC console"
|
bool "ARM JTAG DCC console"
|
||||||
depends on ARM
|
depends on ARM || ARM64
|
||||||
select HVC_DRIVER
|
select HVC_DRIVER
|
||||||
help
|
help
|
||||||
This console uses the JTAG DCC on ARM to create a console under the HVC
|
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/kernel.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/module.h>
|
#include <linux/init.h>
|
||||||
#include <linux/major.h>
|
#include <linux/major.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/sysrq.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
|
* there is no buffered data otherwise sleeps on a wait queue
|
||||||
* waking periodically to check chars_in_buffer().
|
* 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 {
|
} else {
|
||||||
if (hp->port.count < 0)
|
if (hp->port.count < 0)
|
||||||
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
|
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
|
||||||
|
@ -1005,19 +1005,3 @@ static int hvc_init(void)
|
||||||
out:
|
out:
|
||||||
return err;
|
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)
|
static int __init hvc_dcc_console_init(void)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!hvc_dcc_check())
|
if (!hvc_dcc_check())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
|
/* Returns -1 if error */
|
||||||
return 0;
|
ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
|
||||||
|
|
||||||
|
return ret < 0 ? -ENODEV : 0;
|
||||||
}
|
}
|
||||||
console_initcall(hvc_dcc_console_init);
|
console_initcall(hvc_dcc_console_init);
|
||||||
|
|
||||||
static int __init hvc_dcc_init(void)
|
static int __init hvc_dcc_init(void)
|
||||||
{
|
{
|
||||||
|
struct hvc_struct *p;
|
||||||
|
|
||||||
if (!hvc_dcc_check())
|
if (!hvc_dcc_check())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
|
p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
|
||||||
return 0;
|
|
||||||
|
return PTR_ERR_OR_ZERO(p);
|
||||||
}
|
}
|
||||||
device_initcall(hvc_dcc_init);
|
device_initcall(hvc_dcc_init);
|
||||||
|
|
|
@ -1230,7 +1230,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
||||||
irq = hvcsd->vdev->irq;
|
irq = hvcsd->vdev->irq;
|
||||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
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
|
* 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 */
|
/* Try requesting the IRQ */
|
||||||
if (priv->irq >= 0) {
|
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
|
* other local interrupts such as the timer which sets
|
||||||
* IRQF_TIMER (including IRQF_NO_SUSPEND).
|
* 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,
|
ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr,
|
||||||
IRQF_PERCPU | IRQF_SHARED |
|
IRQF_PERCPU | IRQF_SHARED |
|
||||||
IRQF_NO_THREAD | IRQF_NO_SUSPEND,
|
IRQF_NO_THREAD | IRQF_COND_SUSPEND,
|
||||||
priv->fdc_name, priv);
|
priv->fdc_name, priv);
|
||||||
if (ret)
|
if (ret)
|
||||||
priv->irq = -1;
|
priv->irq = -1;
|
||||||
|
@ -1048,38 +1048,6 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
|
||||||
return ret;
|
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)
|
static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev)
|
||||||
{
|
{
|
||||||
struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(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",
|
.name = "mips_ejtag_fdc",
|
||||||
},
|
},
|
||||||
.probe = mips_ejtag_fdc_tty_probe,
|
.probe = mips_ejtag_fdc_tty_probe,
|
||||||
.remove = mips_ejtag_fdc_tty_remove,
|
|
||||||
.cpu_down = mips_ejtag_fdc_tty_cpu_down,
|
.cpu_down = mips_ejtag_fdc_tty_cpu_down,
|
||||||
.cpu_up = mips_ejtag_fdc_tty_cpu_up,
|
.cpu_up = mips_ejtag_fdc_tty_cpu_up,
|
||||||
.id_table = mips_ejtag_fdc_tty_ids,
|
.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)
|
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,
|
add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
|
||||||
error_code, NULL);
|
error_code, NULL);
|
||||||
}
|
}
|
||||||
wake_up_interruptible(&pInfo->read_wait);
|
wake_up_interruptible(&pInfo->tty->read_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&pInfo->lock, flags);
|
spin_lock_irqsave(&pInfo->lock, flags);
|
||||||
|
@ -542,7 +542,7 @@ static void on_receive_block(struct r3964_info *pInfo)
|
||||||
pBlock);
|
pBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wake_up_interruptible(&pInfo->read_wait);
|
wake_up_interruptible(&pInfo->tty->read_wait);
|
||||||
|
|
||||||
pInfo->state = R3964_IDLE;
|
pInfo->state = R3964_IDLE;
|
||||||
|
|
||||||
|
@ -978,8 +978,8 @@ static int r3964_open(struct tty_struct *tty)
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_init(&pInfo->lock);
|
spin_lock_init(&pInfo->lock);
|
||||||
|
mutex_init(&pInfo->read_lock);
|
||||||
pInfo->tty = tty;
|
pInfo->tty = tty;
|
||||||
init_waitqueue_head(&pInfo->read_wait);
|
|
||||||
pInfo->priority = R3964_MASTER;
|
pInfo->priority = R3964_MASTER;
|
||||||
pInfo->rx_first = pInfo->rx_last = NULL;
|
pInfo->rx_first = pInfo->rx_last = NULL;
|
||||||
pInfo->tx_first = pInfo->tx_last = NULL;
|
pInfo->tx_first = pInfo->tx_last = NULL;
|
||||||
|
@ -1045,7 +1045,6 @@ static void r3964_close(struct tty_struct *tty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free buffers: */
|
/* Free buffers: */
|
||||||
wake_up_interruptible(&pInfo->read_wait);
|
|
||||||
kfree(pInfo->rx_buf);
|
kfree(pInfo->rx_buf);
|
||||||
TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
|
TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
|
||||||
kfree(pInfo->tx_buf);
|
kfree(pInfo->tx_buf);
|
||||||
|
@ -1065,7 +1064,16 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||||
|
|
||||||
TRACE_L("read()");
|
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));
|
pClient = findClient(pInfo, task_pid(current));
|
||||||
if (pClient) {
|
if (pClient) {
|
||||||
|
@ -1077,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
/* block until there is a message: */
|
/* 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)));
|
(pMsg = remove_msg(pInfo, pClient)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1107,7 +1115,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||||
}
|
}
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
unlock:
|
unlock:
|
||||||
tty_unlock(tty);
|
mutex_unlock(&pInfo->read_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1156,8 +1164,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
|
||||||
pHeader->locks = 0;
|
pHeader->locks = 0;
|
||||||
pHeader->owner = NULL;
|
pHeader->owner = NULL;
|
||||||
|
|
||||||
tty_lock(tty);
|
|
||||||
|
|
||||||
pClient = findClient(pInfo, task_pid(current));
|
pClient = findClient(pInfo, task_pid(current));
|
||||||
if (pClient) {
|
if (pClient) {
|
||||||
pHeader->owner = 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);
|
add_tx_queue(pInfo, pHeader);
|
||||||
trigger_transmit(pInfo);
|
trigger_transmit(pInfo);
|
||||||
|
|
||||||
tty_unlock(tty);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1227,7 +1231,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
|
||||||
|
|
||||||
pClient = findClient(pInfo, task_pid(current));
|
pClient = findClient(pInfo, task_pid(current));
|
||||||
if (pClient) {
|
if (pClient) {
|
||||||
poll_wait(file, &pInfo->read_wait, wait);
|
poll_wait(file, &tty->read_wait, wait);
|
||||||
spin_lock_irqsave(&pInfo->lock, flags);
|
spin_lock_irqsave(&pInfo->lock, flags);
|
||||||
pMsg = pClient->first_msg;
|
pMsg = pClient->first_msg;
|
||||||
spin_unlock_irqrestore(&pInfo->lock, flags);
|
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),
|
WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
|
||||||
"scheduling buffer work for halted ldisc\n");
|
"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);
|
||||||
}
|
}
|
||||||
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);
|
put_tty_queue('\0', ldata);
|
||||||
} else
|
} else
|
||||||
put_tty_queue(c, ldata);
|
put_tty_queue(c, ldata);
|
||||||
if (waitqueue_active(&tty->read_wait))
|
|
||||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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)
|
static int job_control(struct tty_struct *tty, struct file *file)
|
||||||
{
|
{
|
||||||
struct pid *pgrp;
|
|
||||||
|
|
||||||
/* Job control check -- must be done at start and after
|
/* Job control check -- must be done at start and after
|
||||||
every sleep (POSIX.1 7.1.1.4). */
|
every sleep (POSIX.1 7.1.1.4). */
|
||||||
/* NOTE: not yet done after every sleep pending a thorough
|
/* NOTE: not yet done after every sleep pending a thorough
|
||||||
check of the logic of this change. -- jlc */
|
check of the logic of this change. -- jlc */
|
||||||
/* don't stop on /dev/console */
|
/* don't stop on /dev/console */
|
||||||
if (file->f_op->write == redirected_tty_write ||
|
if (file->f_op->write == redirected_tty_write)
|
||||||
current->signal->tty != tty)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rcu_read_lock();
|
return __tty_check_change(tty, SIGTTIN);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/tty.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;
|
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);
|
module_param(legacy_count, int, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -877,4 +880,4 @@ static int __init pty_init(void)
|
||||||
unix98_pty_init();
|
unix98_pty_init();
|
||||||
return 0;
|
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)
|
if (!page)
|
||||||
return -ENOMEM;
|
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.
|
* 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);
|
mutex_unlock(&port->mutex);
|
||||||
tty_port_tty_set(port, NULL);
|
tty_port_tty_set(port, NULL);
|
||||||
|
|
||||||
wake_up_interruptible(&port->close_wait);
|
|
||||||
complete_all(&info->close_wait);
|
complete_all(&info->close_wait);
|
||||||
atomic_dec(&rp_num_ports_open);
|
atomic_dec(&rp_num_ports_open);
|
||||||
|
|
||||||
|
@ -1511,10 +1502,6 @@ static void rp_hangup(struct tty_struct *tty)
|
||||||
#endif
|
#endif
|
||||||
rp_flush_buffer(tty);
|
rp_flush_buffer(tty);
|
||||||
spin_lock_irqsave(&info->port.lock, flags);
|
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)
|
if (info->port.count)
|
||||||
atomic_dec(&rp_num_ports_open);
|
atomic_dec(&rp_num_ports_open);
|
||||||
clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
|
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];
|
struct m68k_serial *info = &m68k_soft[0];
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
if (info == 0) return;
|
if (info == NULL) return;
|
||||||
if (info->xmit_buf == 0) return;
|
if (info->xmit_buf == NULL) return;
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
left = info->xmit_cnt;
|
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);
|
wake_up_interruptible(&port->open_wait);
|
||||||
}
|
}
|
||||||
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||||
wake_up_interruptible(&port->close_wait);
|
|
||||||
local_irq_restore(flags);
|
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++) {
|
for (i = 0; i < nr_uarts; i++) {
|
||||||
struct uart_8250_port *up = &serial8250_ports[i];
|
struct uart_8250_port *up = &serial8250_ports[i];
|
||||||
|
|
||||||
|
if (up->port.type == PORT_8250_CIR)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (up->port.dev)
|
if (up->port.dev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1027,13 +1030,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||||
if (up->dl_write)
|
if (up->dl_write)
|
||||||
uart->dl_write = up->dl_write;
|
uart->dl_write = up->dl_write;
|
||||||
|
|
||||||
|
if (uart->port.type != PORT_8250_CIR) {
|
||||||
if (serial8250_isa_config != NULL)
|
if (serial8250_isa_config != NULL)
|
||||||
serial8250_isa_config(0, &uart->port,
|
serial8250_isa_config(0, &uart->port,
|
||||||
&uart->capabilities);
|
&uart->capabilities);
|
||||||
|
|
||||||
ret = uart_add_one_port(&serial8250_reg, &uart->port);
|
ret = uart_add_one_port(&serial8250_reg,
|
||||||
|
&uart->port);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = uart->port.line;
|
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);
|
mutex_unlock(&serial_mutex);
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,6 @@ static void __dma_rx_complete(void *param)
|
||||||
struct dma_tx_state state;
|
struct dma_tx_state state;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
|
||||||
dma->rx_size, DMA_FROM_DEVICE);
|
|
||||||
|
|
||||||
dma->rx_running = 0;
|
dma->rx_running = 0;
|
||||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
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->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);
|
dma_async_issue_pending(dma->rxchan);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -63,6 +63,9 @@ struct dw8250_data {
|
||||||
struct clk *pclk;
|
struct clk *pclk;
|
||||||
struct reset_control *rst;
|
struct reset_control *rst;
|
||||||
struct uart_8250_dma dma;
|
struct uart_8250_dma dma;
|
||||||
|
|
||||||
|
unsigned int skip_autocfg:1;
|
||||||
|
unsigned int uart_16550_compatible:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BYT_PRV_CLK 0x800
|
#define BYT_PRV_CLK 0x800
|
||||||
|
@ -244,24 +247,77 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
|
||||||
serial8250_do_set_termios(p, termios, old);
|
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;
|
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;
|
return param == chan->device->dev->parent;
|
||||||
u32 reg = readl(p->membase + DW_UART_UCV);
|
}
|
||||||
|
|
||||||
|
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
|
* If the Component Version Register returns zero, we know that
|
||||||
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
|
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
|
||||||
*/
|
*/
|
||||||
|
reg = readl(p->membase + DW_UART_UCV);
|
||||||
if (!reg)
|
if (!reg)
|
||||||
return;
|
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 >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
|
||||||
|
|
||||||
reg = readl(p->membase + DW_UART_CPR);
|
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->type = PORT_16550A;
|
||||||
p->flags |= UPF_FIXED_TYPE;
|
p->flags |= UPF_FIXED_TYPE;
|
||||||
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
||||||
up->tx_loadsz = p->fifosize;
|
|
||||||
up->capabilities = UART_CAP_FIFO;
|
up->capabilities = UART_CAP_FIFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,131 +336,15 @@ static void dw8250_setup_port(struct uart_8250_port *up)
|
||||||
up->capabilities |= UART_CAP_AFE;
|
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)
|
static int dw8250_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct uart_8250_port uart = {};
|
struct uart_8250_port uart = {};
|
||||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
int irq = platform_get_irq(pdev, 0);
|
int irq = platform_get_irq(pdev, 0);
|
||||||
|
struct uart_port *p = &uart.port;
|
||||||
struct dw8250_data *data;
|
struct dw8250_data *data;
|
||||||
int err;
|
int err;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
if (!regs) {
|
if (!regs) {
|
||||||
dev_err(&pdev->dev, "no registers defined\n");
|
dev_err(&pdev->dev, "no registers defined\n");
|
||||||
|
@ -418,29 +357,70 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_init(&uart.port.lock);
|
spin_lock_init(&p->lock);
|
||||||
uart.port.mapbase = regs->start;
|
p->mapbase = regs->start;
|
||||||
uart.port.irq = irq;
|
p->irq = irq;
|
||||||
uart.port.handle_irq = dw8250_handle_irq;
|
p->handle_irq = dw8250_handle_irq;
|
||||||
uart.port.pm = dw8250_do_pm;
|
p->pm = dw8250_do_pm;
|
||||||
uart.port.type = PORT_8250;
|
p->type = PORT_8250;
|
||||||
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
|
p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
|
||||||
uart.port.dev = &pdev->dev;
|
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,
|
p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
|
||||||
resource_size(regs));
|
if (!p->membase)
|
||||||
if (!uart.port.membase)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
data->dma.fn = dw8250_fallback_dma_filter;
|
||||||
data->usr_reg = DW_UART_USR;
|
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. */
|
/* Always ask for fixed clock rate from a property. */
|
||||||
device_property_read_u32(&pdev->dev, "clock-frequency",
|
device_property_read_u32(p->dev, "clock-frequency", &p->uartclk);
|
||||||
&uart.port.uartclk);
|
|
||||||
|
|
||||||
/* If there is separate baudclk, get the rate from it. */
|
/* If there is separate baudclk, get the rate from it. */
|
||||||
data->clk = devm_clk_get(&pdev->dev, "baudclk");
|
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",
|
dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
|
||||||
err);
|
err);
|
||||||
else
|
else
|
||||||
uart.port.uartclk = clk_get_rate(data->clk);
|
p->uartclk = clk_get_rate(data->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no clock rate is defined, fail. */
|
/* If no clock rate is defined, fail. */
|
||||||
if (!uart.port.uartclk) {
|
if (!p->uartclk) {
|
||||||
dev_err(&pdev->dev, "clock rate not defined\n");
|
dev_err(&pdev->dev, "clock rate not defined\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -484,26 +464,22 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||||
if (!IS_ERR(data->rst))
|
if (!IS_ERR(data->rst))
|
||||||
reset_control_deassert(data->rst);
|
reset_control_deassert(data->rst);
|
||||||
|
|
||||||
data->dma.rx_param = data;
|
dw8250_quirks(p, data);
|
||||||
data->dma.tx_param = data;
|
|
||||||
data->dma.fn = dw8250_dma_filter;
|
|
||||||
|
|
||||||
uart.port.iotype = UPIO_MEM;
|
/* If the Busy Functionality is not implemented, don't handle it */
|
||||||
uart.port.serial_in = dw8250_serial_in;
|
if (data->uart_16550_compatible) {
|
||||||
uart.port.serial_out = dw8250_serial_out;
|
p->serial_out = NULL;
|
||||||
uart.port.private_data = data;
|
p->handle_irq = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (pdev->dev.of_node) {
|
if (!data->skip_autocfg)
|
||||||
err = dw8250_probe_of(&uart.port, data);
|
dw8250_setup_port(p);
|
||||||
if (err)
|
|
||||||
goto err_reset;
|
/* If we have a valid fifosize, try hooking up DMA */
|
||||||
} else if (ACPI_HANDLE(&pdev->dev)) {
|
if (p->fifosize) {
|
||||||
err = dw8250_probe_acpi(&uart, data);
|
data->dma.rxconf.src_maxburst = p->fifosize / 4;
|
||||||
if (err)
|
data->dma.txconf.dst_maxburst = p->fifosize / 4;
|
||||||
goto err_reset;
|
uart.dma = &data->dma;
|
||||||
} else {
|
|
||||||
err = -ENODEV;
|
|
||||||
goto err_reset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data->line = serial8250_register_8250_port(&uart);
|
data->line = serial8250_register_8250_port(&uart);
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/serial_reg.h>
|
#include <linux/serial_reg.h>
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/serial_8250.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(uart8250, early_serial8250_setup);
|
||||||
EARLYCON_DECLARE(uart, 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/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_fdt.h>
|
#include <linux/of_fdt.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/serial_8250.h>
|
#include <linux/serial_8250.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
#include <linux/serial_reg.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 ingenic_uart_data {
|
||||||
struct clk *clk_module;
|
struct clk *clk_module;
|
||||||
struct clk *clk_baud;
|
struct clk *clk_baud;
|
||||||
int line;
|
int line;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id of_match[];
|
||||||
|
|
||||||
#define UART_FCR_UME BIT(4)
|
#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 struct earlycon_device *early_device;
|
||||||
|
|
||||||
static uint8_t __init early_in(struct uart_port *port, int offset)
|
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)
|
static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||||
{
|
{
|
||||||
|
int ier;
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case UART_FCR:
|
case UART_FCR:
|
||||||
/* UART module enable */
|
/* UART module enable */
|
||||||
|
@ -136,9 +152,22 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UART_IER:
|
case UART_IER:
|
||||||
|
/* Enable receive timeout interrupt with the
|
||||||
|
* receive line status interrupt */
|
||||||
value |= (value & 0x4) << 2;
|
value |= (value & 0x4) << 2;
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
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));
|
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)
|
static int ingenic_uart_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct uart_8250_port uart = {};
|
struct uart_8250_port uart = {};
|
||||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
struct ingenic_uart_data *data;
|
struct ingenic_uart_data *data;
|
||||||
|
const struct ingenic_uart_config *cdata;
|
||||||
|
const struct of_device_id *match;
|
||||||
int err, line;
|
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) {
|
if (!regs || !irq) {
|
||||||
dev_err(&pdev->dev, "no registers/irq defined\n");
|
dev_err(&pdev->dev, "no registers/irq defined\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -164,14 +224,18 @@ static int ingenic_uart_probe(struct platform_device *pdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_init(&uart.port.lock);
|
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.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
|
||||||
uart.port.iotype = UPIO_MEM;
|
uart.port.iotype = UPIO_MEM;
|
||||||
uart.port.mapbase = regs->start;
|
uart.port.mapbase = regs->start;
|
||||||
uart.port.regshift = 2;
|
uart.port.regshift = 2;
|
||||||
uart.port.serial_out = ingenic_uart_serial_out;
|
uart.port.serial_out = ingenic_uart_serial_out;
|
||||||
|
uart.port.serial_in = ingenic_uart_serial_in;
|
||||||
uart.port.irq = irq->start;
|
uart.port.irq = irq->start;
|
||||||
uart.port.dev = &pdev->dev;
|
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 */
|
/* Check for a fixed line number */
|
||||||
line = of_alias_get_id(pdev->dev.of_node, "serial");
|
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;
|
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[] = {
|
static const struct of_device_id of_match[] = {
|
||||||
{ .compatible = "ingenic,jz4740-uart" },
|
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
|
||||||
{ .compatible = "ingenic,jz4775-uart" },
|
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
|
||||||
{ .compatible = "ingenic,jz4780-uart" },
|
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
|
||||||
|
{ .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, of_match);
|
MODULE_DEVICE_TABLE(of, of_match);
|
||||||
|
|
|
@ -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->xoff = termios->c_cc[VSTOP];
|
||||||
|
|
||||||
priv->efr = 0;
|
priv->efr = 0;
|
||||||
up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
|
|
||||||
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
|
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
|
||||||
|
|
||||||
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
|
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;
|
struct dma_tx_state state;
|
||||||
int count;
|
int count;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||||
dma->rx_size, DMA_FROM_DEVICE);
|
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;
|
count = dma->rx_size - state.residue;
|
||||||
|
|
||||||
tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||||
p->port.icount.rx += count;
|
|
||||||
|
p->port.icount.rx += ret;
|
||||||
|
p->port.icount.buf_overrun += count - ret;
|
||||||
unlock:
|
unlock:
|
||||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/platform_data/dma-dw.h>
|
#include <linux/platform_data/dma-dw.h>
|
||||||
#include <linux/platform_data/dma-hsu.h>
|
|
||||||
|
|
||||||
#include "8250.h"
|
#include "8250.h"
|
||||||
|
|
||||||
|
@ -1508,167 +1507,6 @@ byt_serial_setup(struct serial_private *priv,
|
||||||
return ret;
|
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
|
static int
|
||||||
pci_omegapci_setup(struct serial_private *priv,
|
pci_omegapci_setup(struct serial_private *priv,
|
||||||
const struct pciserial_board *board,
|
const struct pciserial_board *board,
|
||||||
|
@ -2210,34 +2048,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||||
.subdevice = PCI_ANY_ID,
|
.subdevice = PCI_ANY_ID,
|
||||||
.setup = byt_serial_setup,
|
.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,
|
.vendor = PCI_VENDOR_ID_INTEL,
|
||||||
.device = PCI_DEVICE_ID_INTEL_BSW_UART1,
|
.device = PCI_DEVICE_ID_INTEL_BSW_UART1,
|
||||||
|
@ -3119,8 +2929,6 @@ enum pci_board_num_t {
|
||||||
pbn_ADDIDATA_PCIe_8_3906250,
|
pbn_ADDIDATA_PCIe_8_3906250,
|
||||||
pbn_ce4100_1_115200,
|
pbn_ce4100_1_115200,
|
||||||
pbn_byt,
|
pbn_byt,
|
||||||
pbn_pnw,
|
|
||||||
pbn_tng,
|
|
||||||
pbn_qrk,
|
pbn_qrk,
|
||||||
pbn_omegapci,
|
pbn_omegapci,
|
||||||
pbn_NETMOS9900_2s_115200,
|
pbn_NETMOS9900_2s_115200,
|
||||||
|
@ -3907,16 +3715,6 @@ static struct pciserial_board pci_boards[] = {
|
||||||
.uart_offset = 0x80,
|
.uart_offset = 0x80,
|
||||||
.reg_shift = 2,
|
.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] = {
|
[pbn_qrk] = {
|
||||||
.flags = FL_BASE0,
|
.flags = FL_BASE0,
|
||||||
.num_ports = 1,
|
.num_ports = 1,
|
||||||
|
@ -4005,6 +3803,13 @@ static const struct pci_device_id blacklist[] = {
|
||||||
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
|
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
|
||||||
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
|
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
|
||||||
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
|
{ 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,
|
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
|
||||||
pbn_byt },
|
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
|
* 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);
|
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 */
|
/* Au1x00/RT288x UART hardware has a weird register layout */
|
||||||
static const s8 au_io_in_map[8] = {
|
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;
|
p->serial_out = mem32be_serial_out;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
|
#ifdef CONFIG_SERIAL_8250_RT288X
|
||||||
case UPIO_AU:
|
case UPIO_AU:
|
||||||
p->serial_in = au_serial_in;
|
p->serial_in = au_serial_in;
|
||||||
p->serial_out = au_serial_out;
|
p->serial_out = au_serial_out;
|
||||||
|
@ -1246,6 +1246,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
||||||
inb_p(ICP);
|
inb_p(ICP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uart_console(port))
|
||||||
|
console_lock();
|
||||||
|
|
||||||
/* forget possible initially masked and pending IRQ */
|
/* forget possible initially masked and pending IRQ */
|
||||||
probe_irq_off(probe_irq_on());
|
probe_irq_off(probe_irq_on());
|
||||||
save_mcr = serial_in(up, UART_MCR);
|
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)
|
if (port->flags & UPF_FOURPORT)
|
||||||
outb_p(save_ICP, ICP);
|
outb_p(save_ICP, ICP);
|
||||||
|
|
||||||
|
if (uart_console(port))
|
||||||
|
console_unlock();
|
||||||
|
|
||||||
port->irq = (irq > 0) ? irq : 0;
|
port->irq = (irq > 0) ? irq : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1807,9 +1813,6 @@ int serial8250_do_startup(struct uart_port *port)
|
||||||
unsigned char lsr, iir;
|
unsigned char lsr, iir;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (port->type == PORT_8250_CIR)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (!port->fifosize)
|
if (!port->fifosize)
|
||||||
port->fifosize = uart_config[port->type].fifo_size;
|
port->fifosize = uart_config[port->type].fifo_size;
|
||||||
if (!up->tx_loadsz)
|
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);
|
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
|
void
|
||||||
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
struct ktermios *old)
|
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);
|
cval = serial8250_compute_lcr(up, termios->c_cflag);
|
||||||
|
|
||||||
/*
|
baud = serial8250_get_baud_rate(port, termios, old);
|
||||||
* Ask the core to calculate the divisor for us.
|
|
||||||
*/
|
|
||||||
baud = uart_get_baud_rate(port, termios, old,
|
|
||||||
port->uartclk / 16 / 0xffff,
|
|
||||||
port->uartclk / 16);
|
|
||||||
quot = serial8250_get_divisor(up, baud, &frac);
|
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)
|
static int serial8250_request_port(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up = up_to_u8250p(port);
|
struct uart_8250_port *up = up_to_u8250p(port);
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (port->type == PORT_8250_CIR)
|
return serial8250_request_std_resource(up);
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
ret = serial8250_request_std_resource(up);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fcr_get_rxtrig_bytes(struct uart_8250_port *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);
|
struct uart_8250_port *up = up_to_u8250p(port);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (port->type == PORT_8250_CIR)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the region that we can probe for. This in turn
|
* Find the region that we can probe for. This in turn
|
||||||
* tells us whether we can probe for the type of port.
|
* 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);
|
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
|
* Print a string to the serial port trying not to disturb
|
||||||
* any possible real use of the port...
|
* 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 */
|
/* check scratch reg to see if port powered off during system sleep */
|
||||||
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
|
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
|
||||||
struct ktermios termios;
|
serial8250_console_restore(up);
|
||||||
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);
|
|
||||||
|
|
||||||
up->canary = 0;
|
up->canary = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,8 +274,8 @@ config SERIAL_8250_ACORN
|
||||||
|
|
||||||
config SERIAL_8250_FSL
|
config SERIAL_8250_FSL
|
||||||
bool
|
bool
|
||||||
depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550
|
depends on SERIAL_8250_CONSOLE
|
||||||
default PPC
|
default PPC || ARM || ARM64
|
||||||
|
|
||||||
config SERIAL_8250_DW
|
config SERIAL_8250_DW
|
||||||
tristate "Support for Synopsys DesignWare 8250 quirks"
|
tristate "Support for Synopsys DesignWare 8250 quirks"
|
||||||
|
@ -294,11 +294,12 @@ config SERIAL_8250_EM
|
||||||
|
|
||||||
config SERIAL_8250_RT288X
|
config SERIAL_8250_RT288X
|
||||||
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
|
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
|
help
|
||||||
If you have a Ralink RT288x/RT305x SoC based board and want to use the
|
Selecting this option will add support for the alternate register
|
||||||
serial port, say Y to this option. The driver can handle up to 2 serial
|
layout used by Ralink RT288x/RT305x, Alchemy Au1xxx, and some others.
|
||||||
ports. If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config SERIAL_8250_OMAP
|
config SERIAL_8250_OMAP
|
||||||
tristate "Support for OMAP internal UART (8250 based driver)"
|
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.
|
through the PNP driver. If unsure, say N.
|
||||||
|
|
||||||
config SERIAL_8250_LPC18XX
|
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)
|
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
|
||||||
default ARCH_LPC18XX
|
default ARCH_LPC18XX
|
||||||
help
|
help
|
||||||
|
@ -366,3 +367,13 @@ config SERIAL_8250_INGENIC
|
||||||
help
|
help
|
||||||
If you have a system using an Ingenic SoC and wish to make use of
|
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.
|
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_MT6577) += 8250_mtk.o
|
||||||
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
|
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
|
||||||
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.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
|
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
|
||||||
|
|
|
@ -115,9 +115,9 @@ config SERIAL_SB1250_DUART_CONSOLE
|
||||||
|
|
||||||
config SERIAL_ATMEL
|
config SERIAL_ATMEL
|
||||||
bool "AT91 / AT32 on-chip serial port support"
|
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_CORE
|
||||||
select SERIAL_MCTRL_GPIO
|
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||||
help
|
help
|
||||||
This enables the driver for the on-chip UARTs of the Atmel
|
This enables the driver for the on-chip UARTs of the Atmel
|
||||||
AT91 and AT32 processors.
|
AT91 and AT32 processors.
|
||||||
|
@ -571,7 +571,7 @@ config BFIN_UART3_CTSRTS
|
||||||
|
|
||||||
config SERIAL_IMX
|
config SERIAL_IMX
|
||||||
tristate "IMX serial port support"
|
tristate "IMX serial port support"
|
||||||
depends on ARCH_MXC
|
depends on ARCH_MXC || COMPILE_TEST
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
select RATIONAL
|
select RATIONAL
|
||||||
help
|
help
|
||||||
|
@ -582,6 +582,7 @@ config SERIAL_IMX_CONSOLE
|
||||||
bool "Console on IMX serial port"
|
bool "Console on IMX serial port"
|
||||||
depends on SERIAL_IMX=y
|
depends on SERIAL_IMX=y
|
||||||
select SERIAL_CORE_CONSOLE
|
select SERIAL_CORE_CONSOLE
|
||||||
|
select SERIAL_EARLYCON if OF
|
||||||
help
|
help
|
||||||
If you have enabled the serial port on the Freescale IMX
|
If you have enabled the serial port on the Freescale IMX
|
||||||
CPU you can make it the console by answering Y to this option.
|
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
|
config SERIAL_SH_SCI_DMA
|
||||||
bool "DMA support"
|
bool "DMA support"
|
||||||
depends on SERIAL_SH_SCI && SH_DMAE
|
depends on SERIAL_SH_SCI && DMA_ENGINE
|
||||||
|
|
||||||
config SERIAL_PNX8XXX
|
config SERIAL_PNX8XXX
|
||||||
bool "Enable PNX8XXX SoCs' UART Support"
|
bool "Enable PNX8XXX SoCs' UART Support"
|
||||||
|
@ -1408,7 +1409,7 @@ config SERIAL_PCH_UART_CONSOLE
|
||||||
warnings and which allows logins in single user mode).
|
warnings and which allows logins in single user mode).
|
||||||
|
|
||||||
config SERIAL_MXS_AUART
|
config SERIAL_MXS_AUART
|
||||||
depends on ARCH_MXS
|
depends on ARCH_MXS || COMPILE_TEST
|
||||||
tristate "MXS AUART support"
|
tristate "MXS AUART support"
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||||
|
@ -1538,6 +1539,7 @@ config SERIAL_FSL_LPUART
|
||||||
tristate "Freescale lpuart serial port support"
|
tristate "Freescale lpuart serial port support"
|
||||||
depends on HAS_DMA
|
depends on HAS_DMA
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
|
select SERIAL_EARLYCON
|
||||||
help
|
help
|
||||||
Support for the on-chip lpuart on some Freescale SOCs.
|
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,
|
.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)
|
static int altera_uart_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev);
|
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)
|
if (platp)
|
||||||
port->uartclk = platp->uartclk;
|
port->uartclk = platp->uartclk;
|
||||||
else {
|
else {
|
||||||
ret = altera_uart_get_of_uartclk(pdev, port);
|
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||||
|
&port->uartclk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,8 +191,8 @@ struct uart_amba_port {
|
||||||
*/
|
*/
|
||||||
static int pl011_fifo_to_tty(struct uart_amba_port *uap)
|
static int pl011_fifo_to_tty(struct uart_amba_port *uap)
|
||||||
{
|
{
|
||||||
u16 status, ch;
|
u16 status;
|
||||||
unsigned int flag, max_count = 256;
|
unsigned int ch, flag, max_count = 256;
|
||||||
int fifotaken = 0;
|
int fifotaken = 0;
|
||||||
|
|
||||||
while (max_count--) {
|
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 = {
|
static struct platform_driver grlib_apbuart_of_driver = {
|
||||||
.probe = apbuart_probe,
|
.probe = apbuart_probe,
|
||||||
|
|
|
@ -111,6 +111,12 @@ struct atmel_uart_char {
|
||||||
|
|
||||||
#define ATMEL_SERIAL_RINGSIZE 1024
|
#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.
|
* 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,
|
sg_set_page(&atmel_port->sg_tx,
|
||||||
virt_to_page(port->state->xmit.buf),
|
virt_to_page(port->state->xmit.buf),
|
||||||
UART_XMIT_SIZE,
|
UART_XMIT_SIZE,
|
||||||
(int)port->state->xmit.buf & ~PAGE_MASK);
|
(unsigned long)port->state->xmit.buf & ~PAGE_MASK);
|
||||||
nent = dma_map_sg(port->dev,
|
nent = dma_map_sg(port->dev,
|
||||||
&atmel_port->sg_tx,
|
&atmel_port->sg_tx,
|
||||||
1,
|
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");
|
dev_dbg(port->dev, "need to release resource of dma\n");
|
||||||
goto chan_err;
|
goto chan_err;
|
||||||
} else {
|
} 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),
|
sg_dma_len(&atmel_port->sg_tx),
|
||||||
port->state->xmit.buf,
|
port->state->xmit.buf,
|
||||||
sg_dma_address(&atmel_port->sg_tx));
|
&sg_dma_address(&atmel_port->sg_tx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the slave DMA */
|
/* 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,
|
sg_set_page(&atmel_port->sg_rx,
|
||||||
virt_to_page(ring->buf),
|
virt_to_page(ring->buf),
|
||||||
sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
|
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,
|
nent = dma_map_sg(port->dev,
|
||||||
&atmel_port->sg_rx,
|
&atmel_port->sg_rx,
|
||||||
1,
|
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");
|
dev_dbg(port->dev, "need to release resource of dma\n");
|
||||||
goto chan_err;
|
goto chan_err;
|
||||||
} else {
|
} 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),
|
sg_dma_len(&atmel_port->sg_rx),
|
||||||
ring->buf,
|
ring->buf,
|
||||||
sg_dma_address(&atmel_port->sg_rx));
|
&sg_dma_address(&atmel_port->sg_rx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Configure the slave DMA */
|
/* 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);
|
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||||
|
|
||||||
if (np) {
|
if (np) {
|
||||||
|
struct serial_rs485 *rs485conf = &port->rs485;
|
||||||
u32 rs485_delay[2];
|
u32 rs485_delay[2];
|
||||||
/* rs485 properties */
|
/* rs485 properties */
|
||||||
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
||||||
rs485_delay, 2) == 0) {
|
rs485_delay, 2) == 0) {
|
||||||
struct serial_rs485 *rs485conf = &port->rs485;
|
|
||||||
|
|
||||||
rs485conf->delay_rts_before_send = rs485_delay[0];
|
rs485conf->delay_rts_before_send = rs485_delay[0];
|
||||||
rs485conf->delay_rts_after_send = rs485_delay[1];
|
rs485conf->delay_rts_after_send = rs485_delay[1];
|
||||||
rs485conf->flags = 0;
|
rs485conf->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
||||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
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",
|
if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
|
||||||
NULL))
|
NULL))
|
||||||
rs485conf->flags |= SER_RS485_ENABLED;
|
rs485conf->flags |= SER_RS485_ENABLED;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
port->rs485 = pdata->rs485;
|
port->rs485 = pdata->rs485;
|
||||||
}
|
}
|
||||||
|
@ -2296,7 +2301,7 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (port->uartclk / 16 != ser->baud_base)
|
if (port->uartclk / 16 != ser->baud_base)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if ((void *)port->mapbase != ser->iomem_base)
|
if (port->mapbase != (unsigned long)ser->iomem_base)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (port->iobase != ser->port)
|
if (port->iobase != ser->port)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -2686,7 +2691,7 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
|
||||||
enum mctrl_gpio_idx i;
|
enum mctrl_gpio_idx i;
|
||||||
struct gpio_desc *gpiod;
|
struct gpio_desc *gpiod;
|
||||||
|
|
||||||
p->gpios = mctrl_gpio_init(dev, 0);
|
p->gpios = mctrl_gpio_init_noauto(dev, 0);
|
||||||
if (IS_ERR(p->gpios))
|
if (IS_ERR(p->gpios))
|
||||||
return PTR_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);
|
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))
|
if (IS_ERR(s->gpios))
|
||||||
return PTR_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 = {
|
static struct platform_driver cpm_uart_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
|
|
|
@ -3655,7 +3655,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||||
wake_up_interruptible(&info->port.open_wait);
|
wake_up_interruptible(&info->port.open_wait);
|
||||||
}
|
}
|
||||||
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||||
wake_up_interruptible(&info->port.close_wait);
|
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
|
|
||||||
/* port closed */
|
/* port closed */
|
||||||
|
@ -3758,23 +3757,6 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||||
int retval;
|
int retval;
|
||||||
int do_clocal = 0;
|
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,
|
* If non-blocking mode is set, or the port is not enabled,
|
||||||
* then make the check up front and then exit.
|
* then make the check up front and then exit.
|
||||||
|
@ -3825,7 +3807,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)
|
if (do_clocal)
|
||||||
/* && (do_clocal || DCD_IS_ASSERTED) */
|
/* && (do_clocal || DCD_IS_ASSERTED) */
|
||||||
break;
|
break;
|
||||||
if (signal_pending(current)) {
|
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);
|
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.
|
* If DMA is enabled try to allocate the irq's.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1746,6 +1746,45 @@ static struct console lpuart32_console = {
|
||||||
.data = &lpuart_reg,
|
.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 LPUART_CONSOLE (&lpuart_console)
|
||||||
#define LPUART32_CONSOLE (&lpuart32_console)
|
#define LPUART32_CONSOLE (&lpuart32_console)
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -139,6 +139,7 @@
|
||||||
#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
|
#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
|
||||||
#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
|
#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
|
||||||
#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma 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_TIMEOUT (1<<7) /* Receive timeout interrupt status */
|
||||||
#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
|
#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
|
||||||
#define USR1_AIRINT (1<<5) /* Async IR wake 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) {
|
if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
|
||||||
sport->dma_is_rxing = 1;
|
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 = readl(sport->port.membase + UCR1);
|
||||||
temp &= ~(UCR1_RRDYEN);
|
temp &= ~(UCR1_RRDYEN);
|
||||||
writel(temp, sport->port.membase + UCR1);
|
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. */
|
/* tell the DMA to receive the data. */
|
||||||
start_rx_dma(sport);
|
start_rx_dma(sport);
|
||||||
}
|
}
|
||||||
|
@ -749,7 +754,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
|
||||||
sts = readl(sport->port.membase + USR1);
|
sts = readl(sport->port.membase + USR1);
|
||||||
sts2 = readl(sport->port.membase + USR2);
|
sts2 = readl(sport->port.membase + USR2);
|
||||||
|
|
||||||
if (sts & USR1_RRDY) {
|
if (sts & (USR1_RRDY | USR1_AGTIM)) {
|
||||||
if (sport->dma_is_enabled)
|
if (sport->dma_is_enabled)
|
||||||
imx_dma_rxint(sport);
|
imx_dma_rxint(sport);
|
||||||
else
|
else
|
||||||
|
@ -852,19 +857,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
|
||||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
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)
|
#define RX_BUF_SIZE (PAGE_SIZE)
|
||||||
static void imx_rx_dma_done(struct imx_port *sport)
|
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);
|
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 = readl(sport->port.membase + UCR1);
|
||||||
temp |= UCR1_RRDYEN;
|
temp |= UCR1_RRDYEN;
|
||||||
writel(temp, sport->port.membase + UCR1);
|
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;
|
sport->dma_is_rxing = 0;
|
||||||
|
|
||||||
/* Is the shutdown waiting for us? */
|
/* 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.
|
* [1] the RX DMA buffer is full.
|
||||||
* [2] the Aging timer expires(wait for 8 bytes long)
|
* [2] the aging timer expires
|
||||||
* [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
|
|
||||||
*
|
*
|
||||||
* The [2] is trigger when a character was been sitting in the FIFO
|
* Condition [2] is triggered when a character has been sitting in the FIFO
|
||||||
* meanwhile [3] can wait for 32 bytes long when the RX line is
|
* for at least 8 byte durations.
|
||||||
* on IDLE state and RxFIFO is empty.
|
|
||||||
*/
|
*/
|
||||||
static void dma_rx_callback(void *data)
|
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);
|
status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
|
||||||
count = RX_BUF_SIZE - state.residue;
|
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);
|
dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
|
@ -931,23 +918,21 @@ static void dma_rx_callback(void *data)
|
||||||
sport->port.icount.buf_overrun++;
|
sport->port.icount.buf_overrun++;
|
||||||
}
|
}
|
||||||
tty_flip_buffer_push(port);
|
tty_flip_buffer_push(port);
|
||||||
|
sport->port.icount.rx += count;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
static int start_rx_dma(struct imx_port *sport)
|
||||||
|
@ -980,6 +965,22 @@ static int start_rx_dma(struct imx_port *sport)
|
||||||
return 0;
|
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)
|
static void imx_uart_dma_exit(struct imx_port *sport)
|
||||||
{
|
{
|
||||||
if (sport->dma_chan_rx) {
|
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.direction = DMA_DEV_TO_MEM;
|
||||||
slave_config.src_addr = sport->port.mapbase + URXD0;
|
slave_config.src_addr = sport->port.mapbase + URXD0;
|
||||||
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
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);
|
ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "error in RX dma configuration.\n");
|
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.direction = DMA_MEM_TO_DEV;
|
||||||
slave_config.dst_addr = sport->port.mapbase + URTX0;
|
slave_config.dst_addr = sport->port.mapbase + URTX0;
|
||||||
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
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);
|
ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "error in TX dma configuration.");
|
dev_err(dev, "error in TX dma configuration.");
|
||||||
|
@ -1062,15 +1064,14 @@ static void imx_enable_dma(struct imx_port *sport)
|
||||||
|
|
||||||
/* set UCR1 */
|
/* set UCR1 */
|
||||||
temp = readl(sport->port.membase + UCR1);
|
temp = readl(sport->port.membase + UCR1);
|
||||||
temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
|
temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
|
||||||
/* wait for 32 idle frames for IDDMA interrupt */
|
|
||||||
UCR1_ICD_REG(3);
|
|
||||||
writel(temp, sport->port.membase + UCR1);
|
writel(temp, sport->port.membase + UCR1);
|
||||||
|
|
||||||
/* set UCR4 */
|
temp = readl(sport->port.membase + UCR2);
|
||||||
temp = readl(sport->port.membase + UCR4);
|
temp |= UCR2_ATEN;
|
||||||
temp |= UCR4_IDDMAEN;
|
writel(temp, sport->port.membase + UCR2);
|
||||||
writel(temp, sport->port.membase + UCR4);
|
|
||||||
|
imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA);
|
||||||
|
|
||||||
sport->dma_is_enabled = 1;
|
sport->dma_is_enabled = 1;
|
||||||
}
|
}
|
||||||
|
@ -1086,13 +1087,10 @@ static void imx_disable_dma(struct imx_port *sport)
|
||||||
|
|
||||||
/* clear UCR2 */
|
/* clear UCR2 */
|
||||||
temp = readl(sport->port.membase + 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);
|
writel(temp, sport->port.membase + UCR2);
|
||||||
|
|
||||||
/* clear UCR4 */
|
imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
||||||
temp = readl(sport->port.membase + UCR4);
|
|
||||||
temp &= ~UCR4_IDDMAEN;
|
|
||||||
writel(temp, sport->port.membase + UCR4);
|
|
||||||
|
|
||||||
sport->dma_is_enabled = 0;
|
sport->dma_is_enabled = 0;
|
||||||
}
|
}
|
||||||
|
@ -1115,7 +1113,7 @@ static int imx_startup(struct uart_port *port)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
imx_setup_ufcr(sport, 0);
|
imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
||||||
|
|
||||||
/* disable the DREN bit (Data Ready interrupt enable) before
|
/* disable the DREN bit (Data Ready interrupt enable) before
|
||||||
* requesting IRQs
|
* requesting IRQs
|
||||||
|
@ -1128,6 +1126,11 @@ static int imx_startup(struct uart_port *port)
|
||||||
|
|
||||||
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
|
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);
|
spin_lock_irqsave(&sport->port.lock, flags);
|
||||||
/* Reset fifo's and state machines */
|
/* Reset fifo's and state machines */
|
||||||
i = 100;
|
i = 100;
|
||||||
|
@ -1145,6 +1148,9 @@ static int imx_startup(struct uart_port *port)
|
||||||
writel(USR1_RTSD, sport->port.membase + USR1);
|
writel(USR1_RTSD, sport->port.membase + USR1);
|
||||||
writel(USR2_ORE, sport->port.membase + USR2);
|
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 = readl(sport->port.membase + UCR1);
|
||||||
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
|
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;
|
struct imx_port *sport = (struct imx_port *)port;
|
||||||
unsigned long flags;
|
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 old_csize = old ? old->c_cflag & CSIZE : CS8;
|
||||||
unsigned int div, ufcr;
|
unsigned int div, ufcr;
|
||||||
unsigned long num, denom;
|
unsigned long num, denom;
|
||||||
|
@ -1315,11 +1321,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
} else {
|
} else {
|
||||||
ucr2 |= UCR2_CTSC;
|
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 {
|
} else {
|
||||||
termios->c_cflag &= ~CRTSCTS;
|
termios->c_cflag &= ~CRTSCTS;
|
||||||
}
|
}
|
||||||
|
@ -1387,10 +1388,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
barrier();
|
barrier();
|
||||||
|
|
||||||
/* then, disable everything */
|
/* then, disable everything */
|
||||||
old_txrxen = readl(sport->port.membase + UCR2);
|
old_ucr2 = readl(sport->port.membase + UCR2);
|
||||||
writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN),
|
writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN),
|
||||||
sport->port.membase + UCR2);
|
sport->port.membase + UCR2);
|
||||||
old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
|
old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
|
||||||
|
|
||||||
/* custom-baudrate handling */
|
/* custom-baudrate handling */
|
||||||
div = sport->port.uartclk / (baud * 16);
|
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);
|
writel(old_ucr1, sport->port.membase + UCR1);
|
||||||
|
|
||||||
/* set the parity, stop bits and data size */
|
/* 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))
|
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
|
||||||
imx_enable_ms(&sport->port);
|
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);
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1503,7 +1502,7 @@ static int imx_poll_init(struct uart_port *port)
|
||||||
if (retval)
|
if (retval)
|
||||||
clk_disable_unprepare(sport->clk_ipg);
|
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);
|
spin_lock_irqsave(&sport->port.lock, flags);
|
||||||
|
|
||||||
|
@ -1773,7 +1772,7 @@ imx_console_setup(struct console *co, char *options)
|
||||||
else
|
else
|
||||||
imx_console_get_options(sport, &baud, &parity, &bits);
|
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);
|
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
|
#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
|
#else
|
||||||
#define IMX_CONSOLE NULL
|
#define IMX_CONSOLE NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -691,12 +691,13 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev)
|
||||||
p->port.mapbase = res->start;
|
p->port.mapbase = res->start;
|
||||||
p->port.membase = NULL;
|
p->port.membase = NULL;
|
||||||
|
|
||||||
p->port.irq = platform_get_irq(pdev, 0);
|
ret = platform_get_irq(pdev, 0);
|
||||||
if (p->port.irq < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
|
dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
|
||||||
uarts_registered);
|
uarts_registered);
|
||||||
return p->port.irq;
|
return ret;
|
||||||
}
|
}
|
||||||
|
p->port.irq = ret;
|
||||||
|
|
||||||
p->port.iotype = UPIO_MEM32;
|
p->port.iotype = UPIO_MEM32;
|
||||||
p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
|
p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
|
||||||
|
|
|
@ -35,8 +35,6 @@
|
||||||
#define MEN_Z135_BAUD_REG 0x810
|
#define MEN_Z135_BAUD_REG 0x810
|
||||||
#define MEN_Z135_TIMEOUT 0x814
|
#define MEN_Z135_TIMEOUT 0x814
|
||||||
|
|
||||||
#define MEN_Z135_MEM_SIZE 0x818
|
|
||||||
|
|
||||||
#define IRQ_ID(x) ((x) & 0x1f)
|
#define IRQ_ID(x) ((x) & 0x1f)
|
||||||
|
|
||||||
#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
|
#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 men_z135_port {
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
struct mcb_device *mdev;
|
struct mcb_device *mdev;
|
||||||
|
struct resource *mem;
|
||||||
unsigned char *rxbuf;
|
unsigned char *rxbuf;
|
||||||
u32 stat_reg;
|
u32 stat_reg;
|
||||||
spinlock_t lock;
|
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)
|
static void men_z135_release_port(struct uart_port *port)
|
||||||
{
|
{
|
||||||
|
struct men_z135_port *uart = to_men_z135(port);
|
||||||
|
|
||||||
iounmap(port->membase);
|
iounmap(port->membase);
|
||||||
port->membase = NULL;
|
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)
|
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"))
|
mem = mcb_request_mem(uart->mdev, dev_name(&mdev->dev));
|
||||||
return -EBUSY;
|
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) {
|
if (port->membase == NULL) {
|
||||||
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
|
mcb_release_mem(mem);
|
||||||
return -ENOMEM;
|
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_RX);
|
||||||
psc_ops->command(port, MPC52xx_PSC_RST_TX);
|
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->set_sicr(port, 0); /* UART mode DCD ignored */
|
||||||
|
|
||||||
psc_ops->fifo_init(port);
|
psc_ops->fifo_init(port);
|
||||||
|
|
|
@ -55,8 +55,6 @@
|
||||||
#define SUPPORT_SYSRQ
|
#define SUPPORT_SYSRQ
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/moduleparam.h>
|
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/tty_flip.h>
|
#include <linux/tty_flip.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
|
@ -755,7 +753,7 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
|
||||||
pi->port.line);
|
pi->port.line);
|
||||||
|
|
||||||
if (!pi->dma_region) {
|
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");
|
printk(KERN_ERR "MPSC: Inadequate DMA support\n");
|
||||||
rc = -ENXIO;
|
rc = -ENXIO;
|
||||||
} else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
|
} 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;
|
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 = {
|
static struct platform_driver mpsc_driver = {
|
||||||
.probe = mpsc_drv_probe,
|
.probe = mpsc_drv_probe,
|
||||||
.remove = mpsc_drv_remove,
|
|
||||||
.driver = {
|
.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;
|
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_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
|
||||||
MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
|
MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
|
||||||
MODULE_VERSION(MPSC_VERSION);
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
|
*/
|
||||||
MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/hrtimer.h>
|
#include <linux/hrtimer.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -31,6 +33,7 @@
|
||||||
#include <linux/tty_flip.h>
|
#include <linux/tty_flip.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
@ -39,6 +42,11 @@
|
||||||
|
|
||||||
#include "msm_serial.h"
|
#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 {
|
enum {
|
||||||
UARTDM_1P1 = 1,
|
UARTDM_1P1 = 1,
|
||||||
UARTDM_1P2,
|
UARTDM_1P2,
|
||||||
|
@ -46,6 +54,17 @@ enum {
|
||||||
UARTDM_1P4,
|
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 msm_port {
|
||||||
struct uart_port uart;
|
struct uart_port uart;
|
||||||
char name[16];
|
char name[16];
|
||||||
|
@ -55,9 +74,153 @@ struct msm_port {
|
||||||
int is_uartdm;
|
int is_uartdm;
|
||||||
unsigned int old_snap_state;
|
unsigned int old_snap_state;
|
||||||
bool break_detected;
|
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)) {
|
while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
|
||||||
if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
|
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)
|
static void msm_start_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct msm_port *msm_port = UART_TO_MSM(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_port->imr |= UART_IMR_TXLEV;
|
||||||
msm_write(port, msm_port->imr, UART_IMR);
|
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)
|
static void msm_stop_rx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct msm_port *msm_port = UART_TO_MSM(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_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
|
||||||
msm_write(port, msm_port->imr, UART_IMR);
|
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)
|
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);
|
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;
|
struct tty_port *tport = &port->state->port;
|
||||||
unsigned int sr;
|
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, UART_CR_CMD_RESET_STALE_INT, UART_CR);
|
||||||
msm_write(port, 0xFFFFFF, UARTDM_DMRX);
|
msm_write(port, 0xFFFFFF, UARTDM_DMRX);
|
||||||
msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
|
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;
|
struct tty_port *tport = &port->state->port;
|
||||||
unsigned int sr;
|
unsigned int sr;
|
||||||
|
@ -224,18 +650,11 @@ static void handle_rx(struct uart_port *port)
|
||||||
spin_lock(&port->lock);
|
spin_lock(&port->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset_dm_count(struct uart_port *port, int count)
|
static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_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)
|
|
||||||
{
|
{
|
||||||
struct circ_buf *xmit = &port->state->xmit;
|
struct circ_buf *xmit = &port->state->xmit;
|
||||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||||
unsigned int tx_count, num_chars;
|
unsigned int num_chars;
|
||||||
unsigned int tf_pointer = 0;
|
unsigned int tf_pointer = 0;
|
||||||
void __iomem *tf;
|
void __iomem *tf;
|
||||||
|
|
||||||
|
@ -244,20 +663,8 @@ static void handle_tx(struct uart_port *port)
|
||||||
else
|
else
|
||||||
tf = port->membase + UART_TF;
|
tf = port->membase + UART_TF;
|
||||||
|
|
||||||
tx_count = uart_circ_chars_pending(xmit);
|
if (tx_count && msm_port->is_uartdm)
|
||||||
tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail,
|
msm_reset_dm_count(port, tx_count);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (tf_pointer < tx_count) {
|
while (tf_pointer < tx_count) {
|
||||||
int i;
|
int i;
|
||||||
|
@ -290,20 +697,76 @@ static void handle_tx(struct uart_port *port)
|
||||||
uart_write_wakeup(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);
|
msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
|
||||||
port->icount.cts++;
|
port->icount.cts++;
|
||||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
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 uart_port *port = dev_id;
|
||||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||||
|
struct msm_dma *dma = &msm_port->rx_dma;
|
||||||
|
unsigned long flags;
|
||||||
unsigned int misr;
|
unsigned int misr;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
spin_lock(&port->lock);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
misr = msm_read(port, UART_MISR);
|
misr = msm_read(port, UART_MISR);
|
||||||
msm_write(port, 0, UART_IMR); /* disable interrupt */
|
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 (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
|
||||||
if (msm_port->is_uartdm)
|
if (dma->count) {
|
||||||
handle_rx_dm(port, misr);
|
val = UART_CR_CMD_STALE_EVENT_DISABLE;
|
||||||
else
|
msm_write(port, val, UART_CR);
|
||||||
handle_rx(port);
|
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)
|
if (misr & UART_IMR_TXLEV)
|
||||||
handle_tx(port);
|
msm_handle_tx(port);
|
||||||
if (misr & UART_IMR_DELTA_CTS)
|
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 */
|
msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
|
||||||
spin_unlock(&port->lock);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -408,6 +882,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud)
|
||||||
{ 3, 0xdd, 8 },
|
{ 3, 0xdd, 8 },
|
||||||
{ 2, 0xee, 16 },
|
{ 2, 0xee, 16 },
|
||||||
{ 1, 0xff, 31 },
|
{ 1, 0xff, 31 },
|
||||||
|
{ 0, 0xff, 31 },
|
||||||
};
|
};
|
||||||
|
|
||||||
divisor = uart_get_divisor(port, baud);
|
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 */
|
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);
|
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||||
const struct msm_baud_map *entry;
|
const struct msm_baud_map *entry;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
entry = msm_find_best_baud(port, baud);
|
entry = msm_find_best_baud(port, baud);
|
||||||
|
|
||||||
msm_write(port, entry->code, UART_CSR);
|
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 */
|
/* RX stale watermark */
|
||||||
rxstale = entry->rxstale;
|
rxstale = entry->rxstale;
|
||||||
watermark = UART_IPR_STALE_LSB & rxstale;
|
watermark = UART_IPR_STALE_LSB & rxstale;
|
||||||
|
if (msm_port->is_uartdm) {
|
||||||
|
mask = UART_DM_IPR_STALE_TIMEOUT_MSB;
|
||||||
|
} else {
|
||||||
watermark |= UART_IPR_RXSTALE_LAST;
|
watermark |= UART_IPR_RXSTALE_LAST;
|
||||||
watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
|
mask = UART_IPR_STALE_TIMEOUT_MSB;
|
||||||
|
}
|
||||||
|
|
||||||
|
watermark |= mask & (rxstale << 2);
|
||||||
|
|
||||||
msm_write(port, watermark, UART_IPR);
|
msm_write(port, watermark, UART_IPR);
|
||||||
|
|
||||||
/* set RX watermark */
|
/* set RX watermark */
|
||||||
|
@ -476,13 +971,13 @@ static void msm_init_clock(struct uart_port *port)
|
||||||
static int msm_startup(struct uart_port *port)
|
static int msm_startup(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||||
unsigned int data, rfr_level;
|
unsigned int data, rfr_level, mask;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
snprintf(msm_port->name, sizeof(msm_port->name),
|
snprintf(msm_port->name, sizeof(msm_port->name),
|
||||||
"msm_serial%d", port->line);
|
"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);
|
msm_port->name, port);
|
||||||
if (unlikely(ret))
|
if (unlikely(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -496,11 +991,23 @@ static int msm_startup(struct uart_port *port)
|
||||||
|
|
||||||
/* set automatic RFR level */
|
/* set automatic RFR level */
|
||||||
data = msm_read(port, UART_MR1);
|
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_LEVEL0;
|
||||||
data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
|
data |= mask & (rfr_level << 2);
|
||||||
data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
|
data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
|
||||||
msm_write(port, data, UART_MR1);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,6 +1018,9 @@ static void msm_shutdown(struct uart_port *port)
|
||||||
msm_port->imr = 0;
|
msm_port->imr = 0;
|
||||||
msm_write(port, 0, UART_IMR); /* disable interrupts */
|
msm_write(port, 0, UART_IMR); /* disable interrupts */
|
||||||
|
|
||||||
|
if (msm_port->is_uartdm)
|
||||||
|
msm_release_dma(msm_port);
|
||||||
|
|
||||||
clk_disable_unprepare(msm_port->clk);
|
clk_disable_unprepare(msm_port->clk);
|
||||||
|
|
||||||
free_irq(port->irq, port);
|
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,
|
static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
struct ktermios *old)
|
struct ktermios *old)
|
||||||
{
|
{
|
||||||
|
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||||
|
struct msm_dma *dma = &msm_port->rx_dma;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int baud, mr;
|
unsigned int baud, mr;
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
|
||||||
|
if (dma->chan) /* Terminate if any */
|
||||||
|
msm_stop_dma(port, dma);
|
||||||
|
|
||||||
/* calculate and set baud rate */
|
/* calculate and set baud rate */
|
||||||
baud = uart_get_baud_rate(port, termios, old, 300, 115200);
|
baud = uart_get_baud_rate(port, termios, old, 300, 4000000);
|
||||||
baud = msm_set_baud_rate(port, baud);
|
baud = msm_set_baud_rate(port, baud, &flags);
|
||||||
if (tty_termios_baud_rate(termios))
|
if (tty_termios_baud_rate(termios))
|
||||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
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);
|
uart_update_timeout(port, termios->c_cflag, baud);
|
||||||
|
|
||||||
|
/* Try to use DMA */
|
||||||
|
msm_start_rx_dma(msm_port);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
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);
|
msm_write(port, 0, UART_IMR);
|
||||||
|
|
||||||
if (msm_port->is_uartdm)
|
if (msm_port->is_uartdm)
|
||||||
reset_dm_count(port, 1);
|
msm_reset_dm_count(port, 1);
|
||||||
|
|
||||||
/* Wait until FIFO is empty */
|
/* Wait until FIFO is empty */
|
||||||
while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
|
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)
|
#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;
|
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);
|
spin_lock(&port->lock);
|
||||||
if (is_uartdm)
|
if (is_uartdm)
|
||||||
reset_dm_count(port, count);
|
msm_reset_dm_count(port, count);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < count) {
|
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);
|
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_port = UART_TO_MSM(port);
|
||||||
|
|
||||||
__msm_console_write(port, s, count, msm_port->is_uartdm);
|
__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))
|
if (unlikely(co->index >= UART_NR || co->index < 0))
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
port = get_port_from_line(co->index);
|
port = msm_get_port_from_line(co->index);
|
||||||
|
|
||||||
if (unlikely(!port->membase))
|
if (unlikely(!port->membase))
|
||||||
return -ENXIO;
|
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);
|
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;
|
port->dev = &pdev->dev;
|
||||||
msm_port = UART_TO_MSM(port);
|
msm_port = UART_TO_MSM(port);
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,12 @@
|
||||||
|
|
||||||
#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
|
#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
|
||||||
#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
|
#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
|
||||||
#define UART_MR1_RX_RDY_CTL (1 << 7)
|
#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
|
||||||
#define UART_MR1_CTS_CTL (1 << 6)
|
#define UART_MR1_RX_RDY_CTL BIT(7)
|
||||||
|
#define UART_MR1_CTS_CTL BIT(6)
|
||||||
|
|
||||||
#define UART_MR2 0x0004
|
#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 0x30
|
||||||
#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
|
#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
|
||||||
#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 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_SET_RFR (13 << 4)
|
||||||
#define UART_CR_CMD_RESET_RFR (14 << 4)
|
#define UART_CR_CMD_RESET_RFR (14 << 4)
|
||||||
#define UART_CR_CMD_PROTECTION_EN (16 << 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_STALE_EVENT_ENABLE (80 << 4)
|
||||||
#define UART_CR_CMD_FORCE_STALE (4 << 8)
|
#define UART_CR_CMD_FORCE_STALE (4 << 8)
|
||||||
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
|
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
|
||||||
#define UART_CR_TX_DISABLE (1 << 3)
|
#define UART_CR_TX_DISABLE BIT(3)
|
||||||
#define UART_CR_TX_ENABLE (1 << 2)
|
#define UART_CR_TX_ENABLE BIT(2)
|
||||||
#define UART_CR_RX_DISABLE (1 << 1)
|
#define UART_CR_RX_DISABLE BIT(1)
|
||||||
#define UART_CR_RX_ENABLE (1 << 0)
|
#define UART_CR_RX_ENABLE BIT(0)
|
||||||
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
|
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
|
||||||
|
|
||||||
#define UART_IMR 0x0014
|
#define UART_IMR 0x0014
|
||||||
#define UART_IMR_TXLEV (1 << 0)
|
#define UART_IMR_TXLEV BIT(0)
|
||||||
#define UART_IMR_RXSTALE (1 << 3)
|
#define UART_IMR_RXSTALE BIT(3)
|
||||||
#define UART_IMR_RXLEV (1 << 4)
|
#define UART_IMR_RXLEV BIT(4)
|
||||||
#define UART_IMR_DELTA_CTS (1 << 5)
|
#define UART_IMR_DELTA_CTS BIT(5)
|
||||||
#define UART_IMR_CURRENT_CTS (1 << 6)
|
#define UART_IMR_CURRENT_CTS BIT(6)
|
||||||
#define UART_IMR_RXBREAK_START (1 << 10)
|
#define UART_IMR_RXBREAK_START BIT(10)
|
||||||
|
|
||||||
#define UART_IPR_RXSTALE_LAST 0x20
|
#define UART_IPR_RXSTALE_LAST 0x20
|
||||||
#define UART_IPR_STALE_LSB 0x1F
|
#define UART_IPR_STALE_LSB 0x1F
|
||||||
#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
|
#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
|
||||||
|
#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
|
||||||
|
|
||||||
#define UART_IPR 0x0018
|
#define UART_IPR 0x0018
|
||||||
#define UART_TFWR 0x001C
|
#define UART_TFWR 0x001C
|
||||||
|
@ -96,20 +99,20 @@
|
||||||
#define UART_TEST_CTRL 0x0050
|
#define UART_TEST_CTRL 0x0050
|
||||||
|
|
||||||
#define UART_SR 0x0008
|
#define UART_SR 0x0008
|
||||||
#define UART_SR_HUNT_CHAR (1 << 7)
|
#define UART_SR_HUNT_CHAR BIT(7)
|
||||||
#define UART_SR_RX_BREAK (1 << 6)
|
#define UART_SR_RX_BREAK BIT(6)
|
||||||
#define UART_SR_PAR_FRAME_ERR (1 << 5)
|
#define UART_SR_PAR_FRAME_ERR BIT(5)
|
||||||
#define UART_SR_OVERRUN (1 << 4)
|
#define UART_SR_OVERRUN BIT(4)
|
||||||
#define UART_SR_TX_EMPTY (1 << 3)
|
#define UART_SR_TX_EMPTY BIT(3)
|
||||||
#define UART_SR_TX_READY (1 << 2)
|
#define UART_SR_TX_READY BIT(2)
|
||||||
#define UART_SR_RX_FULL (1 << 1)
|
#define UART_SR_RX_FULL BIT(1)
|
||||||
#define UART_SR_RX_READY (1 << 0)
|
#define UART_SR_RX_READY BIT(0)
|
||||||
|
|
||||||
#define UART_RF 0x000C
|
#define UART_RF 0x000C
|
||||||
#define UARTDM_RF 0x0070
|
#define UARTDM_RF 0x0070
|
||||||
#define UART_MISR 0x0010
|
#define UART_MISR 0x0010
|
||||||
#define UART_ISR 0x0014
|
#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 0x50
|
||||||
#define UARTDM_RXFS_BUF_SHIFT 0x7
|
#define UARTDM_RXFS_BUF_SHIFT 0x7
|
||||||
|
@ -119,6 +122,12 @@
|
||||||
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
|
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
|
||||||
#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
|
#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_DMRX 0x34
|
||||||
#define UARTDM_NCF_TX 0x40
|
#define UARTDM_NCF_TX 0x40
|
||||||
#define UARTDM_RX_TOTAL_SNAP 0x38
|
#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;
|
enum mctrl_gpio_idx i;
|
||||||
struct gpio_desc *gpiod;
|
struct gpio_desc *gpiod;
|
||||||
|
|
||||||
s->gpios = mctrl_gpio_init(dev, 0);
|
s->gpios = mctrl_gpio_init_noauto(dev, 0);
|
||||||
if (IS_ERR(s->gpios))
|
if (IS_ERR(s->gpios))
|
||||||
return PTR_ERR(s->gpios);
|
return PTR_ERR(s->gpios);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
#include <linux/nwpserial.h>
|
#include <linux/nwpserial.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_8250_MODULE
|
||||||
|
#define CONFIG_SERIAL_8250 CONFIG_SERIAL_8250_MODULE
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "8250/8250.h"
|
#include "8250/8250.h"
|
||||||
|
|
||||||
struct of_serial_info {
|
struct of_serial_info {
|
||||||
|
@ -150,6 +154,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||||
break;
|
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;
|
return 0;
|
||||||
out:
|
out:
|
||||||
if (info->clk)
|
if (info->clk)
|
||||||
|
@ -350,6 +359,7 @@ static const struct of_device_id of_platform_serial_table[] = {
|
||||||
#endif
|
#endif
|
||||||
{ /* end of list */ },
|
{ /* end of list */ },
|
||||||
};
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, of_platform_serial_table);
|
||||||
|
|
||||||
static struct platform_driver of_platform_serial_driver = {
|
static struct platform_driver of_platform_serial_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
|
|
|
@ -199,6 +199,7 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
|
||||||
serial_out(up, UART_FCR, 0);
|
serial_out(up, UART_FCR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
|
static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
|
||||||
{
|
{
|
||||||
struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
|
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);
|
pdata->enable_wakeup(up->dev, enable);
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the absolute difference between the desired and actual baud
|
* 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)
|
static void s3c24xx_serial_stop_rx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct s3c24xx_uart_port *ourport = to_ourport(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;
|
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;
|
unsigned int utrstat, ufstat, received;
|
||||||
struct s3c24xx_uart_port *ourport = dev_id;
|
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);
|
enable_rx_pio(ourport);
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_rx_drain_fifo(ourport);
|
s3c24xx_serial_rx_drain_fifo(ourport);
|
||||||
|
|
||||||
if (tty) {
|
if (tty) {
|
||||||
tty_flip_buffer_push(t);
|
tty_flip_buffer_push(t);
|
||||||
|
@ -621,16 +597,12 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
|
||||||
return IRQ_HANDLED;
|
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;
|
struct uart_port *port = &ourport->port;
|
||||||
unsigned int ufcon, ch, flag, ufstat, uerstat;
|
unsigned int ufcon, ch, flag, ufstat, uerstat;
|
||||||
unsigned long flags;
|
|
||||||
int max_count = port->fifosize;
|
int max_count = port->fifosize;
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
|
||||||
|
|
||||||
while (max_count-- > 0) {
|
while (max_count-- > 0) {
|
||||||
ufcon = rd_regl(port, S3C2410_UFCON);
|
ufcon = rd_regl(port, S3C2410_UFCON);
|
||||||
ufstat = rd_regl(port, S3C2410_UFSTAT);
|
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;
|
ufcon |= S3C2410_UFCON_RESETRX;
|
||||||
wr_regl(port, S3C2410_UFCON, ufcon);
|
wr_regl(port, S3C2410_UFCON, ufcon);
|
||||||
rx_enabled(port) = 1;
|
rx_enabled(port) = 1;
|
||||||
spin_unlock_irqrestore(&port->lock,
|
return;
|
||||||
flags);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -676,7 +646,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
|
||||||
dbg("break!\n");
|
dbg("break!\n");
|
||||||
port->icount.brk++;
|
port->icount.brk++;
|
||||||
if (uart_handle_break(port))
|
if (uart_handle_break(port))
|
||||||
goto ignore_char;
|
continue; /* Ignore character */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uerstat & S3C2410_UERSTAT_FRAME)
|
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))
|
if (uart_handle_sysrq_char(port, ch))
|
||||||
goto ignore_char;
|
continue; /* Ignore character */
|
||||||
|
|
||||||
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
|
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
|
||||||
ch, flag);
|
ch, flag);
|
||||||
|
|
||||||
ignore_char:
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
|
||||||
tty_flip_buffer_push(&port->state->port);
|
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;
|
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;
|
struct s3c24xx_uart_port *ourport = dev_id;
|
||||||
|
|
||||||
if (ourport->dma && ourport->dma->rx_chan)
|
if (ourport->dma && ourport->dma->rx_chan)
|
||||||
return s3c24xx_serial_rx_chars_dma(irq, dev_id);
|
return s3c24xx_serial_rx_chars_dma(dev_id);
|
||||||
return s3c24xx_serial_rx_chars_pio(irq, dev_id);
|
return s3c24xx_serial_rx_chars_pio(dev_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *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 =
|
const struct of_device_id *of_id =
|
||||||
of_match_device(sc16is7xx_dt_ids, &spi->dev);
|
of_match_device(sc16is7xx_dt_ids, &spi->dev);
|
||||||
|
|
||||||
|
if (!of_id)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
||||||
} else {
|
} else {
|
||||||
const struct spi_device_id *id_entry = spi_get_device_id(spi);
|
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 =
|
const struct of_device_id *of_id =
|
||||||
of_match_device(sc16is7xx_dt_ids, &i2c->dev);
|
of_match_device(sc16is7xx_dt_ids, &i2c->dev);
|
||||||
|
|
||||||
|
if (!of_id)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
||||||
} else {
|
} else {
|
||||||
devtype = (struct sc16is7xx_devtype *)id->driver_data;
|
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,
|
.id_table = sc16is7xx_i2c_id_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_ALIAS("i2c:sc16is7xx");
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int __init sc16is7xx_init(void)
|
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);
|
tegra_uart_write(tup, mcr, UART_MCR);
|
||||||
tup->mcr_shadow = mcr;
|
tup->mcr_shadow = mcr;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_dtr(struct tegra_uart_port *tup, bool active)
|
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);
|
tegra_uart_write(tup, mcr, UART_MCR);
|
||||||
tup->mcr_shadow = mcr;
|
tup->mcr_shadow = mcr;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
|
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);
|
dtr_enable = !!(mctrl & TIOCM_DTR);
|
||||||
set_dtr(tup, dtr_enable);
|
set_dtr(tup, dtr_enable);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl)
|
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);
|
async_tx_ack(tup->tx_dma_desc);
|
||||||
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
||||||
tup->tx_in_progress = 0;
|
tup->tx_in_progress = 0;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
|
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)
|
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||||
uart_write_wakeup(&tup->uport);
|
uart_write_wakeup(&tup->uport);
|
||||||
tegra_uart_start_next_tx(tup);
|
tegra_uart_start_next_tx(tup);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
|
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)
|
if (!uart_handle_sysrq_char(&tup->uport, ch) && tty)
|
||||||
tty_insert_flip_char(tty, ch, flag);
|
tty_insert_flip_char(tty, ch, flag);
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
|
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);
|
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)
|
static void tegra_uart_rx_dma_complete(void *args)
|
||||||
{
|
{
|
||||||
struct tegra_uart_port *tup = args;
|
struct tegra_uart_port *tup = args;
|
||||||
struct uart_port *u = &tup->uport;
|
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;
|
unsigned long flags;
|
||||||
struct dma_tx_state state;
|
struct dma_tx_state state;
|
||||||
enum dma_status status;
|
enum dma_status status;
|
||||||
|
@ -596,22 +606,11 @@ static void tegra_uart_rx_dma_complete(void *args)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
async_tx_ack(tup->rx_dma_desc);
|
|
||||||
|
|
||||||
/* Deactivate flow control to stop sender */
|
/* Deactivate flow control to stop sender */
|
||||||
if (tup->rts_active)
|
if (tup->rts_active)
|
||||||
set_rts(tup, false);
|
set_rts(tup, false);
|
||||||
|
|
||||||
/* If we are here, DMA is stopped */
|
tegra_uart_rx_buffer_push(tup, 0);
|
||||||
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_start_rx_dma(tup);
|
tegra_uart_start_rx_dma(tup);
|
||||||
|
|
||||||
/* Activate flow control to start transfer */
|
/* Activate flow control to start transfer */
|
||||||
|
@ -622,14 +621,9 @@ static void tegra_uart_rx_dma_complete(void *args)
|
||||||
spin_unlock_irqrestore(&u->lock, flags);
|
spin_unlock_irqrestore(&u->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
|
static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
|
||||||
unsigned long *flags)
|
|
||||||
{
|
{
|
||||||
struct dma_tx_state state;
|
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 */
|
/* Deactivate flow control to stop sender */
|
||||||
if (tup->rts_active)
|
if (tup->rts_active)
|
||||||
|
@ -637,19 +631,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
|
||||||
|
|
||||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||||
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||||
async_tx_ack(tup->rx_dma_desc);
|
tegra_uart_rx_buffer_push(tup, state.residue);
|
||||||
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);
|
|
||||||
}
|
|
||||||
tegra_uart_start_rx_dma(tup);
|
tegra_uart_start_rx_dma(tup);
|
||||||
|
|
||||||
if (tup->rts_active)
|
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 */
|
/* Will start/stop_tx accordingly */
|
||||||
if (msr & UART_MSR_DCTS)
|
if (msr & UART_MSR_DCTS)
|
||||||
uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
|
uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t tegra_uart_isr(int irq, void *data)
|
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);
|
iir = tegra_uart_read(tup, UART_IIR);
|
||||||
if (iir & UART_IIR_NO_INT) {
|
if (iir & UART_IIR_NO_INT) {
|
||||||
if (is_rx_int) {
|
if (is_rx_int) {
|
||||||
tegra_uart_handle_rx_dma(tup, &flags);
|
tegra_uart_handle_rx_dma(tup);
|
||||||
if (tup->rx_in_progress) {
|
if (tup->rx_in_progress) {
|
||||||
ier = tup->ier_shadow;
|
ier = tup->ier_shadow;
|
||||||
ier |= (UART_IER_RLSI | UART_IER_RTOIE |
|
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)
|
static void tegra_uart_stop_rx(struct uart_port *u)
|
||||||
{
|
{
|
||||||
struct tegra_uart_port *tup = to_tegra_uport(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;
|
struct dma_tx_state state;
|
||||||
unsigned long ier;
|
unsigned long ier;
|
||||||
int count;
|
|
||||||
|
|
||||||
if (tup->rts_active)
|
if (tup->rts_active)
|
||||||
set_rts(tup, false);
|
set_rts(tup, false);
|
||||||
|
@ -781,8 +759,6 @@ static void tegra_uart_stop_rx(struct uart_port *u)
|
||||||
if (!tup->rx_in_progress)
|
if (!tup->rx_in_progress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tty = tty_port_tty_get(&tup->uport.state->port);
|
|
||||||
|
|
||||||
tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */
|
tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */
|
||||||
|
|
||||||
ier = tup->ier_shadow;
|
ier = tup->ier_shadow;
|
||||||
|
@ -791,21 +767,9 @@ static void tegra_uart_stop_rx(struct uart_port *u)
|
||||||
tup->ier_shadow = ier;
|
tup->ier_shadow = ier;
|
||||||
tegra_uart_write(tup, ier, UART_IER);
|
tegra_uart_write(tup, ier, UART_IER);
|
||||||
tup->rx_in_progress = 0;
|
tup->rx_in_progress = 0;
|
||||||
if (tup->rx_dma_chan) {
|
|
||||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||||
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||||
async_tx_ack(tup->rx_dma_desc);
|
tegra_uart_rx_buffer_push(tup, state.residue);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_hw_deinit(struct tegra_uart_port *tup)
|
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;
|
tup->tx_bytes = 0;
|
||||||
if (tup->tx_dma_chan)
|
if (tup->tx_dma_chan)
|
||||||
dmaengine_terminate_all(tup->tx_dma_chan);
|
dmaengine_terminate_all(tup->tx_dma_chan);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_uart_shutdown(struct uart_port *u)
|
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);
|
tegra_uart_read(tup, UART_IER);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&u->lock, flags);
|
spin_unlock_irqrestore(&u->lock, flags);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *tegra_uart_type(struct uart_port *u)
|
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);
|
clear_bit(ASYNCB_CLOSING, &port->flags);
|
||||||
spin_unlock_irq(&port->lock);
|
spin_unlock_irq(&port->lock);
|
||||||
wake_up_interruptible(&port->open_wait);
|
wake_up_interruptible(&port->open_wait);
|
||||||
wake_up_interruptible(&port->close_wait);
|
|
||||||
|
|
||||||
mutex_unlock(&port->mutex);
|
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)
|
* @options: ptr for <options> field; NULL if not present (out)
|
||||||
*
|
*
|
||||||
* Decodes earlycon kernel command line parameters of the form
|
* Decodes earlycon kernel command line parameters of the form
|
||||||
* earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
|
* earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||||
* console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
|
* console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||||
*
|
*
|
||||||
* The optional form
|
* The optional form
|
||||||
* earlycon=<name>,0x<addr>,<options>
|
* 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) {
|
} else if (strncmp(p, "mmio32be,", 9) == 0) {
|
||||||
*iotype = UPIO_MEM32BE;
|
*iotype = UPIO_MEM32BE;
|
||||||
p += 9;
|
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) {
|
} else if (strncmp(p, "io,", 3) == 0) {
|
||||||
*iotype = UPIO_PORT;
|
*iotype = UPIO_PORT;
|
||||||
p += 3;
|
p += 3;
|
||||||
|
|
|
@ -12,18 +12,23 @@
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/termios.h>
|
#include <linux/termios.h>
|
||||||
|
#include <linux/serial_core.h>
|
||||||
|
|
||||||
#include "serial_mctrl_gpio.h"
|
#include "serial_mctrl_gpio.h"
|
||||||
|
|
||||||
struct mctrl_gpios {
|
struct mctrl_gpios {
|
||||||
|
struct uart_port *port;
|
||||||
struct gpio_desc *gpio[UART_GPIO_MAX];
|
struct gpio_desc *gpio[UART_GPIO_MAX];
|
||||||
|
int irq[UART_GPIO_MAX];
|
||||||
|
unsigned int mctrl_prev;
|
||||||
|
bool mctrl_on;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
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);
|
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;
|
struct mctrl_gpios *gpios;
|
||||||
enum mctrl_gpio_idx i;
|
enum mctrl_gpio_idx i;
|
||||||
|
@ -110,15 +115,135 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
|
||||||
|
|
||||||
return gpios;
|
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)
|
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||||
{
|
{
|
||||||
enum mctrl_gpio_idx i;
|
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])
|
if (gpios->gpio[i])
|
||||||
devm_gpiod_put(dev, gpios->gpio[i]);
|
devm_gpiod_put(dev, gpios->gpio[i]);
|
||||||
|
}
|
||||||
devm_kfree(dev, gpios);
|
devm_kfree(dev, gpios);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mctrl_gpio_free);
|
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/device.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
|
struct uart_port;
|
||||||
|
|
||||||
enum mctrl_gpio_idx {
|
enum mctrl_gpio_idx {
|
||||||
UART_GPIO_CTS,
|
UART_GPIO_CTS,
|
||||||
UART_GPIO_DSR,
|
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,
|
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||||
enum mctrl_gpio_idx gidx);
|
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.
|
* Request and set direction of modem control lines GPIOs.
|
||||||
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
|
* 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
|
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
||||||
* allocation error.
|
* 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.
|
* 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);
|
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 */
|
#else /* GPIOLIB */
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
|
@ -95,7 +117,13 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
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);
|
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 /* GPIOLIB */
|
||||||
|
|
||||||
#endif
|
#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_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
|
||||||
|
|
||||||
#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF)
|
#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF))
|
||||||
#define SCI_ERROR_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
|
#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
|
||||||
#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE)
|
#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
|
||||||
#define SCI_BREAK_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
|
#define SCI_BREAK_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
|
||||||
|
|
||||||
/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
|
/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
|
||||||
#define SCIF_ER BIT(7) /* Receive Error */
|
#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_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
|
||||||
|
|
||||||
#define SCIF_RDxF_CLEAR ~(SCIF_DR | SCIF_RDF)
|
#define SCIF_RDxF_CLEAR (u32)(~(SCIF_DR | SCIF_RDF))
|
||||||
#define SCIF_ERROR_CLEAR ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER)
|
#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
|
||||||
#define SCIF_TDxE_CLEAR ~(SCIF_TDFE)
|
#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE))
|
||||||
#define SCIF_BREAK_CLEAR ~(SCIF_PER | SCIF_FER | SCIF_BRK)
|
#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
|
||||||
|
|
||||||
/* SCFCR (FIFO Control Register) */
|
/* SCFCR (FIFO Control Register) */
|
||||||
#define SCFCR_MCE BIT(3) /* Modem Control Enable */
|
#define SCFCR_MCE BIT(3) /* Modem Control Enable */
|
||||||
|
@ -119,28 +119,11 @@ enum {
|
||||||
|
|
||||||
#define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask)
|
#define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask)
|
||||||
|
|
||||||
#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
|
#define SCxSR_RDxF_CLEAR(port) \
|
||||||
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
|
(((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
|
||||||
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
|
#define SCxSR_ERROR_CLEAR(port) \
|
||||||
defined(CONFIG_ARCH_SH73A0) || \
|
(to_sci_port(port)->error_clear)
|
||||||
defined(CONFIG_ARCH_R8A7740)
|
#define SCxSR_TDxE_CLEAR(port) \
|
||||||
|
(((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
|
||||||
# define SCxSR_RDxF_CLEAR(port) \
|
#define SCxSR_BREAK_CLEAR(port) \
|
||||||
(serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR)
|
(((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_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
|
|
||||||
|
|
||||||
|
|
|
@ -782,6 +782,7 @@ static const struct of_device_id serial_ids[] = {
|
||||||
{.compatible = "sprd,sc9836-uart",},
|
{.compatible = "sprd,sc9836-uart",},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, serial_ids);
|
||||||
|
|
||||||
static struct platform_driver sprd_platform_driver = {
|
static struct platform_driver sprd_platform_driver = {
|
||||||
.probe = sprd_probe,
|
.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)
|
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)) {
|
asc_port_name(port), port)) {
|
||||||
dev_err(port->dev, "cannot allocate irq.\n");
|
dev_err(port->dev, "cannot allocate irq.\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
|
@ -322,8 +322,7 @@ static int stm32_startup(struct uart_port *port)
|
||||||
u32 val;
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
|
ret = request_irq(port->irq, stm32_interrupt, 0, name, port);
|
||||||
name, port);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
|
@ -3316,8 +3316,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||||
}
|
}
|
||||||
|
|
||||||
dcd = tty_port_carrier_raised(&info->port);
|
dcd = tty_port_carrier_raised(&info->port);
|
||||||
|
if (do_clocal || dcd)
|
||||||
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
|
@ -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",
|
printk("%s(%d):mgsl_open(%s), old ref count = %d\n",
|
||||||
__FILE__,__LINE__,tty->driver->name, info->port.count);
|
__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;
|
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&info->netlock, flags);
|
spin_lock_irqsave(&info->netlock, flags);
|
||||||
|
|
|
@ -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));
|
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);
|
mutex_lock(&info->port.mutex);
|
||||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||||
|
|
||||||
|
@ -3320,8 +3311,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||||
}
|
}
|
||||||
|
|
||||||
cd = tty_port_carrier_raised(port);
|
cd = tty_port_carrier_raised(port);
|
||||||
|
if (do_clocal || cd)
|
||||||
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd ))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
|
|
|
@ -752,15 +752,6 @@ static int open(struct tty_struct *tty, struct file *filp)
|
||||||
printk("%s(%d):%s open(), old ref count = %d\n",
|
printk("%s(%d):%s open(), old ref count = %d\n",
|
||||||
__FILE__,__LINE__,tty->driver->name, info->port.count);
|
__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;
|
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&info->netlock, flags);
|
spin_lock_irqsave(&info->netlock, flags);
|
||||||
|
@ -3341,8 +3332,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||||
}
|
}
|
||||||
|
|
||||||
cd = tty_port_carrier_raised(port);
|
cd = tty_port_carrier_raised(port);
|
||||||
|
if (do_clocal || cd)
|
||||||
if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
|
|
|
@ -1003,6 +1003,10 @@ static const struct kernel_param_ops param_ops_sysrq_reset_seq = {
|
||||||
#define param_check_sysrq_reset_seq(name, p) \
|
#define param_check_sysrq_reset_seq(name, p) \
|
||||||
__param_check(name, p, unsigned short)
|
__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,
|
module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
|
||||||
&sysrq_reset_seq_len, 0644);
|
&sysrq_reset_seq_len, 0644);
|
||||||
|
|
||||||
|
@ -1119,4 +1123,4 @@ static int __init sysrq_init(void)
|
||||||
|
|
||||||
return 0;
|
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.
|
* flush_to_ldisc() sees buffer data.
|
||||||
*/
|
*/
|
||||||
smp_store_release(&buf->tail->commit, buf->tail->used);
|
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);
|
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);
|
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
|
* Locking: ctrl_lock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int tty_check_change(struct tty_struct *tty)
|
int __tty_check_change(struct tty_struct *tty, int sig)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct pid *pgrp;
|
struct pid *pgrp, *tty_pgrp;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (current->signal->tty != tty)
|
if (current->signal->tty != tty)
|
||||||
|
@ -403,33 +403,35 @@ int tty_check_change(struct tty_struct *tty)
|
||||||
pgrp = task_pgrp(current);
|
pgrp = task_pgrp(current);
|
||||||
|
|
||||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||||
|
tty_pgrp = tty->pgrp;
|
||||||
if (!tty->pgrp) {
|
|
||||||
printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
if (pgrp == tty->pgrp)
|
|
||||||
goto out_unlock;
|
|
||||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||||
|
|
||||||
if (is_ignored(SIGTTOU))
|
if (tty_pgrp && pgrp != tty->pgrp) {
|
||||||
goto out_rcuunlock;
|
if (is_ignored(sig)) {
|
||||||
if (is_current_pgrp_orphaned()) {
|
if (sig == SIGTTIN)
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out_rcuunlock;
|
} else if (is_current_pgrp_orphaned())
|
||||||
}
|
ret = -EIO;
|
||||||
kill_pgrp(pgrp, SIGTTOU, 1);
|
else {
|
||||||
rcu_read_unlock();
|
kill_pgrp(pgrp, sig, 1);
|
||||||
set_thread_flag(TIF_SIGPENDING);
|
set_thread_flag(TIF_SIGPENDING);
|
||||||
ret = -ERESTARTSYS;
|
ret = -ERESTARTSYS;
|
||||||
return ret;
|
}
|
||||||
out_unlock:
|
}
|
||||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
|
||||||
out_rcuunlock:
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
if (!tty_pgrp) {
|
||||||
|
pr_warn("%s: tty_check_change: sig=%d, tty->pgrp == NULL!\n",
|
||||||
|
tty_name(tty), sig);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tty_check_change(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
return __tty_check_change(tty, SIGTTOU);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(tty_check_change);
|
EXPORT_SYMBOL(tty_check_change);
|
||||||
|
|
||||||
static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
|
static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
|
||||||
|
@ -1198,10 +1200,8 @@ void tty_write_message(struct tty_struct *tty, char *msg)
|
||||||
if (tty) {
|
if (tty) {
|
||||||
mutex_lock(&tty->atomic_write_lock);
|
mutex_lock(&tty->atomic_write_lock);
|
||||||
tty_lock(tty);
|
tty_lock(tty);
|
||||||
if (tty->ops->write && tty->count > 0) {
|
if (tty->ops->write && tty->count > 0)
|
||||||
tty_unlock(tty);
|
|
||||||
tty->ops->write(tty, msg, strlen(msg));
|
tty->ops->write(tty, msg, strlen(msg));
|
||||||
} else
|
|
||||||
tty_unlock(tty);
|
tty_unlock(tty);
|
||||||
tty_write_unlock(tty);
|
tty_write_unlock(tty);
|
||||||
}
|
}
|
||||||
|
@ -1689,7 +1689,7 @@ static void release_tty(struct tty_struct *tty, int idx)
|
||||||
tty->port->itty = NULL;
|
tty->port->itty = NULL;
|
||||||
if (tty->link)
|
if (tty->link)
|
||||||
tty->link->port->itty = NULL;
|
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->link);
|
||||||
tty_kref_put(tty);
|
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;
|
struct pid *pgrp;
|
||||||
pid_t pgrp_nr;
|
pid_t pgrp_nr;
|
||||||
int retval = tty_check_change(real_tty);
|
int retval = tty_check_change(real_tty);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (retval == -EIO)
|
if (retval == -EIO)
|
||||||
return -ENOTTY;
|
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))
|
if (session_of_pgrp(pgrp) != task_session(current))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
spin_lock_irq(&tty->ctrl_lock);
|
||||||
put_pid(real_tty->pgrp);
|
put_pid(real_tty->pgrp);
|
||||||
real_tty->pgrp = get_pid(pgrp);
|
real_tty->pgrp = get_pid(pgrp);
|
||||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
spin_unlock_irq(&tty->ctrl_lock);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return retval;
|
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)
|
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
|
static int __lockfunc
|
||||||
|
|
|
@ -22,7 +22,6 @@ void tty_port_init(struct tty_port *port)
|
||||||
memset(port, 0, sizeof(*port));
|
memset(port, 0, sizeof(*port));
|
||||||
tty_buffer_init(port);
|
tty_buffer_init(port);
|
||||||
init_waitqueue_head(&port->open_wait);
|
init_waitqueue_head(&port->open_wait);
|
||||||
init_waitqueue_head(&port->close_wait);
|
|
||||||
init_waitqueue_head(&port->delta_msr_wait);
|
init_waitqueue_head(&port->delta_msr_wait);
|
||||||
mutex_init(&port->mutex);
|
mutex_init(&port->mutex);
|
||||||
mutex_init(&port->buf_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)
|
void tty_port_destroy(struct tty_port *port)
|
||||||
{
|
{
|
||||||
cancel_work_sync(&port->buf.work);
|
tty_buffer_cancel_work(port);
|
||||||
tty_buffer_free_all(port);
|
tty_buffer_free_all(port);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tty_port_destroy);
|
EXPORT_SYMBOL(tty_port_destroy);
|
||||||
|
@ -363,16 +362,6 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
DEFINE_WAIT(wait);
|
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
|
/* 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 */
|
the port has just hung up or is in another error state */
|
||||||
if (tty->flags & (1 << TTY_IO_ERROR)) {
|
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
|
* Never ask drivers if CLOCAL is set, this causes troubles
|
||||||
* on some hardware.
|
* on some hardware.
|
||||||
*/
|
*/
|
||||||
if (!(port->flags & ASYNC_CLOSING) &&
|
if (do_clocal || tty_port_carrier_raised(port))
|
||||||
(do_clocal || tty_port_carrier_raised(port)))
|
|
||||||
break;
|
break;
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
retval = -ERESTARTSYS;
|
retval = -ERESTARTSYS;
|
||||||
|
@ -463,10 +451,7 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
|
||||||
schedule_timeout_interruptible(timeout);
|
schedule_timeout_interruptible(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller holds tty lock.
|
/* 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).
|
|
||||||
*/
|
|
||||||
int tty_port_close_start(struct tty_port *port,
|
int tty_port_close_start(struct tty_port *port,
|
||||||
struct tty_struct *tty, struct file *filp)
|
struct tty_struct *tty, struct file *filp)
|
||||||
{
|
{
|
||||||
|
@ -502,7 +487,7 @@ int tty_port_close_start(struct tty_port *port,
|
||||||
if (tty->flow_stopped)
|
if (tty->flow_stopped)
|
||||||
tty_driver_flush_buffer(tty);
|
tty_driver_flush_buffer(tty);
|
||||||
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
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)
|
if (port->drain_delay)
|
||||||
tty_port_drain_delay(port, tty);
|
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);
|
wake_up_interruptible(&port->open_wait);
|
||||||
}
|
}
|
||||||
port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
|
port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
|
||||||
wake_up_interruptible(&port->close_wait);
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(tty_port_close_end);
|
EXPORT_SYMBOL(tty_port_close_end);
|
||||||
|
@ -543,10 +527,6 @@ EXPORT_SYMBOL(tty_port_close_end);
|
||||||
* tty_port_close
|
* tty_port_close
|
||||||
*
|
*
|
||||||
* Caller holds tty lock
|
* 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,
|
void tty_port_close(struct tty_port *port, struct tty_struct *tty,
|
||||||
struct file *filp)
|
struct file *filp)
|
||||||
|
|
|
@ -114,6 +114,7 @@ struct gs_port {
|
||||||
struct gs_buf port_write_buf;
|
struct gs_buf port_write_buf;
|
||||||
wait_queue_head_t drain_wait; /* wait while writes drain */
|
wait_queue_head_t drain_wait; /* wait while writes drain */
|
||||||
bool write_busy;
|
bool write_busy;
|
||||||
|
wait_queue_head_t close_wait;
|
||||||
|
|
||||||
/* REVISIT this state ... */
|
/* REVISIT this state ... */
|
||||||
struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
|
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",
|
pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
|
||||||
port->port_num, tty, file);
|
port->port_num, tty, file);
|
||||||
|
|
||||||
wake_up(&port->port.close_wait);
|
wake_up(&port->close_wait);
|
||||||
exit:
|
exit:
|
||||||
spin_unlock_irq(&port->port_lock);
|
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);
|
tty_port_init(&port->port);
|
||||||
spin_lock_init(&port->port_lock);
|
spin_lock_init(&port->port_lock);
|
||||||
init_waitqueue_head(&port->drain_wait);
|
init_waitqueue_head(&port->drain_wait);
|
||||||
|
init_waitqueue_head(&port->close_wait);
|
||||||
|
|
||||||
tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
|
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);
|
tasklet_kill(&port->push);
|
||||||
/* wait for old opens to finish */
|
/* 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);
|
WARN_ON(port->port_usb != NULL);
|
||||||
tty_port_destroy(&port->port);
|
tty_port_destroy(&port->port);
|
||||||
kfree(port);
|
kfree(port);
|
||||||
|
|
|
@ -35,14 +35,23 @@ struct hsu_dma_chip {
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
struct hsu_dma *hsu;
|
struct hsu_dma *hsu;
|
||||||
struct hsu_dma_platform_data *pdata;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_HSU_DMA)
|
||||||
/* Export to the internal users */
|
/* Export to the internal users */
|
||||||
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr);
|
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr);
|
||||||
|
|
||||||
/* Export to the platform drivers */
|
/* Export to the platform drivers */
|
||||||
int hsu_dma_probe(struct hsu_dma_chip *chip);
|
int hsu_dma_probe(struct hsu_dma_chip *chip);
|
||||||
int hsu_dma_remove(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 */
|
#endif /* _DMA_HSU_H */
|
||||||
|
|
|
@ -152,9 +152,6 @@ struct r3964_info {
|
||||||
unsigned char *rx_buf; /* ring buffer */
|
unsigned char *rx_buf; /* ring buffer */
|
||||||
unsigned char *tx_buf;
|
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_first;
|
||||||
struct r3964_block_header *rx_last;
|
struct r3964_block_header *rx_last;
|
||||||
struct r3964_block_header *tx_first;
|
struct r3964_block_header *tx_first;
|
||||||
|
@ -165,6 +162,7 @@ struct r3964_info {
|
||||||
unsigned char bcc;
|
unsigned char bcc;
|
||||||
unsigned int blocks_in_rx_queue;
|
unsigned int blocks_in_rx_queue;
|
||||||
|
|
||||||
|
struct mutex read_lock; /* serialize r3964_read */
|
||||||
|
|
||||||
struct r3964_client_info *firstClient;
|
struct r3964_client_info *firstClient;
|
||||||
unsigned int state;
|
unsigned int state;
|
||||||
|
|
|
@ -19,12 +19,6 @@
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/platform_data/macb.h>
|
#include <linux/platform_data/macb.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* at91: 6 USARTs and one DBGU port (SAM9260)
|
|
||||||
* avr32: 4
|
|
||||||
*/
|
|
||||||
#define ATMEL_MAX_UART 7
|
|
||||||
|
|
||||||
/* Compact Flash */
|
/* Compact Flash */
|
||||||
struct at91_cf_data {
|
struct at91_cf_data {
|
||||||
int irq_pin; /* I/O IRQ */
|
int irq_pin; /* I/O IRQ */
|
||||||
|
|
|
@ -18,8 +18,4 @@ struct hsu_dma_slave {
|
||||||
int chan_id;
|
int chan_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hsu_dma_platform_data {
|
|
||||||
unsigned short nr_channels;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* _PLATFORM_DATA_DMA_HSU_H */
|
#endif /* _PLATFORM_DATA_DMA_HSU_H */
|
||||||
|
|
|
@ -227,7 +227,6 @@ struct tty_port {
|
||||||
int blocked_open; /* Waiting to open */
|
int blocked_open; /* Waiting to open */
|
||||||
int count; /* Usage count */
|
int count; /* Usage count */
|
||||||
wait_queue_head_t open_wait; /* Open waiters */
|
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 */
|
wait_queue_head_t delta_msr_wait; /* Modem status change */
|
||||||
unsigned long flags; /* TTY flags ASY_*/
|
unsigned long flags; /* TTY flags ASY_*/
|
||||||
unsigned char console:1, /* port is a console */
|
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);
|
const char *routine);
|
||||||
extern const char *tty_name(const struct tty_struct *tty);
|
extern const char *tty_name(const struct tty_struct *tty);
|
||||||
extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
|
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 int tty_check_change(struct tty_struct *tty);
|
||||||
extern void __stop_tty(struct tty_struct *tty);
|
extern void __stop_tty(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_flush(struct tty_struct *tty, struct tty_ldisc *ld);
|
||||||
extern void tty_buffer_init(struct tty_port *port);
|
extern void tty_buffer_init(struct tty_port *port);
|
||||||
extern void tty_buffer_set_lock_subclass(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_baud_rate(struct ktermios *termios);
|
||||||
extern speed_t tty_termios_input_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,
|
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_lock_slave(struct tty_struct *tty);
|
||||||
extern void __lockfunc tty_unlock_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);
|
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
|
#ifdef CONFIG_PROC_FS
|
||||||
extern void proc_tty_register_driver(struct tty_driver *);
|
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
|
* specified, we cannot return before the IrCOMM link is
|
||||||
* ready
|
* ready
|
||||||
*/
|
*/
|
||||||
if (!test_bit(ASYNCB_CLOSING, &port->flags) &&
|
if ((do_clocal || tty_port_carrier_raised(port)) &&
|
||||||
(do_clocal || tty_port_carrier_raised(port)) &&
|
|
||||||
self->state == IRCOMM_TTY_READY)
|
self->state == IRCOMM_TTY_READY)
|
||||||
{
|
{
|
||||||
break;
|
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 */
|
/* Not really used by us, but lets do it anyway */
|
||||||
self->port.low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
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 */
|
/* Check if this is a "normal" ircomm device, or an irlpt device */
|
||||||
if (self->line < 0x10) {
|
if (self->line < 0x10) {
|
||||||
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
|
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
|
||||||
|
|
Loading…
Reference in New Issue