TTY/Serial driver update for 3.15-rc1
Here's the big tty/serial driver update for 3.15-rc1. Nothing major, a number of serial driver updates and a few tty core fixes as well. All have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlM7CWAACgkQMUfUDdst+ylDXACg0vZ+J+5OXbbE3lywVCAebjhB XzkAn1lz7JRIils7IlckAJ2w/m50b174 =M+8c -----END PGP SIGNATURE----- Merge tag 'tty-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver update from Greg KH: "Here's the big tty/serial driver update for 3.15-rc1. Nothing major, a number of serial driver updates and a few tty core fixes as well. All have been in linux-next for a while" * tag 'tty-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (71 commits) tty/serial: omap: empty the RX FIFO at the end of half-duplex TX tty/serial: omap: fix RX interrupt enable/disable in half-duplex TX serial: sh-sci: Neaten dev_<level> uses serial: sh-sci: Replace hardcoded 3 by UART_PM_STATE_OFF serial: sh-sci: Add more register documentation serial: sh-sci: Remove useless casts serial: sh-sci: Replace printk() by pr_*() serial_core: Avoid NULL pointer dereference in uart_close() serial_core: Get a reference for port->tty in uart_remove_one_port() serial: clps711x: Give a chance to perform useful tasks during wait loop serial_core: Grammar s/ports/port's/ serial_core: Spelling s/contro/control/ serial: efm32: properly namespace location property serial: max310x: Add missing #include <linux/uaccess.h> synclink: fix info leak in ioctl serial: 8250: Clean up the locking for -rt serial: 8250_pci: change BayTrail default uartclk serial: 8250_pci: more BayTrail error-free bauds serial: sh-sci: Add missing call to uart_remove_one_port() in failure path serial_core: Unregister console in uart_remove_one_port() ...
This commit is contained in:
commit
cb15955638
|
@ -6,7 +6,7 @@ Required properties:
|
|||
- interrupts : Should contain uart interrupt
|
||||
|
||||
Optional properties:
|
||||
- location : Decides the location of the USART I/O pins.
|
||||
- efm32,location : Decides the location of the USART I/O pins.
|
||||
Allowed range : [0 .. 5]
|
||||
Default: 0
|
||||
|
||||
|
@ -16,5 +16,5 @@ uart@0x4000c400 {
|
|||
compatible = "efm32,uart";
|
||||
reg = <0x4000c400 0x400>;
|
||||
interrupts = <15>;
|
||||
location = <0>;
|
||||
efm32,location = <0>;
|
||||
};
|
||||
|
|
|
@ -4,11 +4,24 @@ Required properties:
|
|||
- compatible : Should be "fsl,<soc>-lpuart"
|
||||
- reg : Address and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- clocks : phandle + clock specifier pairs, one for each entry in clock-names
|
||||
- clock-names : should contain: "ipg" - the uart clock
|
||||
|
||||
Optional properties:
|
||||
- dmas: A list of two dma specifiers, one for each entry in dma-names.
|
||||
- dma-names: should contain "tx" and "rx".
|
||||
|
||||
Note: Optional properties for DMA support. Write them both or both not.
|
||||
|
||||
Example:
|
||||
|
||||
uart0: serial@40027000 {
|
||||
compatible = "fsl,vf610-lpuart";
|
||||
reg = <0x40027000 0x1000>;
|
||||
interrupts = <0 61 0x00>;
|
||||
};
|
||||
compatible = "fsl,vf610-lpuart";
|
||||
reg = <0x40027000 0x1000>;
|
||||
interrupts = <0 61 0x00>;
|
||||
clocks = <&clks VF610_CLK_UART0>;
|
||||
clock-names = "ipg";
|
||||
dmas = <&edma0 0 2>,
|
||||
<&edma0 0 3>;
|
||||
dma-names = "rx","tx";
|
||||
};
|
||||
|
|
36
Documentation/devicetree/bindings/serial/maxim,max310x.txt
Normal file
36
Documentation/devicetree/bindings/serial/maxim,max310x.txt
Normal file
|
@ -0,0 +1,36 @@
|
|||
* Maxim MAX310X advanced Universal Asynchronous Receiver-Transmitter (UART)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
- "maxim,max3107" for Maxim MAX3107,
|
||||
- "maxim,max3108" for Maxim MAX3108,
|
||||
- "maxim,max3109" for Maxim MAX3109,
|
||||
- "maxim,max14830" for Maxim MAX14830.
|
||||
- reg: SPI chip select number.
|
||||
- interrupt-parent: The phandle for the interrupt controller that
|
||||
services interrupts for this IC.
|
||||
- interrupts: Specifies the interrupt source of the parent interrupt
|
||||
controller. The format of the interrupt specifier depends on the
|
||||
parent interrupt controller.
|
||||
- clocks: phandle to the IC source clock.
|
||||
- clock-names: Should be "xtal" if clock is an external crystal or
|
||||
"osc" if an external clock source is used.
|
||||
|
||||
Optional properties:
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be two. The first cell is the GPIO number and
|
||||
the second cell is used to specify the GPIO polarity:
|
||||
0 = active high,
|
||||
1 = active low.
|
||||
|
||||
Example:
|
||||
max14830: max14830@0 {
|
||||
compatible = "maxim,max14830";
|
||||
reg = <0>;
|
||||
clocks = <&clk20m>;
|
||||
clock-names = "osc";
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
|
@ -37,7 +37,7 @@ Example:
|
|||
};
|
||||
|
||||
scifa0: serial@e6c40000 {
|
||||
compatible = "renesas,scifa-r8a7790", "renesas,scifa-generic";
|
||||
compatible = "renesas,scifa-r8a7790", "renesas,scifa";
|
||||
reg = <0 0xe6c40000 0 64>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
|
|
@ -217,8 +217,8 @@
|
|||
interrupts = <17>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 13>;
|
||||
sirf,uart-dma-rx-channel = <21>;
|
||||
sirf,uart-dma-tx-channel = <2>;
|
||||
dmas = <&dmac1 5>, <&dmac0 2>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
uart1: uart@b0060000 {
|
||||
|
@ -228,6 +228,7 @@
|
|||
interrupts = <18>;
|
||||
fifosize = <32>;
|
||||
clocks = <&clks 14>;
|
||||
dma-names = "no-rx", "no-tx";
|
||||
};
|
||||
|
||||
uart2: uart@b0070000 {
|
||||
|
@ -237,8 +238,8 @@
|
|||
interrupts = <19>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 15>;
|
||||
sirf,uart-dma-rx-channel = <6>;
|
||||
sirf,uart-dma-tx-channel = <7>;
|
||||
dmas = <&dmac0 6>, <&dmac0 7>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
usp0: usp@b0080000 {
|
||||
|
@ -248,8 +249,8 @@
|
|||
interrupts = <20>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 28>;
|
||||
sirf,usp-dma-rx-channel = <17>;
|
||||
sirf,usp-dma-tx-channel = <18>;
|
||||
dmas = <&dmac1 1>, <&dmac1 2>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
usp1: usp@b0090000 {
|
||||
|
@ -259,8 +260,8 @@
|
|||
interrupts = <21>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 29>;
|
||||
sirf,usp-dma-rx-channel = <14>;
|
||||
sirf,usp-dma-tx-channel = <15>;
|
||||
dmas = <&dmac0 14>, <&dmac0 15>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
dmac0: dma-controller@b00b0000 {
|
||||
|
|
|
@ -223,8 +223,8 @@
|
|||
interrupts = <17>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 13>;
|
||||
sirf,uart-dma-rx-channel = <21>;
|
||||
sirf,uart-dma-tx-channel = <2>;
|
||||
dmas = <&dmac1 5>, <&dmac0 2>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
uart1: uart@b0060000 {
|
||||
|
@ -243,8 +243,8 @@
|
|||
interrupts = <19>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 15>;
|
||||
sirf,uart-dma-rx-channel = <6>;
|
||||
sirf,uart-dma-tx-channel = <7>;
|
||||
dmas = <&dmac0 6>, <&dmac0 7>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
usp0: usp@b0080000 {
|
||||
|
@ -254,8 +254,8 @@
|
|||
interrupts = <20>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 28>;
|
||||
sirf,usp-dma-rx-channel = <17>;
|
||||
sirf,usp-dma-tx-channel = <18>;
|
||||
dmas = <&dmac1 1>, <&dmac1 2>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
usp1: usp@b0090000 {
|
||||
|
@ -265,8 +265,8 @@
|
|||
interrupts = <21>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 29>;
|
||||
sirf,usp-dma-rx-channel = <14>;
|
||||
sirf,usp-dma-tx-channel = <15>;
|
||||
dmas = <&dmac0 14>, <&dmac0 15>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
usp2: usp@b00a0000 {
|
||||
|
@ -276,8 +276,8 @@
|
|||
interrupts = <22>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 30>;
|
||||
sirf,usp-dma-rx-channel = <10>;
|
||||
sirf,usp-dma-tx-channel = <11>;
|
||||
dmas = <&dmac0 10>, <&dmac0 11>;
|
||||
dma-names = "rx", "tx";
|
||||
};
|
||||
|
||||
dmac0: dma-controller@b00b0000 {
|
||||
|
|
|
@ -128,27 +128,15 @@ static struct platform_device mx31moboard_flash = {
|
|||
.num_resources = 1,
|
||||
};
|
||||
|
||||
static int moboard_uart0_init(struct platform_device *pdev)
|
||||
static void __init moboard_uart0_init(void)
|
||||
{
|
||||
int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
|
||||
if (ret)
|
||||
if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack")) {
|
||||
gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0);
|
||||
gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void moboard_uart0_exit(struct platform_device *pdev)
|
||||
{
|
||||
gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1));
|
||||
}
|
||||
}
|
||||
|
||||
static const struct imxuart_platform_data uart0_pdata __initconst = {
|
||||
.init = moboard_uart0_init,
|
||||
.exit = moboard_uart0_exit,
|
||||
};
|
||||
|
||||
static const struct imxuart_platform_data uart4_pdata __initconst = {
|
||||
|
@ -543,6 +531,7 @@ static void __init mx31moboard_init(void)
|
|||
|
||||
imx31_add_imx2_wdt();
|
||||
|
||||
moboard_uart0_init();
|
||||
imx31_add_imx_uart0(&uart0_pdata);
|
||||
imx31_add_imx_uart4(&uart4_pdata);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
@ -70,6 +71,9 @@ static struct task_struct *hvc_task;
|
|||
/* Picks up late kicks after list walk but before schedule() */
|
||||
static int hvc_kicked;
|
||||
|
||||
/* hvc_init is triggered from hvc_alloc, i.e. only when actually used */
|
||||
static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1);
|
||||
|
||||
static int hvc_init(void);
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
|
@ -851,7 +855,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
|
|||
int i;
|
||||
|
||||
/* We wait until a driver actually comes along */
|
||||
if (!hvc_driver) {
|
||||
if (atomic_inc_not_zero(&hvc_needs_init)) {
|
||||
int err = hvc_init();
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
|
|
@ -176,9 +176,6 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
|
|||
": %d chars not inserted to flip buffer!\n",
|
||||
length - work);
|
||||
|
||||
/*
|
||||
* This may sleep if ->low_latency is set
|
||||
*/
|
||||
if (work)
|
||||
tty_flip_buffer_push(&tty->port);
|
||||
}
|
||||
|
|
|
@ -1900,13 +1900,10 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
|
|||
struct n_tty_data *ldata = tty->disc_data;
|
||||
int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
|
||||
|
||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||
if (ldata->canon_head != ldata->read_tail)
|
||||
return 1;
|
||||
} else if (read_cnt(ldata) >= amt)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
if (ldata->icanon && !L_EXTPROC(tty))
|
||||
return ldata->canon_head != ldata->read_tail;
|
||||
else
|
||||
return read_cnt(ldata) >= amt;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1694,6 +1694,10 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
|
|||
|
||||
static void serial_unlink_irq_chain(struct uart_8250_port *up)
|
||||
{
|
||||
/*
|
||||
* yes, some broken gcc emit "warning: 'i' may be used uninitialized"
|
||||
* but no, we are not going to take a patch that assigns NULL below.
|
||||
*/
|
||||
struct irq_info *i;
|
||||
struct hlist_node *n;
|
||||
struct hlist_head *h;
|
||||
|
@ -2882,14 +2886,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
|
|||
|
||||
touch_nmi_watchdog();
|
||||
|
||||
local_irq_save(flags);
|
||||
if (port->sysrq) {
|
||||
/* serial8250_handle_irq() already took the lock */
|
||||
locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
locked = spin_trylock(&port->lock);
|
||||
} else
|
||||
spin_lock(&port->lock);
|
||||
if (port->sysrq || oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||
else
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
|
@ -2921,8 +2921,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
|
|||
serial8250_modem_status(up);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&port->lock);
|
||||
local_irq_restore(flags);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int __init serial8250_console_setup(struct console *co, char *options)
|
||||
|
|
|
@ -1366,23 +1366,44 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
|
|||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud = tty_termios_baud_rate(termios);
|
||||
unsigned int m = 6912;
|
||||
unsigned int n = 15625;
|
||||
unsigned int m, n;
|
||||
u32 reg;
|
||||
|
||||
/* For baud rates 1M, 2M, 3M and 4M the dividers must be adjusted. */
|
||||
if (baud == 1000000 || baud == 2000000 || baud == 4000000) {
|
||||
/*
|
||||
* For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
|
||||
* dividers must be adjusted.
|
||||
*
|
||||
* uartclk = (m / n) * 100 MHz, where m <= n
|
||||
*/
|
||||
switch (baud) {
|
||||
case 500000:
|
||||
case 1000000:
|
||||
case 2000000:
|
||||
case 4000000:
|
||||
m = 64;
|
||||
n = 100;
|
||||
|
||||
p->uartclk = 64000000;
|
||||
} else if (baud == 3000000) {
|
||||
break;
|
||||
case 3500000:
|
||||
m = 56;
|
||||
n = 100;
|
||||
p->uartclk = 56000000;
|
||||
break;
|
||||
case 1500000:
|
||||
case 3000000:
|
||||
m = 48;
|
||||
n = 100;
|
||||
|
||||
p->uartclk = 48000000;
|
||||
} else {
|
||||
p->uartclk = 44236800;
|
||||
break;
|
||||
case 2500000:
|
||||
m = 40;
|
||||
n = 100;
|
||||
p->uartclk = 40000000;
|
||||
break;
|
||||
default:
|
||||
m = 2304;
|
||||
n = 3125;
|
||||
p->uartclk = 73728000;
|
||||
}
|
||||
|
||||
/* Reset the clock */
|
||||
|
@ -3449,6 +3470,10 @@ static struct pciserial_board pci_boards[] = {
|
|||
.base_baud = 921600,
|
||||
.reg_shift = 2,
|
||||
},
|
||||
/*
|
||||
* Intel BayTrail HSUART reference clock is 44.2368 MHz at power-on,
|
||||
* but is overridden by byt_set_termios.
|
||||
*/
|
||||
[pbn_byt] = {
|
||||
.flags = FL_BASE0,
|
||||
.num_ports = 1,
|
||||
|
|
|
@ -289,7 +289,7 @@ config SERIAL_MAX3100
|
|||
MAX3100 chip support
|
||||
|
||||
config SERIAL_MAX310X
|
||||
bool "MAX310X support"
|
||||
tristate "MAX310X support"
|
||||
depends on SPI_MASTER
|
||||
select SERIAL_CORE
|
||||
select REGMAP_SPI if SPI_MASTER
|
||||
|
@ -708,7 +708,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
|
|||
|
||||
config SERIAL_SH_SCI
|
||||
tristate "SuperH SCI(F) serial port support"
|
||||
depends on HAVE_CLK && (SUPERH || ARM || COMPILE_TEST)
|
||||
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
|
||||
config SERIAL_SH_SCI_NR_UARTS
|
||||
|
|
|
@ -2154,9 +2154,19 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
amba_ports[i] = uap;
|
||||
|
||||
amba_set_drvdata(dev, uap);
|
||||
|
||||
if (!amba_reg.state) {
|
||||
ret = uart_register_driver(&amba_reg);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to register AMBA-PL011 driver\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&amba_reg, &uap->port);
|
||||
if (ret) {
|
||||
amba_ports[i] = NULL;
|
||||
uart_unregister_driver(&amba_reg);
|
||||
pl011_dma_remove(uap);
|
||||
}
|
||||
out:
|
||||
|
@ -2175,6 +2185,7 @@ static int pl011_remove(struct amba_device *dev)
|
|||
amba_ports[i] = NULL;
|
||||
|
||||
pl011_dma_remove(uap);
|
||||
uart_unregister_driver(&amba_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2230,22 +2241,14 @@ static struct amba_driver pl011_driver = {
|
|||
|
||||
static int __init pl011_init(void)
|
||||
{
|
||||
int ret;
|
||||
printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
|
||||
|
||||
ret = uart_register_driver(&amba_reg);
|
||||
if (ret == 0) {
|
||||
ret = amba_driver_register(&pl011_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&amba_reg);
|
||||
}
|
||||
return ret;
|
||||
return amba_driver_register(&pl011_driver);
|
||||
}
|
||||
|
||||
static void __exit pl011_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&pl011_driver);
|
||||
uart_unregister_driver(&amba_reg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -115,9 +115,6 @@ static void atmel_stop_rx(struct uart_port *port);
|
|||
#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
|
||||
#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR)
|
||||
|
||||
static int (*atmel_open_hook)(struct uart_port *);
|
||||
static void (*atmel_close_hook)(struct uart_port *);
|
||||
|
||||
struct atmel_dma_buffer {
|
||||
unsigned char *buf;
|
||||
dma_addr_t dma_addr;
|
||||
|
@ -1555,7 +1552,7 @@ static int atmel_startup(struct uart_port *port)
|
|||
retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
|
||||
tty ? tty->name : "atmel_serial", port);
|
||||
if (retval) {
|
||||
printk("atmel_serial: atmel_startup - Can't get irq\n");
|
||||
dev_err(port->dev, "atmel_startup - Can't get irq\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1575,17 +1572,6 @@ static int atmel_startup(struct uart_port *port)
|
|||
if (retval < 0)
|
||||
atmel_set_ops(port);
|
||||
}
|
||||
/*
|
||||
* If there is a specific "open" function (to register
|
||||
* control line interrupts)
|
||||
*/
|
||||
if (atmel_open_hook) {
|
||||
retval = atmel_open_hook(port);
|
||||
if (retval) {
|
||||
free_irq(port->irq, port);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Save current CSR for comparison in atmel_tasklet_func() */
|
||||
atmel_port->irq_status_prev = UART_GET_CSR(port);
|
||||
|
@ -1684,13 +1670,6 @@ static void atmel_shutdown(struct uart_port *port)
|
|||
* Free the interrupt
|
||||
*/
|
||||
free_irq(port->irq, port);
|
||||
|
||||
/*
|
||||
* If there is a specific "close" function (to unregister
|
||||
* control line interrupts)
|
||||
*/
|
||||
if (atmel_close_hook)
|
||||
atmel_close_hook(port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1738,7 +1717,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
|
|||
clk_disable_unprepare(atmel_port->clk);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
|
||||
dev_err(port->dev, "atmel_serial: unknown pm %d\n", state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1853,13 +1832,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
mode &= ~ATMEL_US_USMODE;
|
||||
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
if ((atmel_port->rs485.delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port,
|
||||
atmel_port->rs485.delay_rts_after_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else {
|
||||
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||
}
|
||||
|
||||
/* set the parity, stop bits and data size */
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_bcm63xx.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define BCM63XX_NR_UARTS 2
|
||||
|
||||
|
@ -588,7 +590,7 @@ static int bcm_uart_request_port(struct uart_port *port)
|
|||
{
|
||||
unsigned int size;
|
||||
|
||||
size = RSET_UART_SIZE;
|
||||
size = UART_REG_SIZE;
|
||||
if (!request_mem_region(port->mapbase, size, "bcm63xx")) {
|
||||
dev_err(port->dev, "Memory region busy\n");
|
||||
return -EBUSY;
|
||||
|
@ -608,7 +610,7 @@ static int bcm_uart_request_port(struct uart_port *port)
|
|||
*/
|
||||
static void bcm_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
release_mem_region(port->mapbase, RSET_UART_SIZE);
|
||||
release_mem_region(port->mapbase, UART_REG_SIZE);
|
||||
iounmap(port->membase);
|
||||
}
|
||||
|
||||
|
@ -805,6 +807,9 @@ static int bcm_uart_probe(struct platform_device *pdev)
|
|||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
pdev->id = of_alias_get_id(pdev->dev.of_node, "uart");
|
||||
|
||||
if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -856,6 +861,12 @@ static int bcm_uart_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm63xx_of_match[] = {
|
||||
{ .compatible = "brcm,bcm6345-uart" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm63xx_of_match);
|
||||
|
||||
/*
|
||||
* platform driver stuff
|
||||
*/
|
||||
|
@ -865,6 +876,7 @@ static struct platform_driver bcm_uart_platform_driver = {
|
|||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "bcm63xx_uart",
|
||||
.of_match_table = bcm63xx_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -368,11 +368,16 @@ static const struct uart_ops uart_clps711x_ops = {
|
|||
static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct clps711x_port *s = dev_get_drvdata(port->dev);
|
||||
u32 sysflg = 0;
|
||||
|
||||
do {
|
||||
/* Wait for FIFO is not full */
|
||||
while (1) {
|
||||
u32 sysflg = 0;
|
||||
|
||||
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
|
||||
} while (sysflg & SYSFLG_UTXFF);
|
||||
if (!(sysflg & SYSFLG_UTXFF))
|
||||
break;
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
writew(ch, port->membase + UARTDR_OFFSET);
|
||||
}
|
||||
|
@ -382,14 +387,18 @@ static void uart_clps711x_console_write(struct console *co, const char *c,
|
|||
{
|
||||
struct uart_port *port = clps711x_uart.state[co->index].uart_port;
|
||||
struct clps711x_port *s = dev_get_drvdata(port->dev);
|
||||
u32 sysflg = 0;
|
||||
|
||||
uart_console_write(port, c, n, uart_clps711x_console_putchar);
|
||||
|
||||
/* Wait for transmitter to become empty */
|
||||
do {
|
||||
while (1) {
|
||||
u32 sysflg = 0;
|
||||
|
||||
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
|
||||
} while (sysflg & SYSFLG_UBUSY);
|
||||
if (!(sysflg & SYSFLG_UBUSY))
|
||||
break;
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
static int uart_clps711x_console_setup(struct console *co, char *options)
|
||||
|
|
|
@ -286,7 +286,6 @@ static struct e100_serial rs_table[] = {
|
|||
#endif
|
||||
|
||||
}, /* ttyS0 */
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
{ .baud = DEF_BAUD,
|
||||
.ioport = (unsigned char *)R_SERIAL1_CTRL,
|
||||
.irq = 1U << 16, /* uses DMA 8 and 9 */
|
||||
|
@ -447,7 +446,6 @@ static struct e100_serial rs_table[] = {
|
|||
.dma_in_enabled = 0
|
||||
#endif
|
||||
} /* ttyS3 */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -1035,7 +1033,6 @@ cflag_to_etrax_baud(unsigned int cflag)
|
|||
static inline void
|
||||
e100_dtr(struct e100_serial *info, int set)
|
||||
{
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
unsigned char mask = e100_modem_pins[info->line].dtr_mask;
|
||||
|
||||
#ifdef SERIAL_DEBUG_IO
|
||||
|
@ -1060,7 +1057,6 @@ e100_dtr(struct e100_serial *info, int set)
|
|||
info->line, *e100_modem_pins[info->line].dtr_shadow,
|
||||
E100_DTR_GET(info));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
|
||||
|
@ -1069,7 +1065,6 @@ e100_dtr(struct e100_serial *info, int set)
|
|||
static inline void
|
||||
e100_rts(struct e100_serial *info, int set)
|
||||
{
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
info->rx_ctrl &= ~E100_RTS_MASK;
|
||||
|
@ -1079,7 +1074,6 @@ e100_rts(struct e100_serial *info, int set)
|
|||
#ifdef SERIAL_DEBUG_IO
|
||||
printk("ser%i rts %i\n", info->line, set);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1087,7 +1081,6 @@ e100_rts(struct e100_serial *info, int set)
|
|||
static inline void
|
||||
e100_ri_out(struct e100_serial *info, int set)
|
||||
{
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
/* RI is active low */
|
||||
{
|
||||
unsigned char mask = e100_modem_pins[info->line].ri_mask;
|
||||
|
@ -1099,12 +1092,10 @@ e100_ri_out(struct e100_serial *info, int set)
|
|||
*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
static inline void
|
||||
e100_cd_out(struct e100_serial *info, int set)
|
||||
{
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
/* CD is active low */
|
||||
{
|
||||
unsigned char mask = e100_modem_pins[info->line].cd_mask;
|
||||
|
@ -1116,27 +1107,22 @@ e100_cd_out(struct e100_serial *info, int set)
|
|||
*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
e100_disable_rx(struct e100_serial *info)
|
||||
{
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
/* disable the receiver */
|
||||
info->ioport[REG_REC_CTRL] =
|
||||
(info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
e100_enable_rx(struct e100_serial *info)
|
||||
{
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
/* enable the receiver */
|
||||
info->ioport[REG_REC_CTRL] =
|
||||
(info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
|
||||
|
@ -1554,24 +1540,6 @@ transmit_chars_dma(struct e100_serial *info)
|
|||
unsigned int c, sentl;
|
||||
struct etrax_dma_descr *descr;
|
||||
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
/* This will output too little if tail is not 0 always since
|
||||
* we don't reloop to send the other part. Anyway this SHOULD be a
|
||||
* no-op - transmit_chars_dma would never really be called during sim
|
||||
* since rs_write does not write into the xmit buffer then.
|
||||
*/
|
||||
if (info->xmit.tail)
|
||||
printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
|
||||
if (info->xmit.head != info->xmit.tail) {
|
||||
SIMCOUT(info->xmit.buf + info->xmit.tail,
|
||||
CIRC_CNT(info->xmit.head,
|
||||
info->xmit.tail,
|
||||
SERIAL_XMIT_SIZE));
|
||||
info->xmit.head = info->xmit.tail; /* move back head */
|
||||
info->tr_running = 0;
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
/* acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
|
||||
*info->oclrintradr =
|
||||
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
|
||||
|
@ -1842,13 +1810,6 @@ static void receive_chars_dma(struct e100_serial *info)
|
|||
struct tty_struct *tty;
|
||||
unsigned char rstat;
|
||||
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
/* No receive in the simulator. Will probably be when the rest of
|
||||
* the serial interface works, and this piece will just be removed.
|
||||
*/
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Acknowledge both dma_descr and dma_eop irq in R_DMA_CHx_CLR_INTR */
|
||||
*info->iclrintradr =
|
||||
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
|
||||
|
@ -1934,12 +1895,6 @@ static int start_recv_dma(struct e100_serial *info)
|
|||
static void
|
||||
start_receive(struct e100_serial *info)
|
||||
{
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
/* No receive in the simulator. Will probably be when the rest of
|
||||
* the serial interface works, and this piece will just be removed.
|
||||
*/
|
||||
return;
|
||||
#endif
|
||||
if (info->uses_dma_in) {
|
||||
/* reset the input dma channel to be sure it works */
|
||||
|
||||
|
@ -1972,17 +1927,6 @@ tr_interrupt(int irq, void *dev_id)
|
|||
int i;
|
||||
int handled = 0;
|
||||
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
/* No receive in the simulator. Will probably be when the rest of
|
||||
* the serial interface works, and this piece will just be removed.
|
||||
*/
|
||||
{
|
||||
const char *s = "What? tr_interrupt in simulator??\n";
|
||||
SIMCOUT(s,strlen(s));
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
#endif
|
||||
|
||||
/* find out the line that caused this irq and get it from rs_table */
|
||||
|
||||
ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */
|
||||
|
@ -2021,17 +1965,6 @@ rec_interrupt(int irq, void *dev_id)
|
|||
int i;
|
||||
int handled = 0;
|
||||
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
/* No receive in the simulator. Will probably be when the rest of
|
||||
* the serial interface works, and this piece will just be removed.
|
||||
*/
|
||||
{
|
||||
const char *s = "What? rec_interrupt in simulator??\n";
|
||||
SIMCOUT(s,strlen(s));
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
#endif
|
||||
|
||||
/* find out the line that caused this irq and get it from rs_table */
|
||||
|
||||
ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */
|
||||
|
@ -2173,10 +2106,6 @@ timed_flush_handler(unsigned long ptr)
|
|||
struct e100_serial *info;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NR_PORTS; i++) {
|
||||
info = rs_table + i;
|
||||
if (info->uses_dma_in)
|
||||
|
@ -2729,25 +2658,6 @@ startup(struct e100_serial * info)
|
|||
printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
/* Bits and pieces collected from below. Better to have them
|
||||
in one ifdef:ed clause than to mix in a lot of ifdefs,
|
||||
right? */
|
||||
if (info->port.tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->xmit.head = info->xmit.tail = 0;
|
||||
info->first_recv_buffer = info->last_recv_buffer = NULL;
|
||||
info->recv_cnt = info->max_recv_cnt = 0;
|
||||
|
||||
for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++)
|
||||
info->rec_descr[i].buf = NULL;
|
||||
|
||||
/* No real action in the simulator, but may set info important
|
||||
to ioctl. */
|
||||
change_speed(info);
|
||||
#else
|
||||
|
||||
/*
|
||||
* Clear the FIFO buffers and disable them
|
||||
* (they will be reenabled in change_speed())
|
||||
|
@ -2837,8 +2747,6 @@ startup(struct e100_serial * info)
|
|||
e100_rts(info, 1);
|
||||
e100_dtr(info, 1);
|
||||
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
@ -2857,7 +2765,6 @@ shutdown(struct e100_serial * info)
|
|||
struct etrax_recv_buffer *buffer;
|
||||
int i;
|
||||
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
/* shut down the transmitter and receiver */
|
||||
DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
|
||||
e100_disable_rx(info);
|
||||
|
@ -2882,8 +2789,6 @@ shutdown(struct e100_serial * info)
|
|||
info->tr_running = 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
return;
|
||||
|
||||
|
@ -2995,17 +2900,12 @@ change_speed(struct e100_serial *info)
|
|||
IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
|
||||
r_alt_ser_baudrate_shadow &= ~mask;
|
||||
r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
info->baud = cflag_to_baud(cflag);
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
info->ioport[REG_BAUD] = cflag_to_etrax_baud(cflag);
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
/* start with default settings and then fill in changes */
|
||||
local_irq_save(flags);
|
||||
/* 8 bit, no/even parity */
|
||||
|
@ -3073,7 +2973,6 @@ change_speed(struct e100_serial *info)
|
|||
|
||||
*((unsigned long *)&info->ioport[REG_XOFF]) = xoff;
|
||||
local_irq_restore(flags);
|
||||
#endif /* !CONFIG_SVINTO_SIM */
|
||||
|
||||
update_char_time(info);
|
||||
|
||||
|
@ -3122,11 +3021,6 @@ static int rs_raw_write(struct tty_struct *tty,
|
|||
count, info->ioport[REG_STATUS]);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SVINTO_SIM
|
||||
/* Really simple. The output is here and now. */
|
||||
SIMCOUT(buf, count);
|
||||
return count;
|
||||
#endif
|
||||
local_save_flags(flags);
|
||||
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
|
||||
DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
|
||||
|
@ -3463,7 +3357,6 @@ static int
|
|||
get_lsr_info(struct e100_serial * info, unsigned int *value)
|
||||
{
|
||||
unsigned int result = TIOCSER_TEMT;
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
unsigned long curr_time = jiffies;
|
||||
unsigned long curr_time_usec = GET_JIFFIES_USEC();
|
||||
unsigned long elapsed_usec =
|
||||
|
@ -3474,7 +3367,6 @@ get_lsr_info(struct e100_serial * info, unsigned int *value)
|
|||
elapsed_usec < 2*info->char_time_usec) {
|
||||
result = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (copy_to_user(value, &result, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
@ -3804,7 +3696,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
|||
e100_disable_serial_data_irq(info);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
e100_disable_rx(info);
|
||||
e100_disable_rx_irq(info);
|
||||
|
||||
|
@ -3816,7 +3707,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
|||
*/
|
||||
rs_wait_until_sent(tty, HZ);
|
||||
}
|
||||
#endif
|
||||
|
||||
shutdown(info);
|
||||
rs_flush_buffer(tty);
|
||||
|
@ -4479,7 +4369,6 @@ static int __init rs_init(void)
|
|||
fast_timer_init();
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
#ifndef CONFIG_ETRAX_KGDB
|
||||
/* Not needed in simulator. May only complicate stuff. */
|
||||
/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
|
||||
|
@ -4489,7 +4378,6 @@ static int __init rs_init(void)
|
|||
panic("%s: Failed to request irq8", __func__);
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -671,7 +671,10 @@ static int efm32_uart_probe_dt(struct platform_device *pdev,
|
|||
if (!np)
|
||||
return 1;
|
||||
|
||||
ret = of_property_read_u32(np, "location", &location);
|
||||
ret = of_property_read_u32(np, "efm32,location", &location);
|
||||
if (ret)
|
||||
/* fall back to old and (wrongly) generic property "location" */
|
||||
ret = of_property_read_u32(np, "location", &location);
|
||||
if (!ret) {
|
||||
if (location > 5) {
|
||||
dev_err(&pdev->dev, "invalid location\n");
|
||||
|
|
|
@ -13,14 +13,19 @@
|
|||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/of_dma.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
/* All registers are 8-bit width */
|
||||
|
@ -112,6 +117,10 @@
|
|||
#define UARTSFIFO_TXOF 0x02
|
||||
#define UARTSFIFO_RXUF 0x01
|
||||
|
||||
#define DMA_MAXBURST 16
|
||||
#define DMA_MAXBURST_MASK (DMA_MAXBURST - 1)
|
||||
#define FSL_UART_RX_DMA_BUFFER_SIZE 64
|
||||
|
||||
#define DRIVER_NAME "fsl-lpuart"
|
||||
#define DEV_NAME "ttyLP"
|
||||
#define UART_NR 6
|
||||
|
@ -121,6 +130,24 @@ struct lpuart_port {
|
|||
struct clk *clk;
|
||||
unsigned int txfifo_size;
|
||||
unsigned int rxfifo_size;
|
||||
|
||||
bool lpuart_dma_use;
|
||||
struct dma_chan *dma_tx_chan;
|
||||
struct dma_chan *dma_rx_chan;
|
||||
struct dma_async_tx_descriptor *dma_tx_desc;
|
||||
struct dma_async_tx_descriptor *dma_rx_desc;
|
||||
dma_addr_t dma_tx_buf_bus;
|
||||
dma_addr_t dma_rx_buf_bus;
|
||||
dma_cookie_t dma_tx_cookie;
|
||||
dma_cookie_t dma_rx_cookie;
|
||||
unsigned char *dma_tx_buf_virt;
|
||||
unsigned char *dma_rx_buf_virt;
|
||||
unsigned int dma_tx_bytes;
|
||||
unsigned int dma_rx_bytes;
|
||||
int dma_tx_in_progress;
|
||||
int dma_rx_in_progress;
|
||||
unsigned int dma_rx_timeout;
|
||||
struct timer_list lpuart_timer;
|
||||
};
|
||||
|
||||
static struct of_device_id lpuart_dt_ids[] = {
|
||||
|
@ -131,6 +158,10 @@ static struct of_device_id lpuart_dt_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
||||
|
||||
/* Forward declare this for the dma callbacks*/
|
||||
static void lpuart_dma_tx_complete(void *arg);
|
||||
static void lpuart_dma_rx_complete(void *arg);
|
||||
|
||||
static void lpuart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned char temp;
|
||||
|
@ -152,6 +183,210 @@ static void lpuart_enable_ms(struct uart_port *port)
|
|||
{
|
||||
}
|
||||
|
||||
static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
|
||||
struct tty_port *tty, int count)
|
||||
{
|
||||
int copied;
|
||||
|
||||
sport->port.icount.rx += count;
|
||||
|
||||
if (!tty) {
|
||||
dev_err(sport->port.dev, "No tty port\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus,
|
||||
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
|
||||
copied = tty_insert_flip_string(tty,
|
||||
((unsigned char *)(sport->dma_rx_buf_virt)), count);
|
||||
|
||||
if (copied != count) {
|
||||
WARN_ON(1);
|
||||
dev_err(sport->port.dev, "RxData copy to tty layer failed\n");
|
||||
}
|
||||
|
||||
dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
|
||||
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void lpuart_pio_tx(struct lpuart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
while (!uart_circ_empty(xmit) &&
|
||||
readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
|
||||
writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
|
||||
sport->port.membase + UARTCR5);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
dma_addr_t tx_bus_addr;
|
||||
|
||||
dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK);
|
||||
tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail;
|
||||
sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan,
|
||||
tx_bus_addr, sport->dma_tx_bytes,
|
||||
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
|
||||
|
||||
if (!sport->dma_tx_desc) {
|
||||
dev_err(sport->port.dev, "Not able to get desc for tx\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sport->dma_tx_desc->callback = lpuart_dma_tx_complete;
|
||||
sport->dma_tx_desc->callback_param = sport;
|
||||
sport->dma_tx_in_progress = 1;
|
||||
sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
|
||||
dma_async_issue_pending(sport->dma_tx_chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpuart_prepare_tx(struct lpuart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
unsigned long count = CIRC_CNT_TO_END(xmit->head,
|
||||
xmit->tail, UART_XMIT_SIZE);
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
if (count < DMA_MAXBURST)
|
||||
writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS,
|
||||
sport->port.membase + UARTCR5);
|
||||
else {
|
||||
writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
|
||||
sport->port.membase + UARTCR5);
|
||||
lpuart_dma_tx(sport, count);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpuart_dma_tx_complete(void *arg)
|
||||
{
|
||||
struct lpuart_port *sport = arg;
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
unsigned long flags;
|
||||
|
||||
async_tx_ack(sport->dma_tx_desc);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
|
||||
sport->dma_tx_in_progress = 0;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
lpuart_prepare_tx(sport);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static int lpuart_dma_rx(struct lpuart_port *sport)
|
||||
{
|
||||
dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
|
||||
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
|
||||
sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan,
|
||||
sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE,
|
||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
|
||||
|
||||
if (!sport->dma_rx_desc) {
|
||||
dev_err(sport->port.dev, "Not able to get desc for rx\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
|
||||
sport->dma_rx_desc->callback_param = sport;
|
||||
sport->dma_rx_in_progress = 1;
|
||||
sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
|
||||
dma_async_issue_pending(sport->dma_rx_chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpuart_dma_rx_complete(void *arg)
|
||||
{
|
||||
struct lpuart_port *sport = arg;
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
unsigned long flags;
|
||||
|
||||
async_tx_ack(sport->dma_rx_desc);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
sport->dma_rx_in_progress = 0;
|
||||
lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
|
||||
tty_flip_buffer_push(port);
|
||||
lpuart_dma_rx(sport);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static void lpuart_timer_func(unsigned long data)
|
||||
{
|
||||
struct lpuart_port *sport = (struct lpuart_port *)data;
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
unsigned long flags;
|
||||
unsigned char temp;
|
||||
int count;
|
||||
|
||||
del_timer(&sport->lpuart_timer);
|
||||
dmaengine_pause(sport->dma_rx_chan);
|
||||
dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
|
||||
dmaengine_terminate_all(sport->dma_rx_chan);
|
||||
count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
|
||||
async_tx_ack(sport->dma_rx_desc);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
sport->dma_rx_in_progress = 0;
|
||||
lpuart_copy_rx_to_tty(sport, port, count);
|
||||
tty_flip_buffer_push(port);
|
||||
temp = readb(sport->port.membase + UARTCR5);
|
||||
writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static inline void lpuart_prepare_rx(struct lpuart_port *sport)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char temp;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
init_timer(&sport->lpuart_timer);
|
||||
sport->lpuart_timer.function = lpuart_timer_func;
|
||||
sport->lpuart_timer.data = (unsigned long)sport;
|
||||
sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
|
||||
add_timer(&sport->lpuart_timer);
|
||||
|
||||
lpuart_dma_rx(sport);
|
||||
temp = readb(sport->port.membase + UARTCR5);
|
||||
writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
|
@ -172,14 +407,21 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
|
|||
|
||||
static void lpuart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
struct lpuart_port, port);
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
unsigned char temp;
|
||||
|
||||
temp = readb(port->membase + UARTCR2);
|
||||
writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
|
||||
|
||||
if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
|
||||
lpuart_transmit_buffer(sport);
|
||||
if (sport->lpuart_dma_use) {
|
||||
if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
|
||||
lpuart_prepare_tx(sport);
|
||||
} else {
|
||||
if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
|
||||
lpuart_transmit_buffer(sport);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t lpuart_txint(int irq, void *dev_id)
|
||||
|
@ -279,12 +521,19 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
|
|||
|
||||
sts = readb(sport->port.membase + UARTSR1);
|
||||
|
||||
if (sts & UARTSR1_RDRF)
|
||||
lpuart_rxint(irq, dev_id);
|
||||
|
||||
if (sts & UARTSR1_RDRF) {
|
||||
if (sport->lpuart_dma_use)
|
||||
lpuart_prepare_rx(sport);
|
||||
else
|
||||
lpuart_rxint(irq, dev_id);
|
||||
}
|
||||
if (sts & UARTSR1_TDRE &&
|
||||
!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS))
|
||||
lpuart_txint(irq, dev_id);
|
||||
!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
|
||||
if (sport->lpuart_dma_use)
|
||||
lpuart_pio_tx(sport);
|
||||
else
|
||||
lpuart_txint(irq, dev_id);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -366,13 +615,156 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
|
|||
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
|
||||
sport->port.membase + UARTCFIFO);
|
||||
|
||||
writeb(2, sport->port.membase + UARTTWFIFO);
|
||||
writeb(0, sport->port.membase + UARTTWFIFO);
|
||||
writeb(1, sport->port.membase + UARTRWFIFO);
|
||||
|
||||
/* Restore cr2 */
|
||||
writeb(cr2_saved, sport->port.membase + UARTCR2);
|
||||
}
|
||||
|
||||
static int lpuart_dma_tx_request(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
struct lpuart_port, port);
|
||||
struct dma_chan *tx_chan;
|
||||
struct dma_slave_config dma_tx_sconfig;
|
||||
dma_addr_t dma_bus;
|
||||
unsigned char *dma_buf;
|
||||
int ret;
|
||||
|
||||
tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
|
||||
|
||||
if (!tx_chan) {
|
||||
dev_err(sport->port.dev, "Dma tx channel request failed!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dma_bus = dma_map_single(tx_chan->device->dev,
|
||||
sport->port.state->xmit.buf,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
|
||||
dev_err(sport->port.dev, "dma_map_single tx failed\n");
|
||||
dma_release_channel(tx_chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_buf = sport->port.state->xmit.buf;
|
||||
dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
|
||||
dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma_tx_sconfig.dst_maxburst = DMA_MAXBURST;
|
||||
dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
|
||||
ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(sport->port.dev,
|
||||
"Dma slave config failed, err = %d\n", ret);
|
||||
dma_release_channel(tx_chan);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sport->dma_tx_chan = tx_chan;
|
||||
sport->dma_tx_buf_virt = dma_buf;
|
||||
sport->dma_tx_buf_bus = dma_bus;
|
||||
sport->dma_tx_in_progress = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpuart_dma_rx_request(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
struct lpuart_port, port);
|
||||
struct dma_chan *rx_chan;
|
||||
struct dma_slave_config dma_rx_sconfig;
|
||||
dma_addr_t dma_bus;
|
||||
unsigned char *dma_buf;
|
||||
int ret;
|
||||
|
||||
rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
|
||||
|
||||
if (!rx_chan) {
|
||||
dev_err(sport->port.dev, "Dma rx channel request failed!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dma_buf = devm_kzalloc(sport->port.dev,
|
||||
FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
|
||||
|
||||
if (!dma_buf) {
|
||||
dev_err(sport->port.dev, "Dma rx alloc failed\n");
|
||||
dma_release_channel(rx_chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
|
||||
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
|
||||
dev_err(sport->port.dev, "dma_map_single rx failed\n");
|
||||
dma_release_channel(rx_chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
|
||||
dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma_rx_sconfig.src_maxburst = 1;
|
||||
dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
|
||||
ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(sport->port.dev,
|
||||
"Dma slave config failed, err = %d\n", ret);
|
||||
dma_release_channel(rx_chan);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sport->dma_rx_chan = rx_chan;
|
||||
sport->dma_rx_buf_virt = dma_buf;
|
||||
sport->dma_rx_buf_bus = dma_bus;
|
||||
sport->dma_rx_in_progress = 0;
|
||||
|
||||
sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
|
||||
FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
|
||||
sport->rxfifo_size / 2;
|
||||
|
||||
if (sport->dma_rx_timeout < msecs_to_jiffies(20))
|
||||
sport->dma_rx_timeout = msecs_to_jiffies(20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpuart_dma_tx_free(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
struct lpuart_port, port);
|
||||
struct dma_chan *dma_chan;
|
||||
|
||||
dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
dma_chan = sport->dma_tx_chan;
|
||||
sport->dma_tx_chan = NULL;
|
||||
sport->dma_tx_buf_bus = 0;
|
||||
sport->dma_tx_buf_virt = NULL;
|
||||
dma_release_channel(dma_chan);
|
||||
}
|
||||
|
||||
static void lpuart_dma_rx_free(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
struct lpuart_port, port);
|
||||
struct dma_chan *dma_chan;
|
||||
|
||||
dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
|
||||
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
dma_chan = sport->dma_rx_chan;
|
||||
sport->dma_rx_chan = NULL;
|
||||
sport->dma_rx_buf_bus = 0;
|
||||
sport->dma_rx_buf_virt = NULL;
|
||||
dma_release_channel(dma_chan);
|
||||
}
|
||||
|
||||
static int lpuart_startup(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
|
@ -380,6 +772,15 @@ static int lpuart_startup(struct uart_port *port)
|
|||
unsigned long flags;
|
||||
unsigned char temp;
|
||||
|
||||
/*whether use dma support by dma request results*/
|
||||
if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) {
|
||||
sport->lpuart_dma_use = false;
|
||||
} else {
|
||||
sport->lpuart_dma_use = true;
|
||||
temp = readb(port->membase + UARTCR5);
|
||||
writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
|
||||
}
|
||||
|
||||
ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
|
||||
DRIVER_NAME, sport);
|
||||
if (ret)
|
||||
|
@ -414,6 +815,11 @@ static void lpuart_shutdown(struct uart_port *port)
|
|||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
devm_free_irq(port->dev, port->irq, sport);
|
||||
|
||||
if (sport->lpuart_dma_use) {
|
||||
lpuart_dma_tx_free(port);
|
||||
lpuart_dma_rx_free(port);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -496,8 +496,7 @@ static void dma_tx_callback(void *data)
|
|||
|
||||
dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (waitqueue_active(&sport->dma_wait)) {
|
||||
wake_up(&sport->dma_wait);
|
||||
|
@ -1117,25 +1116,25 @@ static int imx_startup(struct uart_port *port)
|
|||
*/
|
||||
if (sport->txirq > 0) {
|
||||
retval = request_irq(sport->rxirq, imx_rxint, 0,
|
||||
DRIVER_NAME, sport);
|
||||
dev_name(port->dev), sport);
|
||||
if (retval)
|
||||
goto error_out1;
|
||||
|
||||
retval = request_irq(sport->txirq, imx_txint, 0,
|
||||
DRIVER_NAME, sport);
|
||||
dev_name(port->dev), sport);
|
||||
if (retval)
|
||||
goto error_out2;
|
||||
|
||||
/* do not use RTS IRQ on IrDA */
|
||||
if (!USE_IRDA(sport)) {
|
||||
retval = request_irq(sport->rtsirq, imx_rtsint, 0,
|
||||
DRIVER_NAME, sport);
|
||||
dev_name(port->dev), sport);
|
||||
if (retval)
|
||||
goto error_out3;
|
||||
}
|
||||
} else {
|
||||
retval = request_irq(sport->port.irq, imx_int, 0,
|
||||
DRIVER_NAME, sport);
|
||||
dev_name(port->dev), sport);
|
||||
if (retval) {
|
||||
free_irq(sport->port.irq, sport);
|
||||
goto error_out1;
|
||||
|
@ -1469,36 +1468,6 @@ static const char *imx_type(struct uart_port *port)
|
|||
return sport->port.type == PORT_IMX ? "IMX" : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the memory region(s) being used by 'port'.
|
||||
*/
|
||||
static void imx_release_port(struct uart_port *port)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
struct resource *mmres;
|
||||
|
||||
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(mmres->start, resource_size(mmres));
|
||||
}
|
||||
|
||||
/*
|
||||
* Request the memory region(s) being used by 'port'.
|
||||
*/
|
||||
static int imx_request_port(struct uart_port *port)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
struct resource *mmres;
|
||||
void *ret;
|
||||
|
||||
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mmres)
|
||||
return -ENODEV;
|
||||
|
||||
ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart");
|
||||
|
||||
return ret ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure/autoconfigure the port.
|
||||
*/
|
||||
|
@ -1506,8 +1475,7 @@ static void imx_config_port(struct uart_port *port, int flags)
|
|||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
|
||||
if (flags & UART_CONFIG_TYPE &&
|
||||
imx_request_port(&sport->port) == 0)
|
||||
if (flags & UART_CONFIG_TYPE)
|
||||
sport->port.type = PORT_IMX;
|
||||
}
|
||||
|
||||
|
@ -1617,8 +1585,6 @@ static struct uart_ops imx_pops = {
|
|||
.flush_buffer = imx_flush_buffer,
|
||||
.set_termios = imx_set_termios,
|
||||
.type = imx_type,
|
||||
.release_port = imx_release_port,
|
||||
.request_port = imx_request_port,
|
||||
.config_port = imx_config_port,
|
||||
.verify_port = imx_verify_port,
|
||||
#if defined(CONFIG_CONSOLE_POLL)
|
||||
|
@ -1935,7 +1901,6 @@ static void serial_imx_probe_pdata(struct imx_port *sport,
|
|||
static int serial_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_port *sport;
|
||||
struct imxuart_platform_data *pdata;
|
||||
void __iomem *base;
|
||||
int ret = 0;
|
||||
struct resource *res;
|
||||
|
@ -1951,12 +1916,9 @@ static int serial_imx_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.mapbase = res->start;
|
||||
|
@ -1992,38 +1954,16 @@ static int serial_imx_probe(struct platform_device *pdev)
|
|||
|
||||
imx_ports[sport->port.line] = sport;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
if (pdata && pdata->init) {
|
||||
ret = pdata->init(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&imx_reg, &sport->port);
|
||||
if (ret)
|
||||
goto deinit;
|
||||
platform_set_drvdata(pdev, sport);
|
||||
|
||||
return 0;
|
||||
deinit:
|
||||
if (pdata && pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
return ret;
|
||||
return uart_add_one_port(&imx_reg, &sport->port);
|
||||
}
|
||||
|
||||
static int serial_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imxuart_platform_data *pdata;
|
||||
struct imx_port *sport = platform_get_drvdata(pdev);
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
uart_remove_one_port(&imx_reg, &sport->port);
|
||||
|
||||
if (pdata && pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
|
||||
return 0;
|
||||
return uart_remove_one_port(&imx_reg, &sport->port);
|
||||
}
|
||||
|
||||
static struct platform_driver serial_imx_driver = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
|
||||
*
|
||||
* Copyright (C) 2012-2013 Alexander Shiyan <shc_work@mail.ru>
|
||||
* Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru>
|
||||
*
|
||||
* Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
|
||||
* Based on max3110.c, by Feng Tang <feng.tang@intel.com>
|
||||
|
@ -13,19 +13,21 @@
|
|||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/platform_data/max310x.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define MAX310X_NAME "max310x"
|
||||
#define MAX310X_MAJOR 204
|
||||
|
@ -161,10 +163,6 @@
|
|||
/* IRDA register bits */
|
||||
#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
|
||||
#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
|
||||
#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */
|
||||
#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */
|
||||
#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */
|
||||
#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */
|
||||
|
||||
/* Flow control trigger level register masks */
|
||||
#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */
|
||||
|
@ -220,26 +218,6 @@
|
|||
* XOFF2
|
||||
*/
|
||||
|
||||
/* GPIO configuration register bits */
|
||||
#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */
|
||||
#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */
|
||||
#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */
|
||||
#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */
|
||||
#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */
|
||||
#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */
|
||||
#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */
|
||||
#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */
|
||||
|
||||
/* GPIO DATA register bits */
|
||||
#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */
|
||||
#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */
|
||||
#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */
|
||||
#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */
|
||||
#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */
|
||||
#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */
|
||||
#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */
|
||||
#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */
|
||||
|
||||
/* PLL configuration register masks */
|
||||
#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */
|
||||
#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */
|
||||
|
@ -283,16 +261,15 @@ struct max310x_devtype {
|
|||
struct max310x_one {
|
||||
struct uart_port port;
|
||||
struct work_struct tx_work;
|
||||
struct work_struct md_work;
|
||||
};
|
||||
|
||||
struct max310x_port {
|
||||
struct uart_driver uart;
|
||||
struct max310x_devtype *devtype;
|
||||
struct regmap *regmap;
|
||||
struct regmap_config regcfg;
|
||||
struct mutex mutex;
|
||||
struct max310x_pdata *pdata;
|
||||
int gpio_used;
|
||||
struct clk *clk;
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct gpio_chip gpio;
|
||||
#endif
|
||||
|
@ -504,25 +481,33 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void max310x_set_baud(struct uart_port *port, int baud)
|
||||
static int max310x_set_baud(struct uart_port *port, int baud)
|
||||
{
|
||||
unsigned int mode = 0, div = port->uartclk / baud;
|
||||
unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
|
||||
|
||||
if (!(div / 16)) {
|
||||
/* Check for minimal value for divider */
|
||||
if (div < 16)
|
||||
div = 16;
|
||||
|
||||
if (clk % baud && (div / 16) < 0x8000) {
|
||||
/* Mode x2 */
|
||||
mode = MAX310X_BRGCFG_2XMODE_BIT;
|
||||
div = (port->uartclk * 2) / baud;
|
||||
}
|
||||
clk = port->uartclk * 2;
|
||||
div = clk / baud;
|
||||
|
||||
if (!(div / 16)) {
|
||||
/* Mode x4 */
|
||||
mode = MAX310X_BRGCFG_4XMODE_BIT;
|
||||
div = (port->uartclk * 4) / baud;
|
||||
if (clk % baud && (div / 16) < 0x8000) {
|
||||
/* Mode x4 */
|
||||
mode = MAX310X_BRGCFG_4XMODE_BIT;
|
||||
clk = port->uartclk * 4;
|
||||
div = clk / baud;
|
||||
}
|
||||
}
|
||||
|
||||
max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
|
||||
max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
|
||||
max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
|
||||
|
||||
return DIV_ROUND_CLOSEST(clk, div);
|
||||
}
|
||||
|
||||
static int max310x_update_best_err(unsigned long f, long *besterr)
|
||||
|
@ -538,18 +523,19 @@ static int max310x_update_best_err(unsigned long f, long *besterr)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int max310x_set_ref_clk(struct max310x_port *s)
|
||||
static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq,
|
||||
bool xtal)
|
||||
{
|
||||
unsigned int div, clksrc, pllcfg = 0;
|
||||
long besterr = -1;
|
||||
unsigned long fdiv, fmul, bestfreq = s->pdata->frequency;
|
||||
unsigned long fdiv, fmul, bestfreq = freq;
|
||||
|
||||
/* First, update error without PLL */
|
||||
max310x_update_best_err(s->pdata->frequency, &besterr);
|
||||
max310x_update_best_err(freq, &besterr);
|
||||
|
||||
/* Try all possible PLL dividers */
|
||||
for (div = 1; (div <= 63) && besterr; div++) {
|
||||
fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div);
|
||||
fdiv = DIV_ROUND_CLOSEST(freq, div);
|
||||
|
||||
/* Try multiplier 6 */
|
||||
fmul = fdiv * 6;
|
||||
|
@ -582,10 +568,7 @@ static int max310x_set_ref_clk(struct max310x_port *s)
|
|||
}
|
||||
|
||||
/* Configure clock source */
|
||||
if (s->pdata->driver_flags & MAX310X_EXT_CLK)
|
||||
clksrc = MAX310X_CLKSRC_EXTCLK_BIT;
|
||||
else
|
||||
clksrc = MAX310X_CLKSRC_CRYST_BIT;
|
||||
clksrc = xtal ? MAX310X_CLKSRC_CRYST_BIT : MAX310X_CLKSRC_EXTCLK_BIT;
|
||||
|
||||
/* Configure PLL */
|
||||
if (pllcfg) {
|
||||
|
@ -597,7 +580,7 @@ static int max310x_set_ref_clk(struct max310x_port *s)
|
|||
regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
|
||||
|
||||
/* Wait for crystal */
|
||||
if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK))
|
||||
if (pllcfg && xtal)
|
||||
msleep(10);
|
||||
|
||||
return (int)bestfreq;
|
||||
|
@ -782,11 +765,21 @@ static unsigned int max310x_get_mctrl(struct uart_port *port)
|
|||
return TIOCM_DSR | TIOCM_CAR;
|
||||
}
|
||||
|
||||
static void max310x_md_proc(struct work_struct *ws)
|
||||
{
|
||||
struct max310x_one *one = container_of(ws, struct max310x_one, md_work);
|
||||
|
||||
max310x_port_update(&one->port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_LOOPBACK_BIT,
|
||||
(one->port.mctrl & TIOCM_LOOP) ?
|
||||
MAX310X_MODE2_LOOPBACK_BIT : 0);
|
||||
}
|
||||
|
||||
static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* DCD and DSR are not wired and CTS/RTS is hadnled automatically
|
||||
* so do nothing
|
||||
*/
|
||||
struct max310x_one *one = container_of(port, struct max310x_one, port);
|
||||
|
||||
schedule_work(&one->md_work);
|
||||
}
|
||||
|
||||
static void max310x_break_ctl(struct uart_port *port, int break_state)
|
||||
|
@ -875,40 +868,76 @@ static void max310x_set_termios(struct uart_port *port,
|
|||
port->uartclk / 4);
|
||||
|
||||
/* Setup baudrate generator */
|
||||
max310x_set_baud(port, baud);
|
||||
baud = max310x_set_baud(port, baud);
|
||||
|
||||
/* Update timeout according to new baud rate */
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
}
|
||||
|
||||
static int max310x_ioctl(struct uart_port *port, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
#if defined(TIOCSRS485) && defined(TIOCGRS485)
|
||||
struct serial_rs485 rs485;
|
||||
unsigned int val;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485)))
|
||||
return -EFAULT;
|
||||
if (rs485.delay_rts_before_send > 0x0f ||
|
||||
rs485.delay_rts_after_send > 0x0f)
|
||||
return -ERANGE;
|
||||
val = (rs485.delay_rts_before_send << 4) |
|
||||
rs485.delay_rts_after_send;
|
||||
max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
|
||||
if (rs485.flags & SER_RS485_ENABLED) {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT);
|
||||
} else {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT, 0);
|
||||
}
|
||||
return 0;
|
||||
case TIOCGRS485:
|
||||
memset(&rs485, 0, sizeof(rs485));
|
||||
val = max310x_port_read(port, MAX310X_MODE1_REG);
|
||||
rs485.flags = (val & MAX310X_MODE1_TRNSCVCTRL_BIT) ?
|
||||
SER_RS485_ENABLED : 0;
|
||||
rs485.flags |= SER_RS485_RTS_ON_SEND;
|
||||
val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG);
|
||||
rs485.delay_rts_before_send = val >> 4;
|
||||
rs485.delay_rts_after_send = val & 0x0f;
|
||||
if (copy_to_user((void __user *)arg, &rs485, sizeof(rs485)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static int max310x_startup(struct uart_port *port)
|
||||
{
|
||||
unsigned int val, line = port->line;
|
||||
struct max310x_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned int val;
|
||||
|
||||
s->devtype->power(port, 1);
|
||||
|
||||
/* Configure baud rate, 9600 as default */
|
||||
max310x_set_baud(port, 9600);
|
||||
|
||||
/* Configure LCR register, 8N1 mode by default */
|
||||
max310x_port_write(port, MAX310X_LCR_REG, MAX310X_LCR_WORD_LEN_8);
|
||||
|
||||
/* Configure MODE1 register */
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT,
|
||||
(s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
|
||||
? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
|
||||
|
||||
/* Configure MODE2 register */
|
||||
val = MAX310X_MODE2_RXEMPTINV_BIT;
|
||||
if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK)
|
||||
val |= MAX310X_MODE2_LOOPBACK_BIT;
|
||||
if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS)
|
||||
val |= MAX310X_MODE2_ECHOSUPR_BIT;
|
||||
|
||||
/* Reset FIFOs */
|
||||
val |= MAX310X_MODE2_FIFORST_BIT;
|
||||
/* Configure MODE2 register & Reset FIFOs*/
|
||||
val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT;
|
||||
max310x_port_write(port, MAX310X_MODE2_REG, val);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_FIFORST_BIT, 0);
|
||||
|
@ -989,6 +1018,7 @@ static const struct uart_ops max310x_ops = {
|
|||
.release_port = max310x_null_void,
|
||||
.config_port = max310x_config_port,
|
||||
.verify_port = max310x_verify_port,
|
||||
.ioctl = max310x_ioctl,
|
||||
};
|
||||
|
||||
static int __maybe_unused max310x_suspend(struct device *dev)
|
||||
|
@ -1017,6 +1047,8 @@ static int __maybe_unused max310x_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
|
@ -1063,23 +1095,16 @@ static int max310x_gpio_direction_output(struct gpio_chip *chip,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int max310x_probe(struct device *dev, int is_spi,
|
||||
struct max310x_devtype *devtype, int irq)
|
||||
static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
||||
struct regmap *regmap, int irq, unsigned long flags)
|
||||
{
|
||||
int i, ret, fmin, fmax, freq, uartclk;
|
||||
struct clk *clk_osc, *clk_xtal;
|
||||
struct max310x_port *s;
|
||||
struct max310x_pdata *pdata = dev_get_platdata(dev);
|
||||
int i, ret, uartclk;
|
||||
bool xtal = false;
|
||||
|
||||
/* Check for IRQ */
|
||||
if (irq <= 0) {
|
||||
dev_err(dev, "No IRQ specified\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(dev, "No platform data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
/* Alloc port structure */
|
||||
s = devm_kzalloc(dev, sizeof(*s) +
|
||||
|
@ -1089,52 +1114,44 @@ static int max310x_probe(struct device *dev, int is_spi,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Check input frequency */
|
||||
if ((pdata->driver_flags & MAX310X_EXT_CLK) &&
|
||||
((pdata->frequency < 500000) || (pdata->frequency > 35000000)))
|
||||
goto err_freq;
|
||||
/* Check frequency for quartz */
|
||||
if (!(pdata->driver_flags & MAX310X_EXT_CLK) &&
|
||||
((pdata->frequency < 1000000) || (pdata->frequency > 4000000)))
|
||||
goto err_freq;
|
||||
|
||||
s->pdata = pdata;
|
||||
s->devtype = devtype;
|
||||
dev_set_drvdata(dev, s);
|
||||
|
||||
mutex_init(&s->mutex);
|
||||
|
||||
/* Setup regmap */
|
||||
s->regcfg.reg_bits = 8;
|
||||
s->regcfg.val_bits = 8;
|
||||
s->regcfg.read_flag_mask = 0x00;
|
||||
s->regcfg.write_flag_mask = 0x80;
|
||||
s->regcfg.cache_type = REGCACHE_RBTREE;
|
||||
s->regcfg.writeable_reg = max310x_reg_writeable;
|
||||
s->regcfg.volatile_reg = max310x_reg_volatile;
|
||||
s->regcfg.precious_reg = max310x_reg_precious;
|
||||
s->regcfg.max_register = devtype->nr * 0x20 - 1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_SPI_MASTER) && is_spi) {
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
|
||||
} else
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (IS_ERR(s->regmap)) {
|
||||
dev_err(dev, "Failed to initialize register map\n");
|
||||
return PTR_ERR(s->regmap);
|
||||
clk_osc = devm_clk_get(dev, "osc");
|
||||
clk_xtal = devm_clk_get(dev, "xtal");
|
||||
if (!IS_ERR(clk_osc)) {
|
||||
s->clk = clk_osc;
|
||||
fmin = 500000;
|
||||
fmax = 35000000;
|
||||
} else if (!IS_ERR(clk_xtal)) {
|
||||
s->clk = clk_xtal;
|
||||
fmin = 1000000;
|
||||
fmax = 4000000;
|
||||
xtal = true;
|
||||
} else if (PTR_ERR(clk_osc) == -EPROBE_DEFER ||
|
||||
PTR_ERR(clk_xtal) == -EPROBE_DEFER) {
|
||||
return -EPROBE_DEFER;
|
||||
} else {
|
||||
dev_err(dev, "Cannot get clock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Board specific configure */
|
||||
if (s->pdata->init)
|
||||
s->pdata->init();
|
||||
ret = clk_prepare_enable(s->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
freq = clk_get_rate(s->clk);
|
||||
/* Check frequency limits */
|
||||
if (freq < fmin || freq > fmax) {
|
||||
ret = -ERANGE;
|
||||
goto out_clk;
|
||||
}
|
||||
|
||||
s->regmap = regmap;
|
||||
s->devtype = devtype;
|
||||
dev_set_drvdata(dev, s);
|
||||
|
||||
/* Check device to ensure we are talking to what we expect */
|
||||
ret = devtype->detect(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_clk;
|
||||
|
||||
for (i = 0; i < devtype->nr; i++) {
|
||||
unsigned int offs = i << 5;
|
||||
|
@ -1156,7 +1173,7 @@ static int max310x_probe(struct device *dev, int is_spi,
|
|||
MAX310X_MODE1_AUTOSLEEP_BIT);
|
||||
}
|
||||
|
||||
uartclk = max310x_set_ref_clk(s);
|
||||
uartclk = max310x_set_ref_clk(s, freq, xtal);
|
||||
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
|
||||
|
||||
/* Register UART driver */
|
||||
|
@ -1168,9 +1185,28 @@ static int max310x_probe(struct device *dev, int is_spi,
|
|||
ret = uart_register_driver(&s->uart);
|
||||
if (ret) {
|
||||
dev_err(dev, "Registering UART driver failed\n");
|
||||
return ret;
|
||||
goto out_clk;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
/* Setup GPIO cotroller */
|
||||
s->gpio.owner = THIS_MODULE;
|
||||
s->gpio.dev = dev;
|
||||
s->gpio.label = dev_name(dev);
|
||||
s->gpio.direction_input = max310x_gpio_direction_input;
|
||||
s->gpio.get = max310x_gpio_get;
|
||||
s->gpio.direction_output= max310x_gpio_direction_output;
|
||||
s->gpio.set = max310x_gpio_set;
|
||||
s->gpio.base = -1;
|
||||
s->gpio.ngpio = devtype->nr * 4;
|
||||
s->gpio.can_sleep = 1;
|
||||
ret = gpiochip_add(&s->gpio);
|
||||
if (ret)
|
||||
goto out_uart;
|
||||
#endif
|
||||
|
||||
mutex_init(&s->mutex);
|
||||
|
||||
for (i = 0; i < devtype->nr; i++) {
|
||||
/* Initialize port data */
|
||||
s->p[i].port.line = i;
|
||||
|
@ -1178,8 +1214,7 @@ static int max310x_probe(struct device *dev, int is_spi,
|
|||
s->p[i].port.irq = irq;
|
||||
s->p[i].port.type = PORT_MAX310X;
|
||||
s->p[i].port.fifosize = MAX310X_FIFO_SIZE;
|
||||
s->p[i].port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE |
|
||||
UPF_LOW_LATENCY;
|
||||
s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
|
||||
s->p[i].port.iotype = UPIO_PORT;
|
||||
s->p[i].port.iobase = i * 0x20;
|
||||
s->p[i].port.membase = (void __iomem *)~0;
|
||||
|
@ -1195,48 +1230,35 @@ static int max310x_probe(struct device *dev, int is_spi,
|
|||
MAX310X_MODE1_IRQSEL_BIT);
|
||||
/* Initialize queue for start TX */
|
||||
INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
|
||||
/* Initialize queue for changing mode */
|
||||
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
|
||||
/* Register port */
|
||||
uart_add_one_port(&s->uart, &s->p[i].port);
|
||||
/* Go to suspend mode */
|
||||
devtype->power(&s->p[i].port, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
/* Setup GPIO cotroller */
|
||||
if (s->pdata->gpio_base) {
|
||||
s->gpio.owner = THIS_MODULE;
|
||||
s->gpio.dev = dev;
|
||||
s->gpio.label = dev_name(dev);
|
||||
s->gpio.direction_input = max310x_gpio_direction_input;
|
||||
s->gpio.get = max310x_gpio_get;
|
||||
s->gpio.direction_output= max310x_gpio_direction_output;
|
||||
s->gpio.set = max310x_gpio_set;
|
||||
s->gpio.base = s->pdata->gpio_base;
|
||||
s->gpio.ngpio = devtype->nr * 4;
|
||||
s->gpio.can_sleep = 1;
|
||||
if (!gpiochip_add(&s->gpio))
|
||||
s->gpio_used = 1;
|
||||
} else
|
||||
dev_info(dev, "GPIO support not enabled\n");
|
||||
#endif
|
||||
|
||||
/* Setup interrupt */
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
dev_name(dev), s);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to reguest IRQ %i\n", irq);
|
||||
IRQF_ONESHOT | flags, dev_name(dev), s);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
dev_err(dev, "Unable to reguest IRQ %i\n", irq);
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (s->gpio_used)
|
||||
WARN_ON(gpiochip_remove(&s->gpio));
|
||||
WARN_ON(gpiochip_remove(&s->gpio));
|
||||
|
||||
out_uart:
|
||||
#endif
|
||||
}
|
||||
uart_unregister_driver(&s->uart);
|
||||
|
||||
out_clk:
|
||||
clk_disable_unprepare(s->clk);
|
||||
|
||||
return ret;
|
||||
|
||||
err_freq:
|
||||
dev_err(dev, "Frequency parameter incorrect\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int max310x_remove(struct device *dev)
|
||||
|
@ -1244,30 +1266,51 @@ static int max310x_remove(struct device *dev)
|
|||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
int i, ret = 0;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
ret = gpiochip_remove(&s->gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
cancel_work_sync(&s->p[i].tx_work);
|
||||
cancel_work_sync(&s->p[i].md_work);
|
||||
uart_remove_one_port(&s->uart, &s->p[i].port);
|
||||
s->devtype->power(&s->p[i].port, 0);
|
||||
}
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
uart_unregister_driver(&s->uart);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (s->gpio_used)
|
||||
ret = gpiochip_remove(&s->gpio);
|
||||
#endif
|
||||
|
||||
if (s->pdata->exit)
|
||||
s->pdata->exit();
|
||||
clk_disable_unprepare(s->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
|
||||
{ .compatible = "maxim,max3107", .data = &max3107_devtype, },
|
||||
{ .compatible = "maxim,max3108", .data = &max3108_devtype, },
|
||||
{ .compatible = "maxim,max3109", .data = &max3109_devtype, },
|
||||
{ .compatible = "maxim,max14830", .data = &max14830_devtype },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max310x_dt_ids);
|
||||
|
||||
static struct regmap_config regcfg = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.write_flag_mask = 0x80,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.writeable_reg = max310x_reg_writeable,
|
||||
.volatile_reg = max310x_reg_volatile,
|
||||
.precious_reg = max310x_reg_precious,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SPI_MASTER
|
||||
static int max310x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct max310x_devtype *devtype =
|
||||
(struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
|
||||
struct max310x_devtype *devtype;
|
||||
unsigned long flags = 0;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
/* Setup SPI bus */
|
||||
|
@ -1275,12 +1318,25 @@ static int max310x_spi_probe(struct spi_device *spi)
|
|||
spi->mode = spi->mode ? : SPI_MODE_0;
|
||||
spi->max_speed_hz = spi->max_speed_hz ? : 26000000;
|
||||
ret = spi_setup(spi);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "SPI setup failed\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (spi->dev.of_node) {
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(max310x_dt_ids, &spi->dev);
|
||||
|
||||
devtype = (struct max310x_devtype *)of_id->data;
|
||||
} else {
|
||||
const struct spi_device_id *id_entry = spi_get_device_id(spi);
|
||||
|
||||
devtype = (struct max310x_devtype *)id_entry->driver_data;
|
||||
flags = IRQF_TRIGGER_FALLING;
|
||||
}
|
||||
|
||||
return max310x_probe(&spi->dev, 1, devtype, spi->irq);
|
||||
regcfg.max_register = devtype->nr * 0x20 - 1;
|
||||
regmap = devm_regmap_init_spi(spi, ®cfg);
|
||||
|
||||
return max310x_probe(&spi->dev, devtype, regmap, spi->irq, flags);
|
||||
}
|
||||
|
||||
static int max310x_spi_remove(struct spi_device *spi)
|
||||
|
@ -1288,8 +1344,6 @@ static int max310x_spi_remove(struct spi_device *spi)
|
|||
return max310x_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
|
||||
|
||||
static const struct spi_device_id max310x_id_table[] = {
|
||||
{ "max3107", (kernel_ulong_t)&max3107_devtype, },
|
||||
{ "max3108", (kernel_ulong_t)&max3108_devtype, },
|
||||
|
@ -1301,9 +1355,10 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table);
|
|||
|
||||
static struct spi_driver max310x_uart_driver = {
|
||||
.driver = {
|
||||
.name = MAX310X_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &max310x_pm_ops,
|
||||
.name = MAX310X_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(max310x_dt_ids),
|
||||
.pm = &max310x_pm_ops,
|
||||
},
|
||||
.probe = max310x_spi_probe,
|
||||
.remove = max310x_spi_remove,
|
||||
|
|
|
@ -39,6 +39,13 @@
|
|||
|
||||
#include "msm_serial.h"
|
||||
|
||||
enum {
|
||||
UARTDM_1P1 = 1,
|
||||
UARTDM_1P2,
|
||||
UARTDM_1P3,
|
||||
UARTDM_1P4,
|
||||
};
|
||||
|
||||
struct msm_port {
|
||||
struct uart_port uart;
|
||||
char name[16];
|
||||
|
@ -309,6 +316,8 @@ static unsigned int msm_get_mctrl(struct uart_port *port)
|
|||
|
||||
static void msm_reset(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
|
||||
/* reset everything */
|
||||
msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
|
||||
msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
|
||||
|
@ -316,6 +325,10 @@ static void msm_reset(struct uart_port *port)
|
|||
msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
|
||||
msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
|
||||
msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
|
||||
|
||||
/* Disable DM modes */
|
||||
if (msm_port->is_uartdm)
|
||||
msm_write(port, 0, UARTDM_DMEN);
|
||||
}
|
||||
|
||||
static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
|
@ -711,6 +724,117 @@ static void msm_power(struct uart_port *port, unsigned int state,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int msm_poll_init(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
|
||||
/* Enable single character mode on RX FIFO */
|
||||
if (msm_port->is_uartdm >= UARTDM_1P4)
|
||||
msm_write(port, UARTDM_DMEN_RX_SC_ENABLE, UARTDM_DMEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_poll_get_char_single(struct uart_port *port)
|
||||
{
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
unsigned int rf_reg = msm_port->is_uartdm ? UARTDM_RF : UART_RF;
|
||||
|
||||
if (!(msm_read(port, UART_SR) & UART_SR_RX_READY))
|
||||
return NO_POLL_CHAR;
|
||||
else
|
||||
return msm_read(port, rf_reg) & 0xff;
|
||||
}
|
||||
|
||||
static int msm_poll_get_char_dm_1p3(struct uart_port *port)
|
||||
{
|
||||
int c;
|
||||
static u32 slop;
|
||||
static int count;
|
||||
unsigned char *sp = (unsigned char *)&slop;
|
||||
|
||||
/* Check if a previous read had more than one char */
|
||||
if (count) {
|
||||
c = sp[sizeof(slop) - count];
|
||||
count--;
|
||||
/* Or if FIFO is empty */
|
||||
} else if (!(msm_read(port, UART_SR) & UART_SR_RX_READY)) {
|
||||
/*
|
||||
* If RX packing buffer has less than a word, force stale to
|
||||
* push contents into RX FIFO
|
||||
*/
|
||||
count = msm_read(port, UARTDM_RXFS);
|
||||
count = (count >> UARTDM_RXFS_BUF_SHIFT) & UARTDM_RXFS_BUF_MASK;
|
||||
if (count) {
|
||||
msm_write(port, UART_CR_CMD_FORCE_STALE, UART_CR);
|
||||
slop = msm_read(port, UARTDM_RF);
|
||||
c = sp[0];
|
||||
count--;
|
||||
} else {
|
||||
c = NO_POLL_CHAR;
|
||||
}
|
||||
/* FIFO has a word */
|
||||
} else {
|
||||
slop = msm_read(port, UARTDM_RF);
|
||||
c = sp[0];
|
||||
count = sizeof(slop) - 1;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int msm_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
u32 imr;
|
||||
int c;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
|
||||
/* Disable all interrupts */
|
||||
imr = msm_read(port, UART_IMR);
|
||||
msm_write(port, 0, UART_IMR);
|
||||
|
||||
if (msm_port->is_uartdm == UARTDM_1P3)
|
||||
c = msm_poll_get_char_dm_1p3(port);
|
||||
else
|
||||
c = msm_poll_get_char_single(port);
|
||||
|
||||
/* Enable interrupts */
|
||||
msm_write(port, imr, UART_IMR);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void msm_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
u32 imr;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
|
||||
/* Disable all interrupts */
|
||||
imr = msm_read(port, UART_IMR);
|
||||
msm_write(port, 0, UART_IMR);
|
||||
|
||||
if (msm_port->is_uartdm)
|
||||
reset_dm_count(port, 1);
|
||||
|
||||
/* Wait until FIFO is empty */
|
||||
while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
|
||||
cpu_relax();
|
||||
|
||||
/* Write a character */
|
||||
msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
|
||||
|
||||
/* Wait until FIFO is empty */
|
||||
while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
|
||||
cpu_relax();
|
||||
|
||||
/* Enable interrupts */
|
||||
msm_write(port, imr, UART_IMR);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct uart_ops msm_uart_pops = {
|
||||
.tx_empty = msm_tx_empty,
|
||||
.set_mctrl = msm_set_mctrl,
|
||||
|
@ -729,6 +853,11 @@ static struct uart_ops msm_uart_pops = {
|
|||
.config_port = msm_config_port,
|
||||
.verify_port = msm_verify_port,
|
||||
.pm = msm_power,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_init = msm_poll_init,
|
||||
.poll_get_char = msm_poll_get_char,
|
||||
.poll_put_char = msm_poll_put_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct msm_port msm_uart_ports[] = {
|
||||
|
@ -900,7 +1029,10 @@ static struct uart_driver msm_uart_driver = {
|
|||
static atomic_t msm_uart_next_id = ATOMIC_INIT(0);
|
||||
|
||||
static const struct of_device_id msm_uartdm_table[] = {
|
||||
{ .compatible = "qcom,msm-uartdm" },
|
||||
{ .compatible = "qcom,msm-uartdm-v1.1", .data = (void *)UARTDM_1P1 },
|
||||
{ .compatible = "qcom,msm-uartdm-v1.2", .data = (void *)UARTDM_1P2 },
|
||||
{ .compatible = "qcom,msm-uartdm-v1.3", .data = (void *)UARTDM_1P3 },
|
||||
{ .compatible = "qcom,msm-uartdm-v1.4", .data = (void *)UARTDM_1P4 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -909,6 +1041,7 @@ static int __init msm_serial_probe(struct platform_device *pdev)
|
|||
struct msm_port *msm_port;
|
||||
struct resource *resource;
|
||||
struct uart_port *port;
|
||||
const struct of_device_id *id;
|
||||
int irq;
|
||||
|
||||
if (pdev->id == -1)
|
||||
|
@ -923,8 +1056,9 @@ static int __init msm_serial_probe(struct platform_device *pdev)
|
|||
port->dev = &pdev->dev;
|
||||
msm_port = UART_TO_MSM(port);
|
||||
|
||||
if (of_match_device(msm_uartdm_table, &pdev->dev))
|
||||
msm_port->is_uartdm = 1;
|
||||
id = of_match_device(msm_uartdm_table, &pdev->dev);
|
||||
if (id)
|
||||
msm_port->is_uartdm = (unsigned long)id->data;
|
||||
else
|
||||
msm_port->is_uartdm = 0;
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#define UART_CR_CMD_RESET_RFR (14 << 4)
|
||||
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
|
||||
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
|
||||
#define UART_CR_CMD_FORCE_STALE (4 << 8)
|
||||
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
|
||||
#define UART_CR_TX_DISABLE (1 << 3)
|
||||
#define UART_CR_TX_ENABLE (1 << 2)
|
||||
|
@ -113,6 +114,14 @@
|
|||
#define GSBI_PROTOCOL_UART 0x40
|
||||
#define GSBI_PROTOCOL_IDLE 0x0
|
||||
|
||||
#define UARTDM_RXFS 0x50
|
||||
#define UARTDM_RXFS_BUF_SHIFT 0x7
|
||||
#define UARTDM_RXFS_BUF_MASK 0x7
|
||||
|
||||
#define UARTDM_DMEN 0x3C
|
||||
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
|
||||
#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
|
||||
|
||||
#define UARTDM_DMRX 0x34
|
||||
#define UARTDM_NCF_TX 0x40
|
||||
#define UARTDM_RX_TOTAL_SNAP 0x38
|
||||
|
|
|
@ -342,7 +342,14 @@ static void serial_omap_stop_tx(struct uart_port *port)
|
|||
|
||||
if ((up->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(up->rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
up->ier = UART_IER_RLSI | UART_IER_RDI;
|
||||
/*
|
||||
* Empty the RX FIFO, we are not interested in anything
|
||||
* received during the half-duplex transmission.
|
||||
*/
|
||||
serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_RCVR);
|
||||
/* Re-enable RX interrupts */
|
||||
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
up->port.read_status_mask |= UART_LSR_DR;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
|
@ -355,7 +362,7 @@ static void serial_omap_stop_rx(struct uart_port *port)
|
|||
struct uart_omap_port *up = to_uart_omap_port(port);
|
||||
|
||||
pm_runtime_get_sync(up->dev);
|
||||
up->ier &= ~UART_IER_RLSI;
|
||||
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
|
||||
up->port.read_status_mask &= ~UART_LSR_DR;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
|
|
|
@ -1762,7 +1762,9 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
|||
int fifosize;
|
||||
int port_type;
|
||||
struct pch_uart_driver_data *board;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
char name[32]; /* for debugfs file name */
|
||||
#endif
|
||||
|
||||
board = &drv_dat[id->driver_data];
|
||||
port_type = board->port_type;
|
||||
|
|
|
@ -1282,6 +1282,14 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto probe_err;
|
||||
|
||||
if (!s3c24xx_uart_drv.state) {
|
||||
ret = uart_register_driver(&s3c24xx_uart_drv);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to register Samsung UART driver\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dbg("%s: adding port\n", __func__);
|
||||
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
|
||||
platform_set_drvdata(pdev, &ourport->port);
|
||||
|
@ -1321,6 +1329,8 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
|
|||
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
||||
}
|
||||
|
||||
uart_unregister_driver(&s3c24xx_uart_drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1820,35 +1830,7 @@ static struct platform_driver samsung_serial_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
/* module initialisation code */
|
||||
|
||||
static int __init s3c24xx_serial_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&s3c24xx_uart_drv);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to register Samsung UART driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&samsung_serial_driver);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to register platform driver\n");
|
||||
uart_unregister_driver(&s3c24xx_uart_drv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit s3c24xx_serial_modexit(void)
|
||||
{
|
||||
platform_driver_unregister(&samsung_serial_driver);
|
||||
uart_unregister_driver(&s3c24xx_uart_drv);
|
||||
}
|
||||
|
||||
module_init(s3c24xx_serial_modinit);
|
||||
module_exit(s3c24xx_serial_modexit);
|
||||
module_platform_driver(samsung_serial_driver);
|
||||
|
||||
MODULE_ALIAS("platform:samsung-uart");
|
||||
MODULE_DESCRIPTION("Samsung SoC Serial port driver");
|
||||
|
|
|
@ -1319,9 +1319,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
|||
uport = state->uart_port;
|
||||
port = &state->port;
|
||||
|
||||
pr_debug("uart_close(%d) called\n", uport->line);
|
||||
pr_debug("uart_close(%d) called\n", uport ? uport->line : -1);
|
||||
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
if (!port->count || tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -1762,7 +1762,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
|
|||
}
|
||||
|
||||
/**
|
||||
* uart_parse_options - Parse serial port baud/parity/bits/flow contro.
|
||||
* uart_parse_options - Parse serial port baud/parity/bits/flow control.
|
||||
* @options: pointer to option string
|
||||
* @baud: pointer to an 'int' variable for the baud rate.
|
||||
* @parity: pointer to an 'int' variable for the parity.
|
||||
|
@ -2609,7 +2609,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
|
||||
/*
|
||||
* Register the port whether it's detected or not. This allows
|
||||
* setserial to be used to alter this ports parameters.
|
||||
* setserial to be used to alter this port's parameters.
|
||||
*/
|
||||
tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
|
||||
uport->line, uport->dev, port, tty_dev_attr_groups);
|
||||
|
@ -2645,6 +2645,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
{
|
||||
struct uart_state *state = drv->state + uport->line;
|
||||
struct tty_port *port = &state->port;
|
||||
struct tty_struct *tty;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(in_interrupt());
|
||||
|
@ -2673,8 +2674,17 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
*/
|
||||
tty_unregister_device(drv->tty_driver, uport->line);
|
||||
|
||||
if (port->tty)
|
||||
tty = tty_port_tty_get(port);
|
||||
if (tty) {
|
||||
tty_vhangup(port->tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the port is used as a console, unregister it
|
||||
*/
|
||||
if (uart_console(uport))
|
||||
unregister_console(uport->cons);
|
||||
|
||||
/*
|
||||
* Free the port IO and memory resources, if any.
|
||||
|
|
|
@ -428,7 +428,7 @@ static int sci_probe_regmap(struct plat_sci_port *cfg)
|
|||
cfg->regtype = SCIx_HSCIF_REGTYPE;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "Can't probe register map for given port\n");
|
||||
pr_err("Can't probe register map for given port\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -788,7 +788,7 @@ static int sci_handle_errors(struct uart_port *port)
|
|||
if (tty_insert_flip_char(tport, 0, TTY_OVERRUN))
|
||||
copied++;
|
||||
|
||||
dev_notice(port->dev, "overrun error");
|
||||
dev_notice(port->dev, "overrun error\n");
|
||||
}
|
||||
|
||||
if (status & SCxSR_FER(port)) {
|
||||
|
@ -830,7 +830,7 @@ static int sci_handle_errors(struct uart_port *port)
|
|||
if (tty_insert_flip_char(tport, 0, TTY_PARITY))
|
||||
copied++;
|
||||
|
||||
dev_notice(port->dev, "parity error");
|
||||
dev_notice(port->dev, "parity error\n");
|
||||
}
|
||||
|
||||
if (copied)
|
||||
|
@ -911,7 +911,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
|||
/* Disable future Rx interrupts */
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
|
||||
disable_irq_nosync(irq);
|
||||
scr |= 0x4000;
|
||||
scr |= SCSCR_RDRQE;
|
||||
} else {
|
||||
scr &= ~SCSCR_RIE;
|
||||
}
|
||||
|
@ -1199,7 +1199,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
*/
|
||||
reg = sci_getreg(port, SCFCR);
|
||||
if (reg->size)
|
||||
serial_port_out(port, SCFCR, serial_port_in(port, SCFCR) | 1);
|
||||
serial_port_out(port, SCFCR,
|
||||
serial_port_in(port, SCFCR) |
|
||||
SCFCR_LOOP);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1289,7 +1291,8 @@ static void sci_dma_rx_complete(void *arg)
|
|||
unsigned long flags;
|
||||
int count;
|
||||
|
||||
dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
|
||||
dev_dbg(port->dev, "%s(%d) active #%d\n",
|
||||
__func__, port->line, s->active_rx);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
|
@ -1365,8 +1368,8 @@ static void sci_submit_rx(struct sci_port *s)
|
|||
sci_rx_dma_release(s, true);
|
||||
return;
|
||||
}
|
||||
dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
|
||||
s->cookie_rx[i], i);
|
||||
dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n",
|
||||
__func__, s->cookie_rx[i], i);
|
||||
}
|
||||
|
||||
s->active_rx = s->cookie_rx[0];
|
||||
|
@ -1425,8 +1428,8 @@ static void work_fn_rx(struct work_struct *work)
|
|||
|
||||
s->active_rx = s->cookie_rx[!new];
|
||||
|
||||
dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
|
||||
s->cookie_rx[new], new, s->active_rx);
|
||||
dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n",
|
||||
__func__, s->cookie_rx[new], new, s->active_rx);
|
||||
}
|
||||
|
||||
static void work_fn_tx(struct work_struct *work)
|
||||
|
@ -1479,8 +1482,8 @@ static void work_fn_tx(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
|
||||
xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
|
||||
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
|
||||
__func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
|
||||
|
||||
dma_async_issue_pending(chan);
|
||||
}
|
||||
|
@ -1495,9 +1498,9 @@ static void sci_start_tx(struct uart_port *port)
|
|||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
|
||||
u16 new, scr = serial_port_in(port, SCSCR);
|
||||
if (s->chan_tx)
|
||||
new = scr | 0x8000;
|
||||
new = scr | SCSCR_TDRQE;
|
||||
else
|
||||
new = scr & ~0x8000;
|
||||
new = scr & ~SCSCR_TDRQE;
|
||||
if (new != scr)
|
||||
serial_port_out(port, SCSCR, new);
|
||||
}
|
||||
|
@ -1524,7 +1527,7 @@ static void sci_stop_tx(struct uart_port *port)
|
|||
ctrl = serial_port_in(port, SCSCR);
|
||||
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
|
||||
ctrl &= ~0x8000;
|
||||
ctrl &= ~SCSCR_TDRQE;
|
||||
|
||||
ctrl &= ~SCSCR_TIE;
|
||||
|
||||
|
@ -1538,7 +1541,7 @@ static void sci_start_rx(struct uart_port *port)
|
|||
ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
|
||||
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
|
||||
ctrl &= ~0x4000;
|
||||
ctrl &= ~SCSCR_RDRQE;
|
||||
|
||||
serial_port_out(port, SCSCR, ctrl);
|
||||
}
|
||||
|
@ -1550,7 +1553,7 @@ static void sci_stop_rx(struct uart_port *port)
|
|||
ctrl = serial_port_in(port, SCSCR);
|
||||
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
|
||||
ctrl &= ~0x4000;
|
||||
ctrl &= ~SCSCR_RDRQE;
|
||||
|
||||
ctrl &= ~port_rx_irq_mask(port);
|
||||
|
||||
|
@ -1599,8 +1602,8 @@ static bool filter(struct dma_chan *chan, void *slave)
|
|||
{
|
||||
struct sh_dmae_slave *param = slave;
|
||||
|
||||
dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
|
||||
param->shdma_slave.slave_id);
|
||||
dev_dbg(chan->device->dev, "%s: slave ID %d\n",
|
||||
__func__, param->shdma_slave.slave_id);
|
||||
|
||||
chan->private = ¶m->shdma_slave;
|
||||
return true;
|
||||
|
@ -1613,7 +1616,7 @@ static void rx_timer_fn(unsigned long arg)
|
|||
u16 scr = serial_port_in(port, SCSCR);
|
||||
|
||||
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
|
||||
scr &= ~0x4000;
|
||||
scr &= ~SCSCR_RDRQE;
|
||||
enable_irq(s->irqs[SCIx_RXI_IRQ]);
|
||||
}
|
||||
serial_port_out(port, SCSCR, scr | SCSCR_RIE);
|
||||
|
@ -1629,8 +1632,7 @@ static void sci_request_dma(struct uart_port *port)
|
|||
dma_cap_mask_t mask;
|
||||
int nent;
|
||||
|
||||
dev_dbg(port->dev, "%s: port %d\n", __func__,
|
||||
port->line);
|
||||
dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
|
||||
|
||||
if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)
|
||||
return;
|
||||
|
@ -1658,7 +1660,8 @@ static void sci_request_dma(struct uart_port *port)
|
|||
if (!nent)
|
||||
sci_tx_dma_release(s, false);
|
||||
else
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
|
||||
dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n",
|
||||
__func__,
|
||||
sg_dma_len(&s->sg_tx), port->state->xmit.buf,
|
||||
&sg_dma_address(&s->sg_tx));
|
||||
|
||||
|
@ -1870,13 +1873,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
smr_val = serial_port_in(port, SCSMR) & 3;
|
||||
|
||||
if ((termios->c_cflag & CSIZE) == CS7)
|
||||
smr_val |= 0x40;
|
||||
smr_val |= SCSMR_CHR;
|
||||
if (termios->c_cflag & PARENB)
|
||||
smr_val |= 0x20;
|
||||
smr_val |= SCSMR_PE;
|
||||
if (termios->c_cflag & PARODD)
|
||||
smr_val |= 0x30;
|
||||
smr_val |= SCSMR_PE | SCSMR_ODD;
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
smr_val |= 0x08;
|
||||
smr_val |= SCSMR_STOP;
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
|
@ -1884,7 +1887,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
__func__, smr_val, cks, t, s->cfg->scscr);
|
||||
|
||||
if (t >= 0) {
|
||||
serial_port_out(port, SCSMR, (smr_val & ~3) | cks);
|
||||
serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks);
|
||||
serial_port_out(port, SCBRR, t);
|
||||
reg = sci_getreg(port, HSSRR);
|
||||
if (reg->size)
|
||||
|
@ -1932,8 +1935,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
if (s->chan_rx) {
|
||||
s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
|
||||
port->fifosize / 2;
|
||||
dev_dbg(port->dev,
|
||||
"DMA Rx t-out %ums, tty t-out %u jiffies\n",
|
||||
dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
|
||||
s->rx_timeout * 1000 / HZ, port->timeout);
|
||||
if (s->rx_timeout < msecs_to_jiffies(20))
|
||||
s->rx_timeout = msecs_to_jiffies(20);
|
||||
|
@ -1952,7 +1954,7 @@ static void sci_pm(struct uart_port *port, unsigned int state,
|
|||
struct sci_port *sci_port = to_sci_port(port);
|
||||
|
||||
switch (state) {
|
||||
case 3:
|
||||
case UART_PM_STATE_OFF:
|
||||
sci_port_disable(sci_port);
|
||||
break;
|
||||
default:
|
||||
|
@ -2017,7 +2019,7 @@ static int sci_remap_port(struct uart_port *port)
|
|||
* need to do any remapping, just cast the cookie
|
||||
* directly.
|
||||
*/
|
||||
port->membase = (void __iomem *)port->mapbase;
|
||||
port->membase = (void __iomem *)(uintptr_t)port->mapbase;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2388,8 +2390,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
|
|||
|
||||
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
|
||||
|
||||
static char banner[] __initdata =
|
||||
KERN_INFO "SuperH (H)SCI(F) driver initialized\n";
|
||||
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
|
||||
|
||||
static struct uart_driver sci_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -2423,25 +2424,25 @@ struct sci_port_info {
|
|||
static const struct of_device_id of_sci_match[] = {
|
||||
{
|
||||
.compatible = "renesas,scif",
|
||||
.data = (void *)&(const struct sci_port_info) {
|
||||
.data = &(const struct sci_port_info) {
|
||||
.type = PORT_SCIF,
|
||||
.regtype = SCIx_SH4_SCIF_REGTYPE,
|
||||
},
|
||||
}, {
|
||||
.compatible = "renesas,scifa",
|
||||
.data = (void *)&(const struct sci_port_info) {
|
||||
.data = &(const struct sci_port_info) {
|
||||
.type = PORT_SCIFA,
|
||||
.regtype = SCIx_SCIFA_REGTYPE,
|
||||
},
|
||||
}, {
|
||||
.compatible = "renesas,scifb",
|
||||
.data = (void *)&(const struct sci_port_info) {
|
||||
.data = &(const struct sci_port_info) {
|
||||
.type = PORT_SCIFB,
|
||||
.regtype = SCIx_SCIFB_REGTYPE,
|
||||
},
|
||||
}, {
|
||||
.compatible = "renesas,hscif",
|
||||
.data = (void *)&(const struct sci_port_info) {
|
||||
.data = &(const struct sci_port_info) {
|
||||
.type = PORT_HSCIF,
|
||||
.regtype = SCIx_HSCIF_REGTYPE,
|
||||
},
|
||||
|
@ -2501,11 +2502,9 @@ static int sci_probe_single(struct platform_device *dev,
|
|||
|
||||
/* Sanity check */
|
||||
if (unlikely(index >= SCI_NPORTS)) {
|
||||
dev_notice(&dev->dev, "Attempting to register port "
|
||||
"%d when only %d are available.\n",
|
||||
dev_notice(&dev->dev, "Attempting to register port %d when only %d are available\n",
|
||||
index+1, SCI_NPORTS);
|
||||
dev_notice(&dev->dev, "Consider bumping "
|
||||
"CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
|
||||
dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -2563,6 +2562,7 @@ static int sci_probe(struct platform_device *dev)
|
|||
ret = cpufreq_register_notifier(&sp->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
if (unlikely(ret < 0)) {
|
||||
uart_remove_one_port(&sci_uart_driver, &sp->port);
|
||||
sci_cleanup_single(sp);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2614,7 +2614,7 @@ static int __init sci_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
printk(banner);
|
||||
pr_info("%s\n", banner);
|
||||
|
||||
ret = uart_register_driver(&sci_uart_driver);
|
||||
if (likely(ret == 0)) {
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/sirfsoc_dma.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
|
@ -173,7 +172,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
|
|||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
|
||||
if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
|
||||
if (sirfport->tx_dma_chan) {
|
||||
if (sirfport->tx_dma_state == TX_DMA_RUNNING) {
|
||||
dmaengine_pause(sirfport->tx_dma_chan);
|
||||
sirfport->tx_dma_state = TX_DMA_PAUSE;
|
||||
|
@ -288,7 +287,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
|
|||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
|
||||
if (sirfport->tx_dma_chan)
|
||||
sirfsoc_uart_tx_with_dma(sirfport);
|
||||
else {
|
||||
sirfsoc_uart_pio_tx_chars(sirfport, 1);
|
||||
|
@ -310,7 +309,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
|
|||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
|
||||
if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
|
||||
if (sirfport->rx_dma_chan) {
|
||||
if (!sirfport->is_marco)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
|
@ -675,7 +674,7 @@ recv_char:
|
|||
uart_handle_cts_change(port, cts_status);
|
||||
wake_up_interruptible(&state->port.delta_msr_wait);
|
||||
}
|
||||
if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
|
||||
if (sirfport->rx_dma_chan) {
|
||||
if (intr_status & uint_st->sirfsoc_rx_timeout)
|
||||
sirfsoc_uart_handle_rx_tmo(sirfport);
|
||||
if (intr_status & uint_st->sirfsoc_rx_done)
|
||||
|
@ -686,7 +685,7 @@ recv_char:
|
|||
SIRFSOC_UART_IO_RX_MAX_CNT);
|
||||
}
|
||||
if (intr_status & uint_st->sirfsoc_txfifo_empty) {
|
||||
if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
|
||||
if (sirfport->tx_dma_chan)
|
||||
sirfsoc_uart_tx_with_dma(sirfport);
|
||||
else {
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
|
@ -778,7 +777,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
|
|||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
|
||||
if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
|
||||
if (sirfport->rx_dma_chan)
|
||||
sirfsoc_uart_start_next_rx_dma(port);
|
||||
else {
|
||||
if (!sirfport->is_marco)
|
||||
|
@ -1014,11 +1013,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
|||
(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
|
||||
SIRFSOC_USP_ASYNC_DIV2_OFFSET);
|
||||
}
|
||||
if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
|
||||
if (sirfport->tx_dma_chan)
|
||||
wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
|
||||
if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
|
||||
if (sirfport->rx_dma_chan)
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
|
||||
|
@ -1049,93 +1048,6 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
|
|||
clk_disable_unprepare(sirfport->clk);
|
||||
}
|
||||
|
||||
static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
dma_cap_mask_t dma_mask;
|
||||
struct dma_slave_config tx_slv_cfg = {
|
||||
.dst_maxburst = 2,
|
||||
};
|
||||
|
||||
dma_cap_zero(dma_mask);
|
||||
dma_cap_set(DMA_SLAVE, dma_mask);
|
||||
sirfport->tx_dma_chan = dma_request_channel(dma_mask,
|
||||
(dma_filter_fn)sirfsoc_dma_filter_id,
|
||||
(void *)sirfport->tx_dma_no);
|
||||
if (!sirfport->tx_dma_chan) {
|
||||
dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
|
||||
sirfport->tx_dma_no);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int sirfsoc_uart_init_rx_dma(struct uart_port *port)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
dma_cap_mask_t dma_mask;
|
||||
int ret;
|
||||
int i, j;
|
||||
struct dma_slave_config slv_cfg = {
|
||||
.src_maxburst = 2,
|
||||
};
|
||||
|
||||
dma_cap_zero(dma_mask);
|
||||
dma_cap_set(DMA_SLAVE, dma_mask);
|
||||
sirfport->rx_dma_chan = dma_request_channel(dma_mask,
|
||||
(dma_filter_fn)sirfsoc_dma_filter_id,
|
||||
(void *)sirfport->rx_dma_no);
|
||||
if (!sirfport->rx_dma_chan) {
|
||||
dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
|
||||
sirfport->rx_dma_no);
|
||||
ret = -EPROBE_DEFER;
|
||||
goto request_err;
|
||||
}
|
||||
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
|
||||
sirfport->rx_dma_items[i].xmit.buf =
|
||||
dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
&sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
|
||||
if (!sirfport->rx_dma_items[i].xmit.buf) {
|
||||
dev_err(port->dev, "Uart alloc bufa failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto alloc_coherent_err;
|
||||
}
|
||||
sirfport->rx_dma_items[i].xmit.head =
|
||||
sirfport->rx_dma_items[i].xmit.tail = 0;
|
||||
}
|
||||
dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
|
||||
|
||||
return 0;
|
||||
alloc_coherent_err:
|
||||
for (j = 0; j < i; j++)
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items[j].xmit.buf,
|
||||
sirfport->rx_dma_items[j].dma_addr);
|
||||
dma_release_channel(sirfport->rx_dma_chan);
|
||||
request_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_uninit_tx_dma(struct sirfsoc_uart_port *sirfport)
|
||||
{
|
||||
dmaengine_terminate_all(sirfport->tx_dma_chan);
|
||||
dma_release_channel(sirfport->tx_dma_chan);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_uninit_rx_dma(struct sirfsoc_uart_port *sirfport)
|
||||
{
|
||||
int i;
|
||||
struct uart_port *port = &sirfport->port;
|
||||
dmaengine_terminate_all(sirfport->rx_dma_chan);
|
||||
dma_release_channel(sirfport->rx_dma_chan);
|
||||
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items[i].xmit.buf,
|
||||
sirfport->rx_dma_items[i].dma_addr);
|
||||
}
|
||||
|
||||
static int sirfsoc_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
|
@ -1174,18 +1086,12 @@ static int sirfsoc_uart_startup(struct uart_port *port)
|
|||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
|
||||
|
||||
if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
|
||||
ret = sirfsoc_uart_init_rx_dma(port);
|
||||
if (ret)
|
||||
goto init_rx_err;
|
||||
if (sirfport->rx_dma_chan)
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk,
|
||||
SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
|
||||
SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
|
||||
SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
|
||||
}
|
||||
if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
|
||||
sirfsoc_uart_init_tx_dma(port);
|
||||
SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
|
||||
SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
|
||||
SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
|
||||
if (sirfport->tx_dma_chan) {
|
||||
sirfport->tx_dma_state = TX_DMA_IDLE;
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,
|
||||
SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) |
|
||||
|
@ -1232,12 +1138,8 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
|
|||
gpio_set_value(sirfport->rts_gpio, 1);
|
||||
free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport);
|
||||
}
|
||||
if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
|
||||
sirfsoc_uart_uninit_rx_dma(sirfport);
|
||||
if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
|
||||
sirfsoc_uart_uninit_tx_dma(sirfport);
|
||||
if (sirfport->tx_dma_chan)
|
||||
sirfport->tx_dma_state = TX_DMA_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sirfsoc_uart_type(struct uart_port *port)
|
||||
|
@ -1313,8 +1215,8 @@ sirfsoc_uart_console_setup(struct console *co, char *options)
|
|||
port->cons = co;
|
||||
|
||||
/* default console tx/rx transfer using io mode */
|
||||
sirfport->rx_dma_no = UNVALID_DMA_CHAN;
|
||||
sirfport->tx_dma_no = UNVALID_DMA_CHAN;
|
||||
sirfport->rx_dma_chan = NULL;
|
||||
sirfport->tx_dma_chan = NULL;
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
|
@ -1382,6 +1284,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
|||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
int i, j;
|
||||
struct dma_slave_config slv_cfg = {
|
||||
.src_maxburst = 2,
|
||||
};
|
||||
struct dma_slave_config tx_slv_cfg = {
|
||||
.dst_maxburst = 2,
|
||||
};
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
|
||||
|
@ -1402,27 +1311,10 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
|||
|
||||
sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
|
||||
"sirf,uart-has-rtscts");
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) {
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart"))
|
||||
sirfport->uart_reg->uart_type = SIRF_REAL_UART;
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"sirf,uart-dma-rx-channel",
|
||||
&sirfport->rx_dma_no))
|
||||
sirfport->rx_dma_no = UNVALID_DMA_CHAN;
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"sirf,uart-dma-tx-channel",
|
||||
&sirfport->tx_dma_no))
|
||||
sirfport->tx_dma_no = UNVALID_DMA_CHAN;
|
||||
}
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
|
||||
sirfport->uart_reg->uart_type = SIRF_USP_UART;
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"sirf,usp-dma-rx-channel",
|
||||
&sirfport->rx_dma_no))
|
||||
sirfport->rx_dma_no = UNVALID_DMA_CHAN;
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"sirf,usp-dma-tx-channel",
|
||||
&sirfport->tx_dma_no))
|
||||
sirfport->tx_dma_no = UNVALID_DMA_CHAN;
|
||||
if (!sirfport->hw_flow_ctrl)
|
||||
goto usp_no_flow_control;
|
||||
if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
|
||||
|
@ -1515,8 +1407,32 @@ usp_no_flow_control:
|
|||
goto port_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx");
|
||||
for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
|
||||
sirfport->rx_dma_items[i].xmit.buf =
|
||||
dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
&sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
|
||||
if (!sirfport->rx_dma_items[i].xmit.buf) {
|
||||
dev_err(port->dev, "Uart alloc bufa failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto alloc_coherent_err;
|
||||
}
|
||||
sirfport->rx_dma_items[i].xmit.head =
|
||||
sirfport->rx_dma_items[i].xmit.tail = 0;
|
||||
}
|
||||
if (sirfport->rx_dma_chan)
|
||||
dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
|
||||
sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx");
|
||||
if (sirfport->tx_dma_chan)
|
||||
dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
|
||||
|
||||
return 0;
|
||||
alloc_coherent_err:
|
||||
for (j = 0; j < i; j++)
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items[j].xmit.buf,
|
||||
sirfport->rx_dma_items[j].dma_addr);
|
||||
dma_release_channel(sirfport->rx_dma_chan);
|
||||
port_err:
|
||||
clk_put(sirfport->clk);
|
||||
err:
|
||||
|
@ -1529,6 +1445,19 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
|
|||
struct uart_port *port = &sirfport->port;
|
||||
clk_put(sirfport->clk);
|
||||
uart_remove_one_port(&sirfsoc_uart_drv, port);
|
||||
if (sirfport->rx_dma_chan) {
|
||||
int i;
|
||||
dmaengine_terminate_all(sirfport->rx_dma_chan);
|
||||
dma_release_channel(sirfport->rx_dma_chan);
|
||||
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items[i].xmit.buf,
|
||||
sirfport->rx_dma_items[i].dma_addr);
|
||||
}
|
||||
if (sirfport->tx_dma_chan) {
|
||||
dmaengine_terminate_all(sirfport->tx_dma_chan);
|
||||
dma_release_channel(sirfport->tx_dma_chan);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -392,9 +392,6 @@ struct sirfsoc_uart_register sirfsoc_uart = {
|
|||
/* Indicate how many buffers used */
|
||||
#define SIRFSOC_RX_LOOP_BUF_CNT 2
|
||||
|
||||
/* Indicate if DMA channel valid */
|
||||
#define IS_DMA_CHAN_VALID(x) ((x) != -1)
|
||||
#define UNVALID_DMA_CHAN -1
|
||||
/* For Fast Baud Rate Calculation */
|
||||
struct sirfsoc_baudrate_to_regv {
|
||||
unsigned int baud_rate;
|
||||
|
@ -423,8 +420,6 @@ struct sirfsoc_uart_port {
|
|||
/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
|
||||
bool is_marco;
|
||||
struct sirfsoc_uart_register *uart_reg;
|
||||
int rx_dma_no;
|
||||
int tx_dma_no;
|
||||
struct dma_chan *rx_dma_chan;
|
||||
struct dma_chan *tx_dma_chan;
|
||||
dma_addr_t tx_dma_addr;
|
||||
|
|
|
@ -7866,6 +7866,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
|
||||
HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
|
||||
|
||||
memset(&new_line, 0, sizeof(new_line));
|
||||
switch (flags){
|
||||
case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
|
||||
case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
|
||||
|
|
|
@ -1766,6 +1766,7 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
|
||||
HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
|
||||
|
||||
memset(&new_line, 0, sizeof(new_line));
|
||||
switch (flags){
|
||||
case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
|
||||
case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
|
||||
|
|
|
@ -351,14 +351,11 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
|
|||
* Takes any pending buffers and transfers their ownership to the
|
||||
* ldisc side of the queue. It then schedules those characters for
|
||||
* processing by the line discipline.
|
||||
* Note that this function can only be used when the low_latency flag
|
||||
* is unset. Otherwise the workqueue won't be flushed.
|
||||
*/
|
||||
|
||||
void tty_schedule_flip(struct tty_port *port)
|
||||
{
|
||||
struct tty_bufhead *buf = &port->buf;
|
||||
WARN_ON(port->low_latency);
|
||||
|
||||
buf->tail->commit = buf->tail->used;
|
||||
schedule_work(&buf->work);
|
||||
|
@ -482,17 +479,15 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||
*/
|
||||
void tty_flush_to_ldisc(struct tty_struct *tty)
|
||||
{
|
||||
if (!tty->port->low_latency)
|
||||
flush_work(&tty->port->buf.work);
|
||||
flush_work(&tty->port->buf.work);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_flip_buffer_push - terminal
|
||||
* @port: tty port to push
|
||||
*
|
||||
* Queue a push of the terminal flip buffers to the line discipline. This
|
||||
* function must not be called from IRQ context if port->low_latency is
|
||||
* set.
|
||||
* Queue a push of the terminal flip buffers to the line discipline.
|
||||
* Can be called from IRQ/atomic context.
|
||||
*
|
||||
* In the event of the queue being busy for flipping the work will be
|
||||
* held off and retried later.
|
||||
|
@ -500,14 +495,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
|
|||
|
||||
void tty_flip_buffer_push(struct tty_port *port)
|
||||
{
|
||||
struct tty_bufhead *buf = &port->buf;
|
||||
|
||||
buf->tail->commit = buf->tail->used;
|
||||
|
||||
if (port->low_latency)
|
||||
flush_to_ldisc(&buf->work);
|
||||
else
|
||||
schedule_work(&buf->work);
|
||||
tty_schedule_flip(port);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_flip_buffer_push);
|
||||
|
||||
|
|
|
@ -1271,12 +1271,13 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
|
|||
*
|
||||
* Locking: None
|
||||
*/
|
||||
static void tty_line_name(struct tty_driver *driver, int index, char *p)
|
||||
static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)
|
||||
{
|
||||
if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
|
||||
strcpy(p, driver->name);
|
||||
return sprintf(p, "%s", driver->name);
|
||||
else
|
||||
sprintf(p, "%s%d", driver->name, index + driver->name_base);
|
||||
return sprintf(p, "%s%d", driver->name,
|
||||
index + driver->name_base);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3545,9 +3546,19 @@ static ssize_t show_cons_active(struct device *dev,
|
|||
if (i >= ARRAY_SIZE(cs))
|
||||
break;
|
||||
}
|
||||
while (i--)
|
||||
count += sprintf(buf + count, "%s%d%c",
|
||||
cs[i]->name, cs[i]->index, i ? ' ':'\n');
|
||||
while (i--) {
|
||||
int index = cs[i]->index;
|
||||
struct tty_driver *drv = cs[i]->device(cs[i], &index);
|
||||
|
||||
/* don't resolve tty0 as some programs depend on it */
|
||||
if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR))
|
||||
count += tty_line_name(drv, index, buf + count);
|
||||
else
|
||||
count += sprintf(buf + count, "%s%d",
|
||||
cs[i]->name, cs[i]->index);
|
||||
|
||||
count += sprintf(buf + count, "%c", i ? ' ':'\n');
|
||||
}
|
||||
console_unlock();
|
||||
|
||||
return count;
|
||||
|
|
|
@ -1590,9 +1590,9 @@ static void restore_cur(struct vc_data *vc)
|
|||
vc->vc_need_wrap = 0;
|
||||
}
|
||||
|
||||
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
|
||||
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
|
||||
EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
|
||||
ESpalette };
|
||||
ESpalette, ESosc };
|
||||
|
||||
/* console_lock is held (except via vc_init()) */
|
||||
static void reset_terminal(struct vc_data *vc, int do_clear)
|
||||
|
@ -1652,11 +1652,15 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
|
|||
* Control characters can be used in the _middle_
|
||||
* of an escape sequence.
|
||||
*/
|
||||
if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */
|
||||
return;
|
||||
switch (c) {
|
||||
case 0:
|
||||
return;
|
||||
case 7:
|
||||
if (vc->vc_bell_duration)
|
||||
if (vc->vc_state == ESosc)
|
||||
vc->vc_state = ESnormal;
|
||||
else if (vc->vc_bell_duration)
|
||||
kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
|
||||
return;
|
||||
case 8:
|
||||
|
@ -1767,7 +1771,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
|
|||
} else if (c=='R') { /* reset palette */
|
||||
reset_palette(vc);
|
||||
vc->vc_state = ESnormal;
|
||||
} else
|
||||
} else if (c>='0' && c<='9')
|
||||
vc->vc_state = ESosc;
|
||||
else
|
||||
vc->vc_state = ESnormal;
|
||||
return;
|
||||
case ESpalette:
|
||||
|
@ -1807,9 +1813,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
|
|||
vc->vc_par[vc->vc_npar] *= 10;
|
||||
vc->vc_par[vc->vc_npar] += c - '0';
|
||||
return;
|
||||
} else
|
||||
vc->vc_state = ESgotpars;
|
||||
case ESgotpars:
|
||||
}
|
||||
vc->vc_state = ESnormal;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
|
@ -2023,6 +2027,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
|
|||
vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
|
||||
vc->vc_state = ESnormal;
|
||||
return;
|
||||
case ESosc:
|
||||
return;
|
||||
default:
|
||||
vc->vc_state = ESnormal;
|
||||
}
|
||||
|
|
|
@ -549,8 +549,8 @@ static void gs_rx_push(unsigned long _port)
|
|||
port->read_started--;
|
||||
}
|
||||
|
||||
/* Push from tty to ldisc; without low_latency set this is handled by
|
||||
* a workqueue, so we won't get callbacks and can hold port_lock
|
||||
/* Push from tty to ldisc; this is handled by a workqueue,
|
||||
* so we won't get callbacks and can hold port_lock
|
||||
*/
|
||||
if (do_push)
|
||||
tty_flip_buffer_push(&port->port);
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
|
||||
*
|
||||
* Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
|
||||
*
|
||||
* Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
|
||||
* Based on max3110.c, by Feng Tang <feng.tang@intel.com>
|
||||
* Based on max3107.c, by Aavamobile
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _MAX310X_H_
|
||||
#define _MAX310X_H_
|
||||
|
||||
/*
|
||||
* Example board initialization data:
|
||||
*
|
||||
* static struct max310x_pdata max3107_pdata = {
|
||||
* .driver_flags = MAX310X_EXT_CLK,
|
||||
* .uart_flags[0] = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL,
|
||||
* .frequency = 3686400,
|
||||
* .gpio_base = -1,
|
||||
* };
|
||||
*
|
||||
* static struct spi_board_info spi_device_max3107[] = {
|
||||
* {
|
||||
* .modalias = "max3107",
|
||||
* .irq = IRQ_EINT3,
|
||||
* .bus_num = 1,
|
||||
* .chip_select = 1,
|
||||
* .platform_data = &max3107_pdata,
|
||||
* },
|
||||
* };
|
||||
*/
|
||||
|
||||
#define MAX310X_MAX_UARTS 4
|
||||
|
||||
/* MAX310X platform data structure */
|
||||
struct max310x_pdata {
|
||||
/* Flags global to driver */
|
||||
const u8 driver_flags;
|
||||
#define MAX310X_EXT_CLK (0x00000001) /* External clock enable */
|
||||
/* Flags global to UART port */
|
||||
const u8 uart_flags[MAX310X_MAX_UARTS];
|
||||
#define MAX310X_LOOPBACK (0x00000001) /* Loopback mode enable */
|
||||
#define MAX310X_ECHO_SUPRESS (0x00000002) /* Enable echo supress */
|
||||
#define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction
|
||||
* control (RS-485)
|
||||
*/
|
||||
/* Frequency (extrenal clock or crystal) */
|
||||
const int frequency;
|
||||
/* GPIO base number (can be negative) */
|
||||
const int gpio_base;
|
||||
/* Called during startup */
|
||||
void (*init)(void);
|
||||
/* Called before finish */
|
||||
void (*exit)(void);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -23,8 +23,6 @@
|
|||
#define IMXUART_IRDA (1<<1)
|
||||
|
||||
struct imxuart_platform_data {
|
||||
int (*init)(struct platform_device *pdev);
|
||||
void (*exit)(struct platform_device *pdev);
|
||||
unsigned int flags;
|
||||
void (*irda_enable)(int enable);
|
||||
unsigned int irda_inv_rx:1;
|
||||
|
|
|
@ -116,4 +116,6 @@
|
|||
UART_FIFO_PARERR_MASK | \
|
||||
UART_FIFO_BRKDET_MASK)
|
||||
|
||||
#define UART_REG_SIZE 24
|
||||
|
||||
#endif /* _LINUX_SERIAL_BCM63XX_H */
|
||||
|
|
|
@ -10,45 +10,59 @@
|
|||
|
||||
#define SCIx_NOT_SUPPORTED (-1)
|
||||
|
||||
#define SCSCR_TIE (1 << 7)
|
||||
#define SCSCR_RIE (1 << 6)
|
||||
#define SCSCR_TE (1 << 5)
|
||||
#define SCSCR_RE (1 << 4)
|
||||
#define SCSCR_REIE (1 << 3) /* not supported by all parts */
|
||||
#define SCSCR_TOIE (1 << 2) /* not supported by all parts */
|
||||
#define SCSCR_CKE1 (1 << 1)
|
||||
#define SCSCR_CKE0 (1 << 0)
|
||||
/* SCSMR (Serial Mode Register) */
|
||||
#define SCSMR_CHR (1 << 6) /* 7-bit Character Length */
|
||||
#define SCSMR_PE (1 << 5) /* Parity Enable */
|
||||
#define SCSMR_ODD (1 << 4) /* Odd Parity */
|
||||
#define SCSMR_STOP (1 << 3) /* Stop Bit Length */
|
||||
#define SCSMR_CKS 0x0003 /* Clock Select */
|
||||
|
||||
/* SCxSR SCI */
|
||||
#define SCI_TDRE 0x80
|
||||
#define SCI_RDRF 0x40
|
||||
#define SCI_ORER 0x20
|
||||
#define SCI_FER 0x10
|
||||
#define SCI_PER 0x08
|
||||
#define SCI_TEND 0x04
|
||||
/* Serial Control Register (@ = not supported by all parts) */
|
||||
#define SCSCR_TIE (1 << 7) /* Transmit Interrupt Enable */
|
||||
#define SCSCR_RIE (1 << 6) /* Receive Interrupt Enable */
|
||||
#define SCSCR_TE (1 << 5) /* Transmit Enable */
|
||||
#define SCSCR_RE (1 << 4) /* Receive Enable */
|
||||
#define SCSCR_REIE (1 << 3) /* Receive Error Interrupt Enable @ */
|
||||
#define SCSCR_TOIE (1 << 2) /* Timeout Interrupt Enable @ */
|
||||
#define SCSCR_CKE1 (1 << 1) /* Clock Enable 1 */
|
||||
#define SCSCR_CKE0 (1 << 0) /* Clock Enable 0 */
|
||||
/* SCIFA/SCIFB only */
|
||||
#define SCSCR_TDRQE (1 << 15) /* Tx Data Transfer Request Enable */
|
||||
#define SCSCR_RDRQE (1 << 14) /* Rx Data Transfer Request Enable */
|
||||
|
||||
/* SCxSR (Serial Status Register) on SCI */
|
||||
#define SCI_TDRE 0x80 /* Transmit Data Register Empty */
|
||||
#define SCI_RDRF 0x40 /* Receive Data Register Full */
|
||||
#define SCI_ORER 0x20 /* Overrun Error */
|
||||
#define SCI_FER 0x10 /* Framing Error */
|
||||
#define SCI_PER 0x08 /* Parity Error */
|
||||
#define SCI_TEND 0x04 /* Transmit End */
|
||||
|
||||
#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
|
||||
|
||||
/* SCxSR SCIF, HSCIF */
|
||||
#define SCIF_ER 0x0080
|
||||
#define SCIF_TEND 0x0040
|
||||
#define SCIF_TDFE 0x0020
|
||||
#define SCIF_BRK 0x0010
|
||||
#define SCIF_FER 0x0008
|
||||
#define SCIF_PER 0x0004
|
||||
#define SCIF_RDF 0x0002
|
||||
#define SCIF_DR 0x0001
|
||||
/* SCxSR (Serial Status Register) on SCIF, HSCIF */
|
||||
#define SCIF_ER 0x0080 /* Receive Error */
|
||||
#define SCIF_TEND 0x0040 /* Transmission End */
|
||||
#define SCIF_TDFE 0x0020 /* Transmit FIFO Data Empty */
|
||||
#define SCIF_BRK 0x0010 /* Break Detect */
|
||||
#define SCIF_FER 0x0008 /* Framing Error */
|
||||
#define SCIF_PER 0x0004 /* Parity Error */
|
||||
#define SCIF_RDF 0x0002 /* Receive FIFO Data Full */
|
||||
#define SCIF_DR 0x0001 /* Receive Data Ready */
|
||||
|
||||
#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
|
||||
|
||||
/* SCSPTR, optional */
|
||||
#define SCSPTR_RTSIO (1 << 7)
|
||||
#define SCSPTR_CTSIO (1 << 5)
|
||||
#define SCSPTR_SPB2IO (1 << 1)
|
||||
#define SCSPTR_SPB2DT (1 << 0)
|
||||
/* SCFCR (FIFO Control Register) */
|
||||
#define SCFCR_LOOP (1 << 0) /* Loopback Test */
|
||||
|
||||
/* SCSPTR (Serial Port Register), optional */
|
||||
#define SCSPTR_RTSIO (1 << 7) /* Serial Port RTS Pin Input/Output */
|
||||
#define SCSPTR_CTSIO (1 << 5) /* Serial Port CTS Pin Input/Output */
|
||||
#define SCSPTR_SPB2IO (1 << 1) /* Serial Port Break Input/Output */
|
||||
#define SCSPTR_SPB2DT (1 << 0) /* Serial Port Break Data */
|
||||
|
||||
/* HSSRR HSCIF */
|
||||
#define HSCIF_SRE 0x8000
|
||||
#define HSCIF_SRE 0x8000 /* Sampling Rate Register Enable */
|
||||
|
||||
enum {
|
||||
SCIx_PROBE_REGTYPE,
|
||||
|
@ -73,10 +87,19 @@ enum {
|
|||
* Not all registers will exist on all parts.
|
||||
*/
|
||||
enum {
|
||||
SCSMR, SCBRR, SCSCR, SCxSR,
|
||||
SCFCR, SCFDR, SCxTDR, SCxRDR,
|
||||
SCLSR, SCTFDR, SCRFDR, SCSPTR,
|
||||
HSSRR,
|
||||
SCSMR, /* Serial Mode Register */
|
||||
SCBRR, /* Bit Rate Register */
|
||||
SCSCR, /* Serial Control Register */
|
||||
SCxSR, /* Serial Status Register */
|
||||
SCFCR, /* FIFO Control Register */
|
||||
SCFDR, /* FIFO Data Count Register */
|
||||
SCxTDR, /* Transmit (FIFO) Data Register */
|
||||
SCxRDR, /* Receive (FIFO) Data Register */
|
||||
SCLSR, /* Line Status Register */
|
||||
SCTFDR, /* Transmit FIFO Data Count Register */
|
||||
SCRFDR, /* Receive FIFO Data Count Register */
|
||||
SCSPTR, /* Serial Port Register */
|
||||
HSSRR, /* Sampling Rate Register */
|
||||
|
||||
SCIx_NR_REGS,
|
||||
};
|
||||
|
|
|
@ -208,7 +208,7 @@ struct tty_port {
|
|||
wait_queue_head_t delta_msr_wait; /* Modem status change */
|
||||
unsigned long flags; /* TTY flags ASY_*/
|
||||
unsigned char console:1, /* port is a console */
|
||||
low_latency:1; /* direct buffer flush */
|
||||
low_latency:1; /* optional: tune for latency */
|
||||
struct mutex mutex; /* Locking */
|
||||
struct mutex buf_mutex; /* Buffer alloc lock */
|
||||
unsigned char *xmit_buf; /* Optional buffer */
|
||||
|
|
|
@ -126,7 +126,6 @@
|
|||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue