Commit c2078402 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial driver updates from Greg KH:
 "Here is the big tty/serial driver update for 4.3-rc1.

  Not many major things, a number of driver updates and changes, and the
  8250 driver got split up a bit to make it easier to work with by
  moving some functions to a new file.  Full details are in the
  shortlog.

  All have been in linux-next with no reported issues"

* tag 'tty-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (90 commits)
  serial: imx: save and restore context in the suspend path
  serial: imx: allow waking up on RTSD
  serial: imx: introduce serial_imx_enable_wakeup()
  serial: imx: remove unbalanced clk_prepare
  serial: 8250: move rx_running out of the bitfield
  tty: serial: 8250_omap: do not use RX DMA if pause is not supported
  serial:8250_dw: do not alter CTS and DCTS since AFE is enabled
  tty: serial: men_z135_uart.c: Don't initialize port->lock
  tty: serial: men_z135_uart.c: Fix race between IRQ and set_termios()
  serial: 8250: bind to ALi Fast Infrared Controller (ALI5123)
  serial: 8250: don't bind to SMSC IrCC IR port
  serial: mxs-auart: fix baud rate range
  serial: mxs-auart: keep the AUART unit in reset state when not in use
  serial: mxs-auart: use a function name to reflect what it really does
  serial: 8250_pci: fix mode after S3/S4 resume for F81504/508/512
  sc16is7xx: constify devtype
  sc16is7xx: support multiple devices
  sc16is7xx: save and use per-chip line number
  uart: pl011: Add support to ZTE ZX296702 uart
  uart: pl011: Improve LCRH register access decision
  ...
parents 2f37d65a c868cbb7
...@@ -22,6 +22,8 @@ Optional properties: ...@@ -22,6 +22,8 @@ Optional properties:
memory peripheral interface and USART DMA channel ID, FIFO configuration. memory peripheral interface and USART DMA channel ID, FIFO configuration.
Refer to dma.txt and atmel-dma.txt for details. Refer to dma.txt and atmel-dma.txt for details.
- dma-names: "rx" for RX channel, "tx" for TX channel. - dma-names: "rx" for RX channel, "tx" for TX channel.
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
capable USARTs.
<chip> compatible description: <chip> compatible description:
- at91rm9200: legacy USART support - at91rm9200: legacy USART support
...@@ -57,4 +59,5 @@ Example: ...@@ -57,4 +59,5 @@ Example:
dmas = <&dma0 2 0x3>, dmas = <&dma0 2 0x3>,
<&dma0 2 0x204>; <&dma0 2 0x204>;
dma-names = "tx", "rx"; dma-names = "tx", "rx";
atmel,fifo-size = <32>;
}; };
...@@ -6,7 +6,7 @@ Required properties: ...@@ -6,7 +6,7 @@ Required properties:
- interrupts: device interrupt - interrupts: device interrupt
Optional properties: Optional properties:
- {dtr,dsr,ri,cd}-gpios: specify a GPIO for DTR/DSR/RI/CD - {dtr,dsr,rng,dcd}-gpios: specify a GPIO for DTR/DSR/RI/DCD
line respectively. line respectively.
Example: Example:
...@@ -16,4 +16,8 @@ serial@b00260000 { ...@@ -16,4 +16,8 @@ serial@b00260000 {
reg = <0xb0026000 0x1000>; reg = <0xb0026000 0x1000>;
interrupts = <68>; interrupts = <68>;
status = "disabled"; status = "disabled";
dtr-gpios = <&sysgpio 0 GPIO_ACTIVE_LOW>;
dsr-gpios = <&sysgpio 1 GPIO_ACTIVE_LOW>;
rng-gpios = <&sysgpio 2 GPIO_ACTIVE_LOW>;
dcd-gpios = <&sysgpio 3 GPIO_ACTIVE_LOW>;
}; };
...@@ -4,6 +4,9 @@ Required properties: ...@@ -4,6 +4,9 @@ Required properties:
- compatible : should be "ti,omap2-uart" for OMAP2 controllers - compatible : should be "ti,omap2-uart" for OMAP2 controllers
- compatible : should be "ti,omap3-uart" for OMAP3 controllers - compatible : should be "ti,omap3-uart" for OMAP3 controllers
- compatible : should be "ti,omap4-uart" for OMAP4 controllers - compatible : should be "ti,omap4-uart" for OMAP4 controllers
- compatible : should be "ti,am4372-uart" for AM437x controllers
- compatible : should be "ti,am3352-uart" for AM335x controllers
- compatible : should be "ti,dra742-uart" for DRA7x controllers
- reg : address and length of the register space - reg : address and length of the register space
- interrupts or interrupts-extended : Should contain the uart interrupt - interrupts or interrupts-extended : Should contain the uart interrupt
specifier or both the interrupt specifier or both the interrupt
......
...@@ -210,7 +210,7 @@ gpio3: gpio@481ae000 { ...@@ -210,7 +210,7 @@ gpio3: gpio@481ae000 {
}; };
uart0: serial@44e09000 { uart0: serial@44e09000 {
compatible = "ti,omap3-uart"; compatible = "ti,am3352-uart", "ti,omap3-uart";
ti,hwmods = "uart1"; ti,hwmods = "uart1";
clock-frequency = <48000000>; clock-frequency = <48000000>;
reg = <0x44e09000 0x2000>; reg = <0x44e09000 0x2000>;
...@@ -221,7 +221,7 @@ uart0: serial@44e09000 { ...@@ -221,7 +221,7 @@ uart0: serial@44e09000 {
}; };
uart1: serial@48022000 { uart1: serial@48022000 {
compatible = "ti,omap3-uart"; compatible = "ti,am3352-uart", "ti,omap3-uart";
ti,hwmods = "uart2"; ti,hwmods = "uart2";
clock-frequency = <48000000>; clock-frequency = <48000000>;
reg = <0x48022000 0x2000>; reg = <0x48022000 0x2000>;
...@@ -232,7 +232,7 @@ uart1: serial@48022000 { ...@@ -232,7 +232,7 @@ uart1: serial@48022000 {
}; };
uart2: serial@48024000 { uart2: serial@48024000 {
compatible = "ti,omap3-uart"; compatible = "ti,am3352-uart", "ti,omap3-uart";
ti,hwmods = "uart3"; ti,hwmods = "uart3";
clock-frequency = <48000000>; clock-frequency = <48000000>;
reg = <0x48024000 0x2000>; reg = <0x48024000 0x2000>;
...@@ -243,7 +243,7 @@ uart2: serial@48024000 { ...@@ -243,7 +243,7 @@ uart2: serial@48024000 {
}; };
uart3: serial@481a6000 { uart3: serial@481a6000 {
compatible = "ti,omap3-uart"; compatible = "ti,am3352-uart", "ti,omap3-uart";
ti,hwmods = "uart4"; ti,hwmods = "uart4";
clock-frequency = <48000000>; clock-frequency = <48000000>;
reg = <0x481a6000 0x2000>; reg = <0x481a6000 0x2000>;
...@@ -252,7 +252,7 @@ uart3: serial@481a6000 { ...@@ -252,7 +252,7 @@ uart3: serial@481a6000 {
}; };
uart4: serial@481a8000 { uart4: serial@481a8000 {
compatible = "ti,omap3-uart"; compatible = "ti,am3352-uart", "ti,omap3-uart";
ti,hwmods = "uart5"; ti,hwmods = "uart5";
clock-frequency = <48000000>; clock-frequency = <48000000>;
reg = <0x481a8000 0x2000>; reg = <0x481a8000 0x2000>;
...@@ -261,7 +261,7 @@ uart4: serial@481a8000 { ...@@ -261,7 +261,7 @@ uart4: serial@481a8000 {
}; };
uart5: serial@481aa000 { uart5: serial@481aa000 {
compatible = "ti,omap3-uart"; compatible = "ti,am3352-uart", "ti,omap3-uart";
ti,hwmods = "uart6"; ti,hwmods = "uart6";
clock-frequency = <48000000>; clock-frequency = <48000000>;
reg = <0x481aa000 0x2000>; reg = <0x481aa000 0x2000>;
......
...@@ -397,7 +397,7 @@ gpio8: gpio@48053000 { ...@@ -397,7 +397,7 @@ gpio8: gpio@48053000 {
}; };
uart1: serial@4806a000 { uart1: serial@4806a000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x4806a000 0x100>; reg = <0x4806a000 0x100>;
interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart1"; ti,hwmods = "uart1";
...@@ -408,7 +408,7 @@ uart1: serial@4806a000 { ...@@ -408,7 +408,7 @@ uart1: serial@4806a000 {
}; };
uart2: serial@4806c000 { uart2: serial@4806c000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x4806c000 0x100>; reg = <0x4806c000 0x100>;
interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart2"; ti,hwmods = "uart2";
...@@ -419,7 +419,7 @@ uart2: serial@4806c000 { ...@@ -419,7 +419,7 @@ uart2: serial@4806c000 {
}; };
uart3: serial@48020000 { uart3: serial@48020000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x48020000 0x100>; reg = <0x48020000 0x100>;
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart3"; ti,hwmods = "uart3";
...@@ -430,7 +430,7 @@ uart3: serial@48020000 { ...@@ -430,7 +430,7 @@ uart3: serial@48020000 {
}; };
uart4: serial@4806e000 { uart4: serial@4806e000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x4806e000 0x100>; reg = <0x4806e000 0x100>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart4"; ti,hwmods = "uart4";
...@@ -441,7 +441,7 @@ uart4: serial@4806e000 { ...@@ -441,7 +441,7 @@ uart4: serial@4806e000 {
}; };
uart5: serial@48066000 { uart5: serial@48066000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x48066000 0x100>; reg = <0x48066000 0x100>;
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart5"; ti,hwmods = "uart5";
...@@ -452,7 +452,7 @@ uart5: serial@48066000 { ...@@ -452,7 +452,7 @@ uart5: serial@48066000 {
}; };
uart6: serial@48068000 { uart6: serial@48068000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x48068000 0x100>; reg = <0x48068000 0x100>;
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart6"; ti,hwmods = "uart6";
...@@ -463,7 +463,7 @@ uart6: serial@48068000 { ...@@ -463,7 +463,7 @@ uart6: serial@48068000 {
}; };
uart7: serial@48420000 { uart7: serial@48420000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x48420000 0x100>; reg = <0x48420000 0x100>;
interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart7"; ti,hwmods = "uart7";
...@@ -472,7 +472,7 @@ uart7: serial@48420000 { ...@@ -472,7 +472,7 @@ uart7: serial@48420000 {
}; };
uart8: serial@48422000 { uart8: serial@48422000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x48422000 0x100>; reg = <0x48422000 0x100>;
interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart8"; ti,hwmods = "uart8";
...@@ -481,7 +481,7 @@ uart8: serial@48422000 { ...@@ -481,7 +481,7 @@ uart8: serial@48422000 {
}; };
uart9: serial@48424000 { uart9: serial@48424000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x48424000 0x100>; reg = <0x48424000 0x100>;
interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart9"; ti,hwmods = "uart9";
...@@ -490,7 +490,7 @@ uart9: serial@48424000 { ...@@ -490,7 +490,7 @@ uart9: serial@48424000 {
}; };
uart10: serial@4ae2b000 { uart10: serial@4ae2b000 {
compatible = "ti,omap4-uart"; compatible = "ti,dra742-uart", "ti,omap4-uart";
reg = <0x4ae2b000 0x100>; reg = <0x4ae2b000 0x100>;
interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "uart10"; ti,hwmods = "uart10";
......
...@@ -153,6 +153,7 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = { ...@@ -153,6 +153,7 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = {
{"AEI0250"}, /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */ {"AEI0250"}, /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
{"AEI1240"}, /* Actiontec ISA PNP 56K X2 Fax Modem */ {"AEI1240"}, /* Actiontec ISA PNP 56K X2 Fax Modem */
{"AKY1021"}, /* Rockwell 56K ACF II Fax+Data+Voice Modem */ {"AKY1021"}, /* Rockwell 56K ACF II Fax+Data+Voice Modem */
{"ALI5123"}, /* ALi Fast Infrared Controller */
{"AZT4001"}, /* AZT3005 PnP SOUND DEVICE */ {"AZT4001"}, /* AZT3005 PnP SOUND DEVICE */
{"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */ {"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */
{"BRI0A49"}, /* Boca Complete Ofc Communicator 14.4 Data-FAX */ {"BRI0A49"}, /* Boca Complete Ofc Communicator 14.4 Data-FAX */
......
...@@ -2712,7 +2712,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, ...@@ -2712,7 +2712,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
memcpy(skb_put(skb, size), in_buf, size); memcpy(skb_put(skb, size), in_buf, size);
skb->dev = net; skb->dev = net;
skb->protocol = __constant_htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
/* Ship it off to the kernel */ /* Ship it off to the kernel */
netif_rx(skb); netif_rx(skb);
......
...@@ -2147,6 +2147,8 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *, ...@@ -2147,6 +2147,8 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
static int job_control(struct tty_struct *tty, struct file *file) static int job_control(struct tty_struct *tty, struct file *file)
{ {
struct pid *pgrp;
/* Job control check -- must be done at start and after /* Job control check -- must be done at start and after
every sleep (POSIX.1 7.1.1.4). */ every sleep (POSIX.1 7.1.1.4). */
/* NOTE: not yet done after every sleep pending a thorough /* NOTE: not yet done after every sleep pending a thorough
...@@ -2156,18 +2158,25 @@ static int job_control(struct tty_struct *tty, struct file *file) ...@@ -2156,18 +2158,25 @@ static int job_control(struct tty_struct *tty, struct file *file)
current->signal->tty != tty) current->signal->tty != tty)
return 0; return 0;
rcu_read_lock();
pgrp = task_pgrp(current);
spin_lock_irq(&tty->ctrl_lock); spin_lock_irq(&tty->ctrl_lock);
if (!tty->pgrp) if (!tty->pgrp)
printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
else if (task_pgrp(current) != tty->pgrp) { else if (pgrp != tty->pgrp) {
spin_unlock_irq(&tty->ctrl_lock); spin_unlock_irq(&tty->ctrl_lock);
if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) {
rcu_read_unlock();
return -EIO; return -EIO;
kill_pgrp(task_pgrp(current), SIGTTIN, 1); }
kill_pgrp(pgrp, SIGTTIN, 1);
rcu_read_unlock();
set_thread_flag(TIF_SIGPENDING); set_thread_flag(TIF_SIGPENDING);
return -ERESTARTSYS; return -ERESTARTSYS;
} }
spin_unlock_irq(&tty->ctrl_lock); spin_unlock_irq(&tty->ctrl_lock);
rcu_read_unlock();
return 0; return 0;
} }
......
...@@ -26,6 +26,12 @@ ...@@ -26,6 +26,12 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/poll.h> #include <linux/poll.h>
#undef TTY_DEBUG_HANGUP
#ifdef TTY_DEBUG_HANGUP
# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args)
#else
# define tty_debug_hangup(tty, f, args...) do {} while (0)
#endif
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver; static struct tty_driver *ptm_driver;
...@@ -779,6 +785,8 @@ static int ptmx_open(struct inode *inode, struct file *filp) ...@@ -779,6 +785,8 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval) if (retval)
goto err_release; goto err_release;
tty_debug_hangup(tty, "(tty count=%d)\n", tty->count);
tty_unlock(tty); tty_unlock(tty);
return 0; return 0;
err_release: err_release:
......
...@@ -42,9 +42,9 @@ struct uart_8250_dma { ...@@ -42,9 +42,9 @@ struct uart_8250_dma {
size_t rx_size; size_t rx_size;
size_t tx_size; size_t tx_size;
unsigned char tx_running:1; unsigned char tx_running;
unsigned char tx_err: 1; unsigned char tx_err;
unsigned char rx_running:1; unsigned char rx_running;
}; };
struct old_serial_port { struct old_serial_port {
...@@ -211,3 +211,14 @@ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) ...@@ -211,3 +211,14 @@ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
} }
return 1; return 1;
} }
static inline int serial_index(struct uart_port *port)
{
return port->minor - 64;
}
#if 0
#define DEBUG_INTR(fmt...) printk(fmt)
#else
#define DEBUG_INTR(fmt...) do { } while (0)
#endif
This diff is collapsed.
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
struct dw8250_data { struct dw8250_data {
u8 usr_reg; u8 usr_reg;
int last_mcr;
int line; int line;
int msr_mask_on; int msr_mask_on;
int msr_mask_off; int msr_mask_off;
...@@ -76,12 +75,6 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) ...@@ -76,12 +75,6 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{ {
struct dw8250_data *d = p->private_data; struct dw8250_data *d = p->private_data;
/* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */
if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) {
value |= UART_MSR_CTS;
value &= ~UART_MSR_DCTS;
}
/* Override any modem control signals if needed */ /* Override any modem control signals if needed */
if (offset == UART_MSR) { if (offset == UART_MSR) {
value |= d->msr_mask_on; value |= d->msr_mask_on;
...@@ -101,11 +94,6 @@ static void dw8250_force_idle(struct uart_port *p) ...@@ -101,11 +94,6 @@ static void dw8250_force_idle(struct uart_port *p)
static void dw8250_serial_out(struct uart_port *p, int offset, int value) static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{ {
struct dw8250_data *d = p->private_data;
if (offset == UART_MCR)
d->last_mcr = value;
writeb(value, p->membase + (offset << p->regshift)); writeb(value, p->membase + (offset << p->regshift));
/* Make sure LCR write wasn't ignored */ /* Make sure LCR write wasn't ignored */
...@@ -144,11 +132,6 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) ...@@ -144,11 +132,6 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
static void dw8250_serial_outq(struct uart_port *p, int offset, int value) static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{ {
struct dw8250_data *d = p->private_data;
if (offset == UART_MCR)
d->last_mcr = value;
value &= 0xff; value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift)); __raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */ /* Read back to ensure register write ordering. */
...@@ -175,11 +158,6 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value) ...@@ -175,11 +158,6 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
static void dw8250_serial_out32(struct uart_port *p, int offset, int value) static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{ {
struct dw8250_data *d = p->private_data;
if (offset == UART_MCR)
d->last_mcr = value;
writel(value, p->membase + (offset << p->regshift)); writel(value, p->membase + (offset << p->regshift));
/* Make sure LCR write wasn't ignored */ /* Make sure LCR write wasn't ignored */
...@@ -257,6 +235,11 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, ...@@ -257,6 +235,11 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
if (!ret) if (!ret)
p->uartclk = rate; p->uartclk = rate;
p->status &= ~UPSTAT_AUTOCTS;
if (termios->c_cflag & CRTSCTS)
p->status |= UPSTAT_AUTOCTS;
out: out:
serial8250_do_set_termios(p, termios, old); serial8250_do_set_termios(p, termios, old);
} }
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/serial.h> #include <asm/serial.h>
unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) static unsigned int __init serial8250_early_in(struct uart_port *port, int offset)
{ {
switch (port->iotype) { switch (port->iotype) {
case UPIO_MEM: case UPIO_MEM:
...@@ -51,7 +51,7 @@ unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offse ...@@ -51,7 +51,7 @@ unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offse
} }
} }
void __weak __init serial8250_early_out(struct uart_port *port, int offset, int value) static void __init serial8250_early_out(struct uart_port *port, int offset, int value)
{ {
switch (port->iotype) { switch (port->iotype) {
case UPIO_MEM: case UPIO_MEM:
......
...@@ -17,18 +17,19 @@ ...@@ -17,18 +17,19 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include "8250.h" #include "8250.h"
#define ADDR_PORT 0x4E #define ADDR_PORT 0
#define DATA_PORT 0x4F #define DATA_PORT 1
#define ENTRY_KEY 0x77
#define EXIT_KEY 0xAA #define EXIT_KEY 0xAA
#define CHIP_ID1 0x20 #define CHIP_ID1 0x20
#define CHIP_ID1_VAL 0x02
#define CHIP_ID2 0x21 #define CHIP_ID2 0x21
#define CHIP_ID2_VAL 0x16 #define CHIP_ID_0 0x1602
#define CHIP_ID_1 0x0501
#define VENDOR_ID1 0x23 #define VENDOR_ID1 0x23
#define VENDOR_ID1_VAL 0x19 #define VENDOR_ID1_VAL 0x19
#define VENDOR_ID2 0x24 #define VENDOR_ID2 0x24
#define VENDOR_ID2_VAL 0x34 #define VENDOR_ID2_VAL 0x34
#define IO_ADDR1 0x61
#define IO_ADDR2 0x60
#define LDN 0x7 #define LDN 0x7
#define RS485 0xF0 #define RS485 0xF0
...@@ -39,51 +40,49 @@ ...@@ -39,51 +40,49 @@
#define DRIVER_NAME "8250_fintek" #define DRIVER_NAME "8250_fintek"
static int fintek_8250_enter_key(void){ struct fintek_8250 {
u16 base_port;
u8 index;
u8 key;
long line;
};
static int fintek_8250_enter_key(u16 base_port, u8 key)
{
if (!request_muxed_region(ADDR_PORT, 2, DRIVER_NAME)) if (!request_muxed_region(base_port, 2, DRIVER_NAME))
return -EBUSY; return -EBUSY;
outb(ENTRY_KEY, ADDR_PORT); outb(key, base_port + ADDR_PORT);
outb(ENTRY_KEY, ADDR_PORT); outb(key, base_port + ADDR_PORT);
return 0; return 0;
} }
static void fintek_8250_exit_key(void){ static void fintek_8250_exit_key(u16 base_port)
outb(EXIT_KEY, ADDR_PORT);
release_region(ADDR_PORT, 2);
}
static int fintek_8250_get_index(resource_size_t base_addr)
{ {
resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
int i;
for (i = 0; i < ARRAY_SIZE(base); i++)
if (base_addr == base[i])
return i;
return -ENODEV; outb(EXIT_KEY, base_port + ADDR_PORT);
release_region(base_port + ADDR_PORT, 2);
} }
static int fintek_8250_check_id(void) static int fintek_8250_check_id(u16 base_port)
{ {
u16 chip;
outb(CHIP_ID1, ADDR_PORT); outb(VENDOR_ID1, base_port + ADDR_PORT);
if (inb(DATA_PORT) != CHIP_ID1_VAL) if (inb(base_port + DATA_PORT) != VENDOR_ID1_VAL)
return -ENODEV; return -ENODEV;
outb(CHIP_ID2, ADDR_PORT); outb(VENDOR_ID2, base_port + ADDR_PORT);
if (inb(DATA_PORT) != CHIP_ID2_VAL) if (inb(base_port + DATA_PORT) != VENDOR_ID2_VAL)
return -ENODEV; return -ENODEV;
outb(VENDOR_ID1, ADDR_PORT); outb(CHIP_ID1, base_port + ADDR_PORT);
if (inb(DATA_PORT) != VENDOR_ID1_VAL) chip = inb(base_port + DATA_PORT);
return -ENODEV; outb(CHIP_ID2, base_port + ADDR_PORT);
chip |= inb(base_port + DATA_PORT) << 8;
outb(VENDOR_ID2, ADDR_PORT); if (chip != CHIP_ID_0 && chip != CHIP_ID_1)
if (inb(DATA_PORT) != VENDOR_ID2_VAL)
return -ENODEV; return -ENODEV;
return 0; return 0;
...@@ -93,9 +92,9 @@ static int fintek_8250_rs485_config(struct uart_port *port, ...@@ -93,9 +92,9 @@ static int fintek_8250_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485) struct serial_rs485 *rs485)
{ {
uint8_t config = 0; uint8_t config = 0;
int index = fintek_8250_get_index(port->iobase); struct fintek_8250 *pdata = port->private_data;
if (index < 0) if (!pdata)
return -EINVAL; return -EINVAL;
if (rs485->flags & SER_RS485_ENABLED) if (rs485->flags & SER_RS485_ENABLED)
...@@ -125,44 +124,84 @@ static int fintek_8250_rs485_config(struct uart_port *port, ...@@ -125,44 +124,84 @@ static int fintek_8250_rs485_config(struct uart_port *port,
if (rs485->flags & SER_RS485_RTS_ON_SEND) if (rs485->flags & SER_RS485_RTS_ON_SEND)
config |= RTS_INVERT; config |= RTS_INVERT;
if (fintek_8250_enter_key()) if (fintek_8250_enter_key(pdata->base_port, pdata->key))
return -EBUSY; return -EBUSY;
outb(LDN, ADDR_PORT); outb(LDN, pdata->base_port + ADDR_PORT);
outb(index, DATA_PORT); outb(pdata->index, pdata->base_port + DATA_PORT);
outb(RS485, ADDR_PORT); outb(RS485, pdata->base_port + ADDR_PORT);
outb(config, DATA_PORT); outb(config, pdata->base_port + DATA_PORT);
fintek_8250_exit_key(); fintek_8250_exit_key(pdata->base_port);
port->rs485 = *rs485; port->rs485 = *rs485;
return 0; return 0;
} }
static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
{
static const u16 addr[] = {0x4e, 0x2e};
static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
int i, j, k;
for (i = 0; i < ARRAY_SIZE(addr); i++) {
for (j = 0; j < ARRAY_SIZE(keys); j++) {
if (fintek_8250_enter_key(addr[i], keys[j]))
continue;
if (fintek_8250_check_id(addr[i])) {
fintek_8250_exit_key(addr[i]);
continue;
}
for (k = 0; k < 4; k++) {
u16 aux;
outb(LDN, addr[i] + ADDR_PORT);
outb(k, addr[i] + DATA_PORT);
outb(IO_ADDR1, addr[i] + ADDR_PORT);
aux = inb(addr[i] + DATA_PORT);
outb(IO_ADDR2, addr[i] + ADDR_PORT);
aux |= inb(addr[i] + DATA_PORT) << 8;
if (aux != io_address)
continue;
fintek_8250_exit_key(addr[i]);
*key = keys[j];
*index = k;
return addr[i];
}
fintek_8250_exit_key(addr[i]);
}
}
return -ENODEV;
}
static int static int
fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{ {
int line;
struct uart_8250_port uart; struct uart_8250_port uart;
int ret; struct fintek_8250 *pdata;
int base_port;
u8 key;
u8 index;
if (!pnp_port_valid(dev, 0)) if (!pnp_port_valid(dev, 0))
return -ENODEV; return -ENODEV;
if (fintek_8250_get_index(pnp_port_start(dev, 0)) < 0) base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index);
if (base_port < 0)
return -ENODEV; return -ENODEV;
/* Enable configuration registers*/ memset(&uart, 0, sizeof(uart));
if (fintek_8250_enter_key())
return -EBUSY;
/*Check ID*/ pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
ret = fintek_8250_check_id(); if (!pdata)
fintek_8250_exit_key(); return -ENOMEM;
if (ret) uart.port.private_data = pdata;
return ret;
memset(&uart, 0, sizeof(uart));
if (!pnp_irq_valid(dev, 0)) if (!pnp_irq_valid(dev, 0))
return -ENODEV; return -ENODEV;
uart.port.irq = pnp_irq(dev, 0); uart.port.irq = pnp_irq(dev, 0);
...@@ -176,40 +215,43 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) ...@@ -176,40 +215,43 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
uart.port.uartclk = 1843200; uart.port.uartclk = 1843200;
uart.port.dev = &dev->dev; uart.port.dev = &dev->dev;
line = serial8250_register_8250_port(&uart); pdata->key = key;
if (line < 0) pdata->base_port = base_port;
pdata->index = index;
pdata->line = serial8250_register_8250_port(&uart);
if (pdata->line < 0)
return -ENODEV; return -ENODEV;
pnp_set_drvdata(dev, (void *)((long)line + 1)); pnp_set_drvdata(dev, pdata);
return 0; return 0;
} }
static void fintek_8250_remove(struct pnp_dev *dev) static void fintek_8250_remove(struct pnp_dev *dev)
{ {
long line = (long)pnp_get_drvdata(dev); struct fintek_8250 *pdata = pnp_get_drvdata(dev);
if (line) if (pdata)
serial8250_unregister_port(line - 1); serial8250_unregister_port(pdata->line);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state) static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
{ {
long line = (long)pnp_get_drvdata(dev); struct fintek_8250 *pdata = pnp_get_drvdata(dev);
if (!line) if (!pdata)
return -ENODEV; return -ENODEV;
serial8250_suspend_port(line - 1); serial8250_suspend_port(pdata->line);
return 0; return 0;
} }
static int fintek_8250_resume(struct pnp_dev *dev) static int fintek_8250_resume(struct pnp_dev *dev)
{ {
long line = (long)pnp_get_drvdata(dev); struct fintek_8250 *pdata = pnp_get_drvdata(dev);
if (!line) if (!pdata)
return -ENODEV; return -ENODEV;
serial8250_resume_port(line - 1); serial8250_resume_port(pdata->line);
return 0; return 0;
} }
#else #else
......
...@@ -252,7 +252,6 @@ MODULE_DEVICE_TABLE(of, of_match); ...@@ -252,7 +252,6 @@ MODULE_DEVICE_TABLE(of, of_match);
static struct platform_driver ingenic_uart_platform_driver = { static struct platform_driver ingenic_uart_platform_driver = {
.driver = { .driver = {
.name = "ingenic-uart", .name = "ingenic-uart",
.owner = THIS_MODULE,
.of_match_table = of_match, .of_match_table = of_match,
}, },
.probe = ingenic_uart_probe, .probe = ingenic_uart_probe,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -32,6 +33,11 @@ ...@@ -32,6 +33,11 @@
#define UART_ERRATA_i202_MDR1_ACCESS (1 << 0) #define UART_ERRATA_i202_MDR1_ACCESS (1 << 0)
#define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1) #define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1)
#define OMAP_DMA_TX_KICK (1 << 2) #define OMAP_DMA_TX_KICK (1 << 2)
/*
* See Advisory 21 in AM437x errata SPRZ408B, updated April 2015.
* The same errata is applicable to AM335x and DRA7x processors too.
*/
#define UART_ERRATA_CLOCK_DISABLE (1 << 3)
#define OMAP_UART_FCR_RX_TRIG 6 #define OMAP_UART_FCR_RX_TRIG 6
#define OMAP_UART_FCR_TX_TRIG 4 #define OMAP_UART_FCR_TX_TRIG 4
...@@ -53,6 +59,12 @@ ...@@ -53,6 +59,12 @@
#define OMAP_UART_MVR_MAJ_SHIFT 8 #define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f #define OMAP_UART_MVR_MIN_MASK 0x3f
/* SYSC register bitmasks */
#define OMAP_UART_SYSC_SOFTRESET (1 << 1)
/* SYSS register bitmasks */
#define OMAP_UART_SYSS_RESETDONE (1 << 0)
#define UART_TI752_TLR_TX 0 #define UART_TI752_TLR_TX 0
#define UART_TI752_TLR_RX 4 #define UART_TI752_TLR_RX 4
...@@ -100,6 +112,7 @@ struct omap8250_priv { ...@@ -100,6 +112,7 @@ struct omap8250_priv {
struct work_struct qos_work; struct work_struct qos_work;
struct uart_8250_dma omap8250_dma; struct uart_8250_dma omap8250_dma;
spinlock_t rx_dma_lock; spinlock_t rx_dma_lock;
bool rx_dma_broken;
}; };
static u32 uart_read(struct uart_8250_port *up, u32 reg) static u32 uart_read(struct uart_8250_port *up, u32 reg)
...@@ -232,6 +245,15 @@ static void omap8250_update_scr(struct uart_8250_port *up, ...@@ -232,6 +245,15 @@ static void omap8250_update_scr(struct uart_8250_port *up,
serial_out(up, UART_OMAP_SCR, priv->scr); serial_out(up, UART_OMAP_SCR, priv->scr);
} }
static void omap8250_update_mdr1(struct uart_8250_port *up,
struct omap8250_priv *priv)
{
if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS)
omap_8250_mdr1_errataset(up, priv);
else
serial_out(up, UART_OMAP_MDR1, priv->mdr1);
}
static void omap8250_restore_regs(struct uart_8250_port *up) static void omap8250_restore_regs(struct uart_8250_port *up)
{ {
struct omap8250_priv *priv = up->port.private_data; struct omap8250_priv *priv = up->port.private_data;
...@@ -282,11 +304,9 @@ static void omap8250_restore_regs(struct uart_8250_port *up) ...@@ -282,11 +304,9 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
serial_out(up, UART_XOFF1, priv->xoff); serial_out(up, UART_XOFF1, priv->xoff);
serial_out(up, UART_LCR, up->lcr); serial_out(up, UART_LCR, up->lcr);
/* need mode A for FCR */
if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS) omap8250_update_mdr1(up, priv);
omap_8250_mdr1_errataset(up, priv);
else
serial_out(up, UART_OMAP_MDR1, priv->mdr1);
up->port.ops->set_mctrl(&up->port, up->port.mctrl); up->port.ops->set_mctrl(&up->port, up->port.mctrl);
} }
...@@ -428,12 +448,9 @@ static void omap_8250_set_termios(struct uart_port *port, ...@@ -428,12 +448,9 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->efr |= UART_EFR_CTS; priv->efr |= UART_EFR_CTS;
} else if (up->port.flags & UPF_SOFT_FLOW) { } else if (up->port.flags & UPF_SOFT_FLOW) {
/* /*
* IXON Flag: * OMAP rx s/w flow control is borked; the transmitter remains
* Enable XON/XOFF flow control on input. * stuck off even if rx flow control is subsequently disabled
* Receiver compares XON1, XOFF1.
*/ */
if (termios->c_iflag & IXON)
priv->efr |= OMAP_UART_SW_RX;
/* /*
* IXOFF Flag: * IXOFF Flag:
...@@ -444,15 +461,6 @@ static void omap_8250_set_termios(struct uart_port *port, ...@@ -444,15 +461,6 @@ static void omap_8250_set_termios(struct uart_port *port,
up->port.status |= UPSTAT_AUTOXOFF; up->port.status |= UPSTAT_AUTOXOFF;
priv->efr |= OMAP_UART_SW_TX; priv->efr |= OMAP_UART_SW_TX;
} }
/*
* IXANY Flag:
* Enable any character to restart output.
* Operation resumes after receiving any
* character after recognition of the XOFF character
*/
if (termios->c_iflag & IXANY)
up->mcr |= UART_MCR_XONANY;
} }
omap8250_restore_regs(up); omap8250_restore_regs(up);
...@@ -530,14 +538,14 @@ static void omap_serial_fill_features_erratas(struct uart_8250_port *up, ...@@ -530,14 +538,14 @@ static void omap_serial_fill_features_erratas(struct uart_8250_port *up,
switch (revision) { switch (revision) {
case OMAP_UART_REV_46: case OMAP_UART_REV_46:
priv->habit = UART_ERRATA_i202_MDR1_ACCESS; priv->habit |= UART_ERRATA_i202_MDR1_ACCESS;
break; break;
case OMAP_UART_REV_52: case OMAP_UART_REV_52:
priv->habit = UART_ERRATA_i202_MDR1_ACCESS | priv->habit |= UART_ERRATA_i202_MDR1_ACCESS |
OMAP_UART_WER_HAS_TX_WAKEUP; OMAP_UART_WER_HAS_TX_WAKEUP;
break; break;
case OMAP_UART_REV_63: case OMAP_UART_REV_63:
priv->habit = UART_ERRATA_i202_MDR1_ACCESS | priv->habit |= UART_ERRATA_i202_MDR1_ACCESS |
OMAP_UART_WER_HAS_TX_WAKEUP; OMAP_UART_WER_HAS_TX_WAKEUP;
break; break;
default: default:
...@@ -754,6 +762,7 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p) ...@@ -754,6 +762,7 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
struct omap8250_priv *priv = p->port.private_data; struct omap8250_priv *priv = p->port.private_data;
struct uart_8250_dma *dma = p->dma; struct uart_8250_dma *dma = p->dma;
unsigned long flags; unsigned long flags;
int ret;
spin_lock_irqsave(&priv->rx_dma_lock, flags); spin_lock_irqsave(&priv->rx_dma_lock, flags);
...@@ -762,7 +771,9 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p) ...@@ -762,7 +771,9 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
return; return;
} }
dmaengine_pause(dma->rxchan); ret = dmaengine_pause(dma->rxchan);
if (WARN_ON_ONCE(ret))
priv->rx_dma_broken = true;
spin_unlock_irqrestore(&priv->rx_dma_lock, flags); spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
...@@ -806,6 +817,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) ...@@ -806,6 +817,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
break; break;
} }
if (priv->rx_dma_broken)
return -EINVAL;
spin_lock_irqsave(&priv->rx_dma_lock, flags); spin_lock_irqsave(&priv->rx_dma_lock, flags);
if (dma->rx_running) if (dma->rx_running)
...@@ -1054,6 +1068,20 @@ static int omap8250_no_handle_irq(struct uart_port *port) ...@@ -1054,6 +1068,20 @@ static int omap8250_no_handle_irq(struct uart_port *port)
return 0; return 0;
} }
static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;
static const u8 am4372_habit = UART_ERRATA_CLOCK_DISABLE;
static const struct of_device_id omap8250_dt_ids[] = {
{ .compatible = "ti,omap2-uart" },
{ .compatible = "ti,omap3-uart" },
{ .compatible = "ti,omap4-uart" },
{ .compatible = "ti,am3352-uart", .data = &am3352_habit, },
{ .compatible = "ti,am4372-uart", .data = &am4372_habit, },
{ .compatible = "ti,dra742-uart", .data = &am4372_habit, },
{},
};
MODULE_DEVICE_TABLE(of, omap8250_dt_ids);
static int omap8250_probe(struct platform_device *pdev) static int omap8250_probe(struct platform_device *pdev)
{ {
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
...@@ -1118,11 +1146,17 @@ static int omap8250_probe(struct platform_device *pdev) ...@@ -1118,11 +1146,17 @@ static int omap8250_probe(struct platform_device *pdev)
up.port.unthrottle = omap_8250_unthrottle; up.port.unthrottle = omap_8250_unthrottle;
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
const struct of_device_id *id;
ret = of_alias_get_id(pdev->dev.of_node, "serial"); ret = of_alias_get_id(pdev->dev.of_node, "serial");
of_property_read_u32(pdev->dev.of_node, "clock-frequency", of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&up.port.uartclk); &up.port.uartclk);
priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1);
id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev);
if (id && id->data)
priv->habit |= *(u8 *)id->data;
} else { } else {
ret = pdev->id; ret = pdev->id;
} }
...@@ -1180,6 +1214,11 @@ static int omap8250_probe(struct platform_device *pdev) ...@@ -1180,6 +1214,11 @@ static int omap8250_probe(struct platform_device *pdev)
if (of_machine_is_compatible("ti,am33xx")) if (of_machine_is_compatible("ti,am33xx"))
priv->habit |= OMAP_DMA_TX_KICK; priv->habit |= OMAP_DMA_TX_KICK;
/*
* pause is currently not supported atleast on omap-sdma
* and edma on most earlier kernels.
*/
priv->rx_dma_broken = true;
} }
} }
#endif #endif
...@@ -1257,17 +1296,46 @@ static int omap8250_lost_context(struct uart_8250_port *up) ...@@ -1257,17 +1296,46 @@ static int omap8250_lost_context(struct uart_8250_port *up)
{ {
u32 val; u32 val;
val = serial_in(up, UART_OMAP_MDR1); val = serial_in(up, UART_OMAP_SCR);
/* /*
* If we lose context, then MDR1 is set to its reset value which is * If we lose context, then SCR is set to its reset value of zero.
* UART_OMAP_MDR1_DISABLE. After set_termios() we set it either to 13x * After set_termios() we set bit 3 of SCR (TX_EMPTY_CTL_IT) to 1,
* or 16x but never to disable again. * among other bits, to never set the register back to zero again.
*/ */
if (val == UART_OMAP_MDR1_DISABLE) if (!val)
return 1; return 1;
return 0; return 0;
} }
/* TODO: in future, this should happen via API in drivers/reset/ */
static int omap8250_soft_reset(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
int timeout = 100;
int sysc;
int syss;
sysc = serial_in(up, UART_OMAP_SYSC);
/* softreset the UART */
sysc |= OMAP_UART_SYSC_SOFTRESET;
serial_out(up, UART_OMAP_SYSC, sysc);
/* By experiments, 1us enough for reset complete on AM335x */
do {
udelay(1);
syss = serial_in(up, UART_OMAP_SYSS);
} while (--timeout && !(syss & OMAP_UART_SYSS_RESETDONE));
if (!timeout) {
dev_err(dev, "timed out waiting for reset done\n");
return -ETIMEDOUT;
}
return 0;
}
static int omap8250_runtime_suspend(struct device *dev) static int omap8250_runtime_suspend(struct device *dev)
{ {
struct omap8250_priv *priv = dev_get_drvdata(dev); struct omap8250_priv *priv = dev_get_drvdata(dev);
...@@ -1285,7 +1353,18 @@ static int omap8250_runtime_suspend(struct device *dev) ...@@ -1285,7 +1353,18 @@ static int omap8250_runtime_suspend(struct device *dev)
return -EBUSY; return -EBUSY;
} }
if (up->dma) if (priv->habit & UART_ERRATA_CLOCK_DISABLE) {
int ret;
ret = omap8250_soft_reset(dev);
if (ret)
return ret;
/* Restore to UART mode after reset (for wakeup) */
omap8250_update_mdr1(up, priv);
}
if (up->dma && up->dma->rxchan)
omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
...@@ -1310,7 +1389,7 @@ static int omap8250_runtime_resume(struct device *dev) ...@@ -1310,7 +1389,7 @@ static int omap8250_runtime_resume(struct device *dev)
if (loss_cntx) if (loss_cntx)
omap8250_restore_regs(up); omap8250_restore_regs(up);
if (up->dma) if (up->dma && up->dma->rxchan)
omap_8250_rx_dma(up, 0); omap_8250_rx_dma(up, 0);
priv->latency = priv->calc_latency; priv->latency = priv->calc_latency;
...@@ -1367,14 +1446,6 @@ static const struct dev_pm_ops omap8250_dev_pm_ops = { ...@@ -1367,14 +1446,6 @@ static const struct dev_pm_ops omap8250_dev_pm_ops = {
.complete = omap8250_complete, .complete = omap8250_complete,
}; };
static const struct of_device_id omap8250_dt_ids[] = {
{ .compatible = "ti,omap2-uart" },
{ .compatible = "ti,omap3-uart" },
{ .compatible = "ti,omap4-uart" },
{},
};
MODULE_DEVICE_TABLE(of, omap8250_dt_ids);
static struct platform_driver omap8250_platform_driver = { static struct platform_driver omap8250_platform_driver = {
.driver = { .driver = {
.name = "omap8250", .name = "omap8250",
......
...@@ -1417,6 +1417,10 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, ...@@ -1417,6 +1417,10 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
writel(reg, p->membase + BYT_PRV_CLK); writel(reg, p->membase + BYT_PRV_CLK);
p->status &= ~UPSTAT_AUTOCTS;
if (termios->c_cflag & CRTSCTS)
p->status |= UPSTAT_AUTOCTS;
serial8250_do_set_termios(p, termios, old); serial8250_do_set_termios(p, termios, old);
} }
...@@ -1685,11 +1689,65 @@ pci_brcm_trumanage_setup(struct serial_private *priv, ...@@ -1685,11 +1689,65 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
return ret; return ret;
} }
/* RTS will control by MCR if this bit is 0 */
#define FINTEK_RTS_CONTROL_BY_HW BIT(4)
/* only worked with FINTEK_RTS_CONTROL_BY_HW on */
#define FINTEK_RTS_INVERT BIT(5)
/* We should do proper H/W transceiver setting before change to RS485 mode */
static int pci_fintek_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
u8 setting;
u8 *index = (u8 *) port->private_data;
struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev,
dev);
pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);
if (!rs485)
rs485 = &port->rs485;
else if (rs485->flags & SER_RS485_ENABLED)
memset(rs485->padding, 0, sizeof(rs485->padding));
else
memset(rs485, 0, sizeof(*rs485));
/* F81504/508/512 not support RTS delay before or after send */
rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable RTS H/W control mode */
setting |= FINTEK_RTS_CONTROL_BY_HW;
if (rs485->flags & SER_RS485_RTS_ON_SEND) {
/* RTS driving high on TX */
setting &= ~FINTEK_RTS_INVERT;
} else {
/* RTS driving low on TX */
setting |= FINTEK_RTS_INVERT;
}
rs485->delay_rts_after_send = 0;
rs485->delay_rts_before_send = 0;
} else {
/* Disable RTS H/W control mode */
setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT);
}
pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting);
if (rs485 != &port->rs485)
port->rs485 = *rs485;
return 0;
}
static int pci_fintek_setup(struct serial_private *priv, static int pci_fintek_setup(struct serial_private *priv,
const struct pciserial_board *board, const struct pciserial_board *board,
struct uart_8250_port *port, int idx) struct uart_8250_port *port, int idx)
{ {
struct pci_dev *pdev = priv->dev; struct pci_dev *pdev = priv->dev;
u8 *data;
u8 config_base; u8 config_base;
u16 iobase; u16 iobase;
...@@ -1702,6 +1760,15 @@ static int pci_fintek_setup(struct serial_private *priv, ...@@ -1702,6 +1760,15 @@ static int pci_fintek_setup(struct serial_private *priv,
port->port.iotype = UPIO_PORT; port->port.iotype = UPIO_PORT;
port->port.iobase = iobase; port->port.iobase = iobase;
port->port.rs485_config = pci_fintek_rs485_config;
data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* preserve index in PCI configuration space */
*data = idx;
port->port.private_data = data;
return 0; return 0;
} }
...@@ -1712,6 +1779,8 @@ static int pci_fintek_init(struct pci_dev *dev) ...@@ -1712,6 +1779,8 @@ static int pci_fintek_init(struct pci_dev *dev)
u32 max_port, i; u32 max_port, i;
u32 bar_data[3]; u32 bar_data[3];
u8 config_base; u8 config_base;
struct serial_private *priv = pci_get_drvdata(dev);
struct uart_8250_port *port;
switch (dev->device) { switch (dev->device) {
case 0x1104: /* 4 ports */ case 0x1104: /* 4 ports */
...@@ -1752,6 +1821,19 @@ static int pci_fintek_init(struct pci_dev *dev) ...@@ -1752,6 +1821,19 @@ static int pci_fintek_init(struct pci_dev *dev)
(u8)((iobase & 0xff00) >> 8)); (u8)((iobase & 0xff00) >> 8));
pci_write_config_byte(dev, config_base + 0x06, dev->irq); pci_write_config_byte(dev, config_base + 0x06, dev->irq);
if (priv) {
/* re-apply RS232/485 mode when
* pciserial_resume_ports()
*/
port = serial8250_get_port(priv->line[i]);
pci_fintek_rs485_config(&port->port, NULL);
} else {
/* First init without port data
* force init to RS232 Mode
*/
pci_write_config_byte(dev, config_base + 0x07, 0x01);
}
} }
return max_port; return max_port;
...@@ -2017,6 +2099,12 @@ pci_wch_ch38x_setup(struct serial_private *priv, ...@@ -2017,6 +2099,12 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
#define PCI_VENDOR_ID_PERICOM 0x12D8
#define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951
#define PCI_DEVICE_ID_PERICOM_PI7C9X7952 0x7952
#define PCI_DEVICE_ID_PERICOM_PI7C9X7954 0x7954
#define PCI_DEVICE_ID_PERICOM_PI7C9X7958 0x7958
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */ /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588
...@@ -2331,27 +2419,12 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { ...@@ -2331,27 +2419,12 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
* Pericom * Pericom
*/ */
{ {
.vendor = 0x12d8, .vendor = PCI_VENDOR_ID_PERICOM,
.device = 0x7952, .device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_pericom_setup,
},
{
.vendor = 0x12d8,
.device = 0x7954,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_pericom_setup,
},
{
.vendor = 0x12d8,
.device = 0x7958,
.subvendor = PCI_ANY_ID, .subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.setup = pci_pericom_setup, .setup = pci_pericom_setup,
}, },
/* /*
* PLX * PLX
*/ */
...@@ -3056,6 +3129,10 @@ enum pci_board_num_t { ...@@ -3056,6 +3129,10 @@ enum pci_board_num_t {
pbn_fintek_8, pbn_fintek_8,
pbn_fintek_12, pbn_fintek_12,
pbn_wch384_4, pbn_wch384_4,
pbn_pericom_PI7C9X7951,
pbn_pericom_PI7C9X7952,
pbn_pericom_PI7C9X7954,
pbn_pericom_PI7C9X7958,
}; };
/* /*
...@@ -3881,7 +3958,6 @@ static struct pciserial_board pci_boards[] = { ...@@ -3881,7 +3958,6 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 115200, .base_baud = 115200,
.first_offset = 0x40, .first_offset = 0x40,
}, },
[pbn_wch384_4] = { [pbn_wch384_4] = {
.flags = FL_BASE0, .flags = FL_BASE0,
.num_ports = 4, .num_ports = 4,
...@@ -3889,6 +3965,33 @@ static struct pciserial_board pci_boards[] = { ...@@ -3889,6 +3965,33 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 8, .uart_offset = 8,
.first_offset = 0xC0, .first_offset = 0xC0,
}, },
/*
* Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
*/
[pbn_pericom_PI7C9X7951] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 921600,
.uart_offset = 0x8,
},
[pbn_pericom_PI7C9X7952] = {
.flags = FL_BASE0,
.num_ports = 2,
.base_baud = 921600,
.uart_offset = 0x8,
},
[pbn_pericom_PI7C9X7954] = {
.flags = FL_BASE0,
.num_ports = 4,
.base_baud = 921600,
.uart_offset = 0x8,
},
[pbn_pericom_PI7C9X7958] = {
.flags = FL_BASE0,
.num_ports = 8,
.base_baud = 921600,
.uart_offset = 0x8,
},
}; };
static const struct pci_device_id blacklist[] = { static const struct pci_device_id blacklist[] = {
...@@ -5153,6 +5256,25 @@ static struct pci_device_id serial_pci_tbl[] = { ...@@ -5153,6 +5256,25 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
0, 0,
0, pbn_exar_XR17V8358 }, 0, pbn_exar_XR17V8358 },
/*
* Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
*/
{ PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951,
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_pericom_PI7C9X7951 },
{ PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952,
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_pericom_PI7C9X7952 },
{ PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954,
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_pericom_PI7C9X7954 },
{ PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958,
PCI_ANY_ID, PCI_ANY_ID,
0,
0, pbn_pericom_PI7C9X7958 },
/* /*
* Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
*/ */
......
...@@ -41,6 +41,12 @@ static const struct pnp_device_id pnp_dev_table[] = { ...@@ -41,6 +41,12 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "AEI1240", 0 }, { "AEI1240", 0 },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */ /* Rockwell 56K ACF II Fax+Data+Voice Modem */
{ "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ }, { "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ },
/*
* ALi Fast Infrared Controller
* Native driver (ali-ircc) is broken so at least
* it can be used with irtty-sir.
*/
{ "ALI5123", 0 },
/* AZT3005 PnP SOUND DEVICE */ /* AZT3005 PnP SOUND DEVICE */
{ "AZT4001", 0 }, { "AZT4001", 0 },
/* Best Data Products Inc. Smart One 336F PnP Modem */ /* Best Data Products Inc. Smart One 336F PnP Modem */
...@@ -364,6 +370,11 @@ static const struct pnp_device_id pnp_dev_table[] = { ...@@ -364,6 +370,11 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* Winbond CIR port, should not be probed. We should keep track /* Winbond CIR port, should not be probed. We should keep track
of it to prevent the legacy serial driver from probing it */ of it to prevent the legacy serial driver from probing it */
{ "WEC1022", CIR_PORT }, { "WEC1022", CIR_PORT },
/*
* SMSC IrCC SIR/FIR port, should not be probed by serial driver
* as well so its own driver can bind to it.
*/
{ "SMCF010", CIR_PORT },
{ "", 0 } { "", 0 }
}; };
......
This diff is collapsed.
...@@ -218,6 +218,7 @@ static int uniphier_uart_probe(struct platform_device *pdev) ...@@ -218,6 +218,7 @@ static int uniphier_uart_probe(struct platform_device *pdev)
ret = serial8250_register_8250_port(&up); ret = serial8250_register_8250_port(&up);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to register 8250 port\n"); dev_err(dev, "failed to register 8250 port\n");
clk_disable_unprepare(priv->clk);
return ret; return ret;
} }
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
# Makefile for the 8250 serial device drivers. # Makefile for the 8250 serial device drivers.
# #
obj-$(CONFIG_SERIAL_8250) += 8250.o obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250-y := 8250_core.o 8250-y := 8250_core.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
8250-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o 8250_base-y := 8250_port.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
......
...@@ -47,12 +47,12 @@ config SERIAL_AMBA_PL010_CONSOLE ...@@ -47,12 +47,12 @@ config SERIAL_AMBA_PL010_CONSOLE
config SERIAL_AMBA_PL011 config SERIAL_AMBA_PL011
tristate "ARM AMBA PL011 serial port support" tristate "ARM AMBA PL011 serial port support"
depends on ARM_AMBA depends on ARM_AMBA || SOC_ZX296702
select SERIAL_CORE select SERIAL_CORE
help help
This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have
an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M
here. here. Say Y or M if you have SOC_ZX296702.
If unsure, say N. If unsure, say N.
...@@ -594,7 +594,7 @@ config SERIAL_IMX_CONSOLE ...@@ -594,7 +594,7 @@ config SERIAL_IMX_CONSOLE
config SERIAL_UARTLITE config SERIAL_UARTLITE
tristate "Xilinx uartlite serial port support" tristate "Xilinx uartlite serial port support"
depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE || ARCH_ZYNQ depends on HAS_IOMEM
select SERIAL_CORE select SERIAL_CORE
help help
Say Y here if you want to use the Xilinx uartlite serial controller. Say Y here if you want to use the Xilinx uartlite serial controller.
...@@ -1067,6 +1067,7 @@ config SERIAL_ETRAXFS ...@@ -1067,6 +1067,7 @@ config SERIAL_ETRAXFS
bool "ETRAX FS serial port support" bool "ETRAX FS serial port support"
depends on ETRAX_ARCH_V32 && OF depends on ETRAX_ARCH_V32 && OF
select SERIAL_CORE select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
config SERIAL_ETRAXFS_CONSOLE config SERIAL_ETRAXFS_CONSOLE
bool "ETRAX FS serial console support" bool "ETRAX FS serial console support"
...@@ -1376,7 +1377,8 @@ config SERIAL_ALTERA_UART_CONSOLE ...@@ -1376,7 +1377,8 @@ config SERIAL_ALTERA_UART_CONSOLE
config SERIAL_IFX6X60 config SERIAL_IFX6X60
tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
depends on GPIOLIB && SPI && HAS_DMA depends on GPIOLIB || COMPILE_TEST
depends on SPI && HAS_DMA
help help
Support for the IFX6x60 modem devices on Intel MID platforms. Support for the IFX6x60 modem devices on Intel MID platforms.
......
This diff is collapsed.
This diff is collapsed.
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <hwregs/ser_defs.h> #include <hwregs/ser_defs.h>
#include "serial_mctrl_gpio.h"
#define DRV_NAME "etraxfs-uart" #define DRV_NAME "etraxfs-uart"
#define UART_NR CONFIG_ETRAX_SERIAL_PORTS #define UART_NR CONFIG_ETRAX_SERIAL_PORTS
...@@ -28,10 +30,7 @@ struct uart_cris_port { ...@@ -28,10 +30,7 @@ struct uart_cris_port {
void __iomem *regi_ser; void __iomem *regi_ser;
struct gpio_desc *dtr_pin; struct mctrl_gpios *gpios;
struct gpio_desc *dsr_pin;
struct gpio_desc *ri_pin;
struct gpio_desc *cd_pin;
int write_ongoing; int write_ongoing;
}; };
...@@ -112,17 +111,10 @@ cris_console_setup(struct console *co, char *options) ...@@ -112,17 +111,10 @@ cris_console_setup(struct console *co, char *options)
return 0; return 0;
} }
static struct tty_driver *cris_console_device(struct console *co, int *index)
{
struct uart_driver *p = co->data;
*index = co->index;
return p->tty_driver;
}
static struct console cris_console = { static struct console cris_console = {
.name = "ttyS", .name = "ttyS",
.write = cris_console_write, .write = cris_console_write,
.device = cris_console_device, .device = uart_console_device,
.setup = cris_console_setup, .setup = cris_console_setup,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
.index = -1, .index = -1,
...@@ -373,14 +365,6 @@ static void etraxfs_uart_stop_rx(struct uart_port *port) ...@@ -373,14 +365,6 @@ static void etraxfs_uart_stop_rx(struct uart_port *port)
REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl); REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
} }
static void etraxfs_uart_enable_ms(struct uart_port *port)
{
}
static void check_modem_status(struct uart_cris_port *up)
{
}
static unsigned int etraxfs_uart_tx_empty(struct uart_port *port) static unsigned int etraxfs_uart_tx_empty(struct uart_port *port)
{ {
struct uart_cris_port *up = (struct uart_cris_port *)port; struct uart_cris_port *up = (struct uart_cris_port *)port;
...@@ -404,21 +388,9 @@ static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port) ...@@ -404,21 +388,9 @@ static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port)
ret = 0; ret = 0;
if (crisv32_serial_get_rts(up)) if (crisv32_serial_get_rts(up))
ret |= TIOCM_RTS; ret |= TIOCM_RTS;
/* DTR is active low */
if (up->dtr_pin && !gpiod_get_raw_value(up->dtr_pin))
ret |= TIOCM_DTR;
/* CD is active low */
if (up->cd_pin && !gpiod_get_raw_value(up->cd_pin))
ret |= TIOCM_CD;
/* RI is active low */
if (up->ri_pin && !gpiod_get_raw_value(up->ri_pin))
ret |= TIOCM_RI;
/* DSR is active low */
if (up->dsr_pin && !gpiod_get_raw_value(up->dsr_pin))
ret |= TIOCM_DSR;
if (crisv32_serial_get_cts(up)) if (crisv32_serial_get_cts(up))
ret |= TIOCM_CTS; ret |= TIOCM_CTS;
return ret; return mctrl_gpio_get(up->gpios, &ret);
} }
static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
...@@ -426,15 +398,7 @@ static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) ...@@ -426,15 +398,7 @@ static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
struct uart_cris_port *up = (struct uart_cris_port *)port; struct uart_cris_port *up = (struct uart_cris_port *)port;
crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0); crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0);
/* DTR is active low */ mctrl_gpio_set(up->gpios, mctrl);
if (up->dtr_pin)
gpiod_set_raw_value(up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1);
/* RI is active low */
if (up->ri_pin)
gpiod_set_raw_value(up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1);
/* CD is active low */
if (up->cd_pin)
gpiod_set_raw_value(up->cd_pin, mctrl & TIOCM_CD ? 0 : 1);
} }
static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state) static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state)
...@@ -598,7 +562,6 @@ ser_interrupt(int irq, void *dev_id) ...@@ -598,7 +562,6 @@ ser_interrupt(int irq, void *dev_id)
receive_chars_no_dma(up); receive_chars_no_dma(up);
handled = 1; handled = 1;
} }
check_modem_status(up);
if (masked_intr.tr_rdy) { if (masked_intr.tr_rdy) {
transmit_chars_no_dma(up); transmit_chars_no_dma(up);
...@@ -862,7 +825,6 @@ static const struct uart_ops etraxfs_uart_pops = { ...@@ -862,7 +825,6 @@ static const struct uart_ops etraxfs_uart_pops = {
.start_tx = etraxfs_uart_start_tx, .start_tx = etraxfs_uart_start_tx,
.send_xchar = etraxfs_uart_send_xchar, .send_xchar = etraxfs_uart_send_xchar,
.stop_rx = etraxfs_uart_stop_rx, .stop_rx = etraxfs_uart_stop_rx,
.enable_ms = etraxfs_uart_enable_ms,
.break_ctl = etraxfs_uart_break_ctl, .break_ctl = etraxfs_uart_break_ctl,
.startup = etraxfs_uart_startup, .startup = etraxfs_uart_startup,
.shutdown = etraxfs_uart_shutdown, .shutdown = etraxfs_uart_shutdown,
...@@ -930,11 +892,12 @@ static int etraxfs_uart_probe(struct platform_device *pdev) ...@@ -930,11 +892,12 @@ static int etraxfs_uart_probe(struct platform_device *pdev)
up->irq = irq_of_parse_and_map(np, 0); up->irq = irq_of_parse_and_map(np, 0);
up->regi_ser = of_iomap(np, 0); up->regi_ser = of_iomap(np, 0);
up->dtr_pin = devm_gpiod_get_optional(&pdev->dev, "dtr");
up->dsr_pin = devm_gpiod_get_optional(&pdev->dev, "dsr");
up->ri_pin = devm_gpiod_get_optional(&pdev->dev, "ri");
up->cd_pin = devm_gpiod_get_optional(&pdev->dev, "cd");
up->port.dev = &pdev->dev; up->port.dev = &pdev->dev;
up->gpios = mctrl_gpio_init(&pdev->dev, 0);
if (IS_ERR(up->gpios))
return PTR_ERR(up->gpios);
cris_serial_port_init(&up->port, dev_id); cris_serial_port_init(&up->port, dev_id);
etraxfs_uart_ports[dev_id] = up; etraxfs_uart_ports[dev_id] = up;
......
...@@ -216,6 +216,8 @@ struct imx_port { ...@@ -216,6 +216,8 @@ struct imx_port {
unsigned int tx_bytes; unsigned int tx_bytes;
unsigned int dma_tx_nents; unsigned int dma_tx_nents;
wait_queue_head_t dma_wait; wait_queue_head_t dma_wait;
unsigned int saved_reg[10];
bool context_saved;
}; };
struct imx_port_ucrs { struct imx_port_ucrs {
...@@ -700,7 +702,8 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) ...@@ -700,7 +702,8 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
if (sport->port.ignore_status_mask & URXD_DUMMY_READ) if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
goto out; goto out;
tty_insert_flip_char(port, rx, flg); if (tty_insert_flip_char(port, rx, flg) == 0)
sport->port.icount.buf_overrun++;
} }
out: out:
...@@ -766,7 +769,6 @@ static irqreturn_t imx_int(int irq, void *dev_id) ...@@ -766,7 +769,6 @@ static irqreturn_t imx_int(int irq, void *dev_id)
writel(USR1_AWAKE, sport->port.membase + USR1); writel(USR1_AWAKE, sport->port.membase + USR1);
if (sts2 & USR2_ORE) { if (sts2 & USR2_ORE) {
dev_err(sport->port.dev, "Rx FIFO overrun\n");
sport->port.icount.overrun++; sport->port.icount.overrun++;
writel(USR2_ORE, sport->port.membase + USR2); writel(USR2_ORE, sport->port.membase + USR2);
} }
...@@ -921,8 +923,13 @@ static void dma_rx_callback(void *data) ...@@ -921,8 +923,13 @@ static void dma_rx_callback(void *data)
dev_dbg(sport->port.dev, "We get %d bytes.\n", count); dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
if (count) { if (count) {
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
tty_insert_flip_string(port, sport->rx_buf, count); int bytes = tty_insert_flip_string(port, sport->rx_buf,
count);
if (bytes != count)
sport->port.icount.buf_overrun++;
}
tty_flip_buffer_push(port); tty_flip_buffer_push(port);
start_rx_dma(sport); start_rx_dma(sport);
...@@ -1624,12 +1631,12 @@ imx_console_write(struct console *co, const char *s, unsigned int count) ...@@ -1624,12 +1631,12 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
int locked = 1; int locked = 1;
int retval; int retval;
retval = clk_enable(sport->clk_per); retval = clk_prepare_enable(sport->clk_per);
if (retval) if (retval)
return; return;
retval = clk_enable(sport->clk_ipg); retval = clk_prepare_enable(sport->clk_ipg);
if (retval) { if (retval) {
clk_disable(sport->clk_per); clk_disable_unprepare(sport->clk_per);
return; return;
} }
...@@ -1668,8 +1675,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count) ...@@ -1668,8 +1675,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
if (locked) if (locked)
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock_irqrestore(&sport->port.lock, flags);
clk_disable(sport->clk_ipg); clk_disable_unprepare(sport->clk_ipg);
clk_disable(sport->clk_per); clk_disable_unprepare(sport->clk_per);
} }
/* /*
...@@ -1770,14 +1777,6 @@ imx_console_setup(struct console *co, char *options) ...@@ -1770,14 +1777,6 @@ imx_console_setup(struct console *co, char *options)
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
clk_disable(sport->clk_ipg);
if (retval) {
clk_unprepare(sport->clk_ipg);
goto error_console;
}
retval = clk_prepare(sport->clk_per);
if (retval)
clk_disable_unprepare(sport->clk_ipg); clk_disable_unprepare(sport->clk_ipg);
error_console: error_console:
...@@ -1810,36 +1809,6 @@ static struct uart_driver imx_reg = { ...@@ -1810,36 +1809,6 @@ static struct uart_driver imx_reg = {
.cons = IMX_CONSOLE, .cons = IMX_CONSOLE,
}; };
static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
{
struct imx_port *sport = platform_get_drvdata(dev);
unsigned int val;
/* enable wakeup from i.MX UART */
val = readl(sport->port.membase + UCR3);
val |= UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
uart_suspend_port(&imx_reg, &sport->port);
return 0;
}
static int serial_imx_resume(struct platform_device *dev)
{
struct imx_port *sport = platform_get_drvdata(dev);
unsigned int val;
/* disable wakeup from i.MX UART */
val = readl(sport->port.membase + UCR3);
val &= ~UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
uart_resume_port(&imx_reg, &sport->port);
return 0;
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
/* /*
* This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it
...@@ -1901,7 +1870,7 @@ static int serial_imx_probe(struct platform_device *pdev) ...@@ -1901,7 +1870,7 @@ static int serial_imx_probe(struct platform_device *pdev)
{ {
struct imx_port *sport; struct imx_port *sport;
void __iomem *base; void __iomem *base;
int ret = 0; int ret = 0, reg;
struct resource *res; struct resource *res;
int txirq, rxirq, rtsirq; int txirq, rxirq, rtsirq;
...@@ -1956,6 +1925,19 @@ static int serial_imx_probe(struct platform_device *pdev) ...@@ -1956,6 +1925,19 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->port.uartclk = clk_get_rate(sport->clk_per); sport->port.uartclk = clk_get_rate(sport->clk_per);
/* For register access, we only need to enable the ipg clock. */
ret = clk_prepare_enable(sport->clk_ipg);
if (ret)
return ret;
/* Disable interrupts before requesting them */
reg = readl_relaxed(sport->port.membase + UCR1);
reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN |
UCR1_TXMPTYEN | UCR1_RTSDEN);
writel_relaxed(reg, sport->port.membase + UCR1);
clk_disable_unprepare(sport->clk_ipg);
/* /*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
* chips only have one interrupt. * chips only have one interrupt.
...@@ -1991,16 +1973,135 @@ static int serial_imx_remove(struct platform_device *pdev) ...@@ -1991,16 +1973,135 @@ static int serial_imx_remove(struct platform_device *pdev)
return uart_remove_one_port(&imx_reg, &sport->port); return uart_remove_one_port(&imx_reg, &sport->port);
} }
static void serial_imx_restore_context(struct imx_port *sport)
{
if (!sport->context_saved)
return;
writel(sport->saved_reg[4], sport->port.membase + UFCR);
writel(sport->saved_reg[5], sport->port.membase + UESC);
writel(sport->saved_reg[6], sport->port.membase + UTIM);
writel(sport->saved_reg[7], sport->port.membase + UBIR);
writel(sport->saved_reg[8], sport->port.membase + UBMR);
writel(sport->saved_reg[9], sport->port.membase + IMX21_UTS);
writel(sport->saved_reg[0], sport->port.membase + UCR1);
writel(sport->saved_reg[1] | UCR2_SRST, sport->port.membase + UCR2);
writel(sport->saved_reg[2], sport->port.membase + UCR3);
writel(sport->saved_reg[3], sport->port.membase + UCR4);
sport->context_saved = false;
}
static void serial_imx_save_context(struct imx_port *sport)
{
/* Save necessary regs */
sport->saved_reg[0] = readl(sport->port.membase + UCR1);
sport->saved_reg[1] = readl(sport->port.membase + UCR2);
sport->saved_reg[2] = readl(sport->port.membase + UCR3);
sport->saved_reg[3] = readl(sport->port.membase + UCR4);
sport->saved_reg[4] = readl(sport->port.membase + UFCR);
sport->saved_reg[5] = readl(sport->port.membase + UESC);
sport->saved_reg[6] = readl(sport->port.membase + UTIM);
sport->saved_reg[7] = readl(sport->port.membase + UBIR);
sport->saved_reg[8] = readl(sport->port.membase + UBMR);
sport->saved_reg[9] = readl(sport->port.membase + IMX21_UTS);
sport->context_saved = true;
}
static void serial_imx_enable_wakeup(struct imx_port *sport, bool on)
{
unsigned int val;
val = readl(sport->port.membase + UCR3);
if (on)
val |= UCR3_AWAKEN;
else
val &= ~UCR3_AWAKEN;
writel(val, sport->port.membase + UCR3);
val = readl(sport->port.membase + UCR1);
if (on)
val |= UCR1_RTSDEN;
else
val &= ~UCR1_RTSDEN;
writel(val, sport->port.membase + UCR1);
}
static int imx_serial_port_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
int ret;
ret = clk_enable(sport->clk_ipg);
if (ret)
return ret;
serial_imx_save_context(sport);
clk_disable(sport->clk_ipg);
return 0;
}
static int imx_serial_port_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
int ret;
ret = clk_enable(sport->clk_ipg);
if (ret)
return ret;
serial_imx_restore_context(sport);
clk_disable(sport->clk_ipg);
return 0;
}
static int imx_serial_port_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
/* enable wakeup from i.MX UART */
serial_imx_enable_wakeup(sport, true);
uart_suspend_port(&imx_reg, &sport->port);
return 0;
}
static int imx_serial_port_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
/* disable wakeup from i.MX UART */
serial_imx_enable_wakeup(sport, false);
uart_resume_port(&imx_reg, &sport->port);
return 0;
}
static const struct dev_pm_ops imx_serial_port_pm_ops = {
.suspend_noirq = imx_serial_port_suspend_noirq,
.resume_noirq = imx_serial_port_resume_noirq,
.suspend = imx_serial_port_suspend,
.resume = imx_serial_port_resume,
};
static struct platform_driver serial_imx_driver = { static struct platform_driver serial_imx_driver = {
.probe = serial_imx_probe, .probe = serial_imx_probe,
.remove = serial_imx_remove, .remove = serial_imx_remove,
.suspend = serial_imx_suspend,
.resume = serial_imx_resume,
.id_table = imx_uart_devtype, .id_table = imx_uart_devtype,
.driver = { .driver = {
.name = "imx-uart", .name = "imx-uart",
.of_match_table = imx_uart_dt_ids, .of_match_table = imx_uart_dt_ids,
.pm = &imx_serial_port_pm_ops,
}, },
}; };
......
This diff is collapsed.
This diff is collapsed.
...@@ -239,8 +239,9 @@ static int mpc52xx_psc_tx_rdy(struct uart_port *port) ...@@ -239,8 +239,9 @@ static int mpc52xx_psc_tx_rdy(struct uart_port *port)
static int mpc52xx_psc_tx_empty(struct uart_port *port) static int mpc52xx_psc_tx_empty(struct uart_port *port)
{ {
return in_be16(&PSC(port)->mpc52xx_psc_status) u16 sts = in_be16(&PSC(port)->mpc52xx_psc_status);
& MPC52xx_PSC_SR_TXEMP;
return (sts & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
} }
static void mpc52xx_psc_start_tx(struct uart_port *port) static void mpc52xx_psc_start_tx(struct uart_port *port)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment