Commit 5bd4af34 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull tty/serial updates from Greg KH:
 "Here is the big tty and serial pull request for 4.20-rc1

  Lots of little things here, including a merge from the SPI tree in
  order to keep things simpler for everyone to sync around for one
  platform.

  Major stuff is:

   - tty buffer clearing after use

   - atmel_serial fixes and additions

   - xilinx uart driver updates

  and of course, lots of tiny fixes and additions to individual serial
  drivers.

  All of these have been in linux-next with no reported issues for a
  while"

* tag 'tty-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (66 commits)
  of: base: Change logic in of_alias_get_alias_list()
  of: base: Fix english spelling in of_alias_get_alias_list()
  serial: sh-sci: do not warn if DMA transfers are not supported
  serial: uartps: Do not allow use aliases >= MAX_UART_INSTANCES
  tty: check name length in tty_find_polling_driver()
  serial: sh-sci: Add r8a77990 support
  tty: wipe buffer if not echoing data
  tty: wipe buffer.
  serial: fsl_lpuart: Remove the alias node dependence
  TTY: sn_console: Replace spin_is_locked() with spin_trylock()
  Revert "serial:serial_core: Allow use of CTS for PPS line discipline"
  serial: 8250_uniphier: add auto-flow-control support
  serial: 8250_uniphier: flatten probe function
  serial: 8250_uniphier: remove unused "fifo-size" property
  dt-bindings: serial: sh-sci: Document r8a7744 bindings
  serial: uartps: Fix missing unlock on error in cdns_get_id()
  tty/serial: atmel: add ISO7816 support
  tty/serial_core: add ISO7816 infrastructure
  serial:serial_core: Allow use of CTS for PPS line discipline
  serial: docs: Fix filename for serial reference implementation
  ...
parents 738b04fb 59eaeba6
...@@ -14,6 +14,10 @@ Required properties: ...@@ -14,6 +14,10 @@ Required properties:
- "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART. - "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART.
- "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB compatible UART. - "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB compatible UART.
- "renesas,hscif-r8a7743" for R8A7743 (RZ/G1M) HSCIF compatible UART. - "renesas,hscif-r8a7743" for R8A7743 (RZ/G1M) HSCIF compatible UART.
- "renesas,scif-r8a7744" for R8A7744 (RZ/G1N) SCIF compatible UART.
- "renesas,scifa-r8a7744" for R8A7744 (RZ/G1N) SCIFA compatible UART.
- "renesas,scifb-r8a7744" for R8A7744 (RZ/G1N) SCIFB compatible UART.
- "renesas,hscif-r8a7744" for R8A7744 (RZ/G1N) HSCIF compatible UART.
- "renesas,scif-r8a7745" for R8A7745 (RZ/G1E) SCIF compatible UART. - "renesas,scif-r8a7745" for R8A7745 (RZ/G1E) SCIF compatible UART.
- "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART. - "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
- "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART. - "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
...@@ -50,6 +54,8 @@ Required properties: ...@@ -50,6 +54,8 @@ Required properties:
- "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF compatible UART. - "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF compatible UART.
- "renesas,scif-r8a77980" for R8A77980 (R-Car V3H) SCIF compatible UART. - "renesas,scif-r8a77980" for R8A77980 (R-Car V3H) SCIF compatible UART.
- "renesas,hscif-r8a77980" for R8A77980 (R-Car V3H) HSCIF compatible UART. - "renesas,hscif-r8a77980" for R8A77980 (R-Car V3H) HSCIF compatible UART.
- "renesas,scif-r8a77990" for R8A77990 (R-Car E3) SCIF compatible UART.
- "renesas,hscif-r8a77990" for R8A77990 (R-Car E3) HSCIF compatible UART.
- "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART. - "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART.
- "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART. - "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART.
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
......
...@@ -7,7 +7,7 @@ Required properties: ...@@ -7,7 +7,7 @@ Required properties:
- clocks: phandle to the input clock. - clocks: phandle to the input clock.
Optional properties: Optional properties:
- fifo-size: the RX/TX FIFO size. Defaults to 64 if not specified. -auto-flow-control: enable automatic flow control support.
Example: Example:
aliases { aliases {
...@@ -19,5 +19,4 @@ Example: ...@@ -19,5 +19,4 @@ Example:
reg = <0x54006800 0x40>; reg = <0x54006800 0x40>;
interrupts = <0 33 4>; interrupts = <0 33 4>;
clocks = <&uart_clk>; clocks = <&uart_clk>;
fifo-size = <64>;
}; };
...@@ -7,7 +7,7 @@ This document is meant as a brief overview of some aspects of the new serial ...@@ -7,7 +7,7 @@ This document is meant as a brief overview of some aspects of the new serial
driver. It is not complete, any questions you have should be directed to driver. It is not complete, any questions you have should be directed to
<rmk@arm.linux.org.uk> <rmk@arm.linux.org.uk>
The reference implementation is contained within amba_pl011.c. The reference implementation is contained within amba-pl011.c.
......
ISO7816 SERIAL COMMUNICATIONS
1. INTRODUCTION
ISO/IEC7816 is a series of standards specifying integrated circuit cards (ICC)
also known as smart cards.
2. HARDWARE-RELATED CONSIDERATIONS
Some CPUs/UARTs (e.g., Microchip AT91) contain a built-in mode capable of
handling communication with a smart card.
For these microcontrollers, the Linux driver should be made capable of
working in both modes, and proper ioctls (see later) should be made
available at user-level to allow switching from one mode to the other, and
vice versa.
3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL
The Linux kernel provides the serial_iso7816 structure (see [1]) to handle
ISO7816 communications. This data structure is used to set and configure
ISO7816 parameters in ioctls.
Any driver for devices capable of working both as RS232 and ISO7816 should
implement the iso7816_config callback in the uart_port structure. The
serial_core calls iso7816_config to do the device specific part in response
to TIOCGISO7816 and TIOCSISO7816 ioctls (see below). The iso7816_config
callback receives a pointer to struct serial_iso7816.
4. USAGE FROM USER-LEVEL
From user-level, ISO7816 configuration can be get/set using the previous
ioctls. For instance, to set ISO7816 you can use the following code:
#include <linux/serial.h>
/* Include definition for ISO7816 ioctls: TIOCSISO7816 and TIOCGISO7816 */
#include <sys/ioctl.h>
/* Open your specific device (e.g., /dev/mydevice): */
int fd = open ("/dev/mydevice", O_RDWR);
if (fd < 0) {
/* Error handling. See errno. */
}
struct serial_iso7816 iso7816conf;
/* Reserved fields as to be zeroed */
memset(&iso7816conf, 0, sizeof(iso7816conf));
/* Enable ISO7816 mode: */
iso7816conf.flags |= SER_ISO7816_ENABLED;
/* Select the protocol: */
/* T=0 */
iso7816conf.flags |= SER_ISO7816_T(0);
/* or T=1 */
iso7816conf.flags |= SER_ISO7816_T(1);
/* Set the guard time: */
iso7816conf.tg = 2;
/* Set the clock frequency*/
iso7816conf.clk = 3571200;
/* Set transmission factors: */
iso7816conf.sc_fi = 372;
iso7816conf.sc_di = 1;
if (ioctl(fd_usart, TIOCSISO7816, &iso7816conf) < 0) {
/* Error handling. See errno. */
}
/* Use read() and write() syscalls here... */
/* Close the device when finished: */
if (close (fd) < 0) {
/* Error handling. See errno. */
}
5. REFERENCES
[1] include/uapi/linux/serial.h
...@@ -102,6 +102,8 @@ ...@@ -102,6 +102,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG 0x5453 #define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454 #define TIOCSERGWILD 0x5454
......
...@@ -93,6 +93,8 @@ ...@@ -93,6 +93,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
/* I hope the range from 0x5480 on is free ... */ /* I hope the range from 0x5480 on is free ... */
#define TIOCSCTTY 0x5480 /* become controlling tty */ #define TIOCSCTTY 0x5480 /* become controlling tty */
......
...@@ -62,6 +62,8 @@ ...@@ -62,6 +62,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ #define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define FIOCLEX 0x5451 #define FIOCLEX 0x5451
......
...@@ -102,6 +102,8 @@ ...@@ -102,6 +102,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG 0x5453 #define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454 #define TIOCSERGWILD 0x5454
......
...@@ -95,6 +95,8 @@ ...@@ -95,6 +95,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */ #define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */
#define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */ #define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485) #define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485)
#define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485) #define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485)
#define TIOCGISO7816 _IOR('T', 0x43, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x44, struct serial_iso7816)
/* Note that all the ioctls that are not available in Linux have a /* Note that all the ioctls that are not available in Linux have a
* double underscore on the front to: a) avoid some programs to * double underscore on the front to: a) avoid some programs to
......
...@@ -107,6 +107,8 @@ ...@@ -107,6 +107,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG _IO('T', 83) #define TIOCSERCONFIG _IO('T', 83)
#define TIOCSERGWILD _IOR('T', 84, int) #define TIOCSERGWILD _IOR('T', 84, int)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define pr_fmt(fmt) "OF: " fmt #define pr_fmt(fmt) "OF: " fmt
#include <linux/bitmap.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/cpu.h> #include <linux/cpu.h>
...@@ -1985,6 +1986,59 @@ int of_alias_get_id(struct device_node *np, const char *stem) ...@@ -1985,6 +1986,59 @@ int of_alias_get_id(struct device_node *np, const char *stem)
} }
EXPORT_SYMBOL_GPL(of_alias_get_id); EXPORT_SYMBOL_GPL(of_alias_get_id);
/**
* of_alias_get_alias_list - Get alias list for the given device driver
* @matches: Array of OF device match structures to search in
* @stem: Alias stem of the given device_node
* @bitmap: Bitmap field pointer
* @nbits: Maximum number of alias IDs which can be recorded in bitmap
*
* The function travels the lookup table to record alias ids for the given
* device match structures and alias stem.
*
* Return: 0 or -ENOSYS when !CONFIG_OF or
* -EOVERFLOW if alias ID is greater then allocated nbits
*/
int of_alias_get_alias_list(const struct of_device_id *matches,
const char *stem, unsigned long *bitmap,
unsigned int nbits)
{
struct alias_prop *app;
int ret = 0;
/* Zero bitmap field to make sure that all the time it is clean */
bitmap_zero(bitmap, nbits);
mutex_lock(&of_mutex);
pr_debug("%s: Looking for stem: %s\n", __func__, stem);
list_for_each_entry(app, &aliases_lookup, link) {
pr_debug("%s: stem: %s, id: %d\n",
__func__, app->stem, app->id);
if (strcmp(app->stem, stem) != 0) {
pr_debug("%s: stem comparison didn't pass %s\n",
__func__, app->stem);
continue;
}
if (of_match_node(matches, app->np)) {
pr_debug("%s: Allocated ID %d\n", __func__, app->id);
if (app->id >= nbits) {
pr_warn("%s: ID %d >= than bitmap field %d\n",
__func__, app->id, nbits);
ret = -EOVERFLOW;
} else {
set_bit(app->id, bitmap);
}
}
}
mutex_unlock(&of_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(of_alias_get_alias_list);
/** /**
* of_alias_get_highest_id - Get highest alias id for the given stem * of_alias_get_highest_id - Get highest alias id for the given stem
* @stem: Alias stem to be examined * @stem: Alias stem to be examined
......
...@@ -128,8 +128,8 @@ static int find_console_handle(void) ...@@ -128,8 +128,8 @@ static int find_console_handle(void)
*/ */
iprop = of_get_property(np, "hv-handle", NULL); iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) { if (!iprop) {
pr_err("ehv-bc: no 'hv-handle' property in %s node\n", pr_err("ehv-bc: no 'hv-handle' property in %pOFn node\n",
np->name); np);
return 0; return 0;
} }
stdout_bc = be32_to_cpu(*iprop); stdout_bc = be32_to_cpu(*iprop);
...@@ -661,8 +661,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev) ...@@ -661,8 +661,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
iprop = of_get_property(np, "hv-handle", NULL); iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) { if (!iprop) {
dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n", dev_err(&pdev->dev, "no 'hv-handle' property in %pOFn node\n",
np->name); np);
return -ENODEV; return -ENODEV;
} }
...@@ -682,8 +682,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev) ...@@ -682,8 +682,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
bc->rx_irq = irq_of_parse_and_map(np, 0); bc->rx_irq = irq_of_parse_and_map(np, 0);
bc->tx_irq = irq_of_parse_and_map(np, 1); bc->tx_irq = irq_of_parse_and_map(np, 1);
if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) { if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
dev_err(&pdev->dev, "no 'interrupts' property in %s node\n", dev_err(&pdev->dev, "no 'interrupts' property in %pOFn node\n",
np->name); np);
ret = -ENODEV; ret = -ENODEV;
goto error; goto error;
} }
......
...@@ -152,17 +152,28 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i) ...@@ -152,17 +152,28 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
} }
/* If we are not echoing the data, perhaps this is a secret so erase it */
static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
{
bool icanon = !!L_ICANON(tty);
bool no_echo = !L_ECHO(tty);
if (icanon && no_echo)
memset(buffer, 0x00, size);
}
static int tty_copy_to_user(struct tty_struct *tty, void __user *to, static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
size_t tail, size_t n) size_t tail, size_t n)
{ {
struct n_tty_data *ldata = tty->disc_data; struct n_tty_data *ldata = tty->disc_data;
size_t size = N_TTY_BUF_SIZE - tail; size_t size = N_TTY_BUF_SIZE - tail;
const void *from = read_buf_addr(ldata, tail); void *from = read_buf_addr(ldata, tail);
int uncopied; int uncopied;
if (n > size) { if (n > size) {
tty_audit_add_data(tty, from, size); tty_audit_add_data(tty, from, size);
uncopied = copy_to_user(to, from, size); uncopied = copy_to_user(to, from, size);
zero_buffer(tty, from, size - uncopied);
if (uncopied) if (uncopied)
return uncopied; return uncopied;
to += size; to += size;
...@@ -171,7 +182,9 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to, ...@@ -171,7 +182,9 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
} }
tty_audit_add_data(tty, from, n); tty_audit_add_data(tty, from, n);
return copy_to_user(to, from, n); uncopied = copy_to_user(to, from, n);
zero_buffer(tty, from, n - uncopied);
return uncopied;
} }
/** /**
...@@ -1960,11 +1973,12 @@ static int copy_from_read_buf(struct tty_struct *tty, ...@@ -1960,11 +1973,12 @@ static int copy_from_read_buf(struct tty_struct *tty,
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail); n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
n = min(*nr, n); n = min(*nr, n);
if (n) { if (n) {
const unsigned char *from = read_buf_addr(ldata, tail); unsigned char *from = read_buf_addr(ldata, tail);
retval = copy_to_user(*b, from, n); retval = copy_to_user(*b, from, n);
n -= retval; n -= retval;
is_eof = n == 1 && *from == EOF_CHAR(tty); is_eof = n == 1 && *from == EOF_CHAR(tty);
tty_audit_add_data(tty, from, n); tty_audit_add_data(tty, from, n);
zero_buffer(tty, from, n);
smp_store_release(&ldata->read_tail, ldata->read_tail + n); smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */ /* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof && if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
......
...@@ -130,12 +130,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) ...@@ -130,12 +130,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
l = l->next; l = l->next;
if (l == i->head && pass_counter++ > PASS_LIMIT) { if (l == i->head && pass_counter++ > PASS_LIMIT)
/* If we hit this, we're dead. */
printk_ratelimited(KERN_ERR
"serial8250: too much work for irq%d\n", irq);
break; break;
}
} while (l != end); } while (l != end);
spin_unlock(&i->lock); spin_unlock(&i->lock);
......
...@@ -58,7 +58,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ...@@ -58,7 +58,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
struct resource resource; struct resource resource;
struct device_node *np = ofdev->dev.of_node; struct device_node *np = ofdev->dev.of_node;
u32 clk, spd, prop; u32 clk, spd, prop;
int ret; int ret, irq;
memset(port, 0, sizeof *port); memset(port, 0, sizeof *port);
...@@ -143,21 +143,27 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ...@@ -143,21 +143,27 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (ret >= 0) if (ret >= 0)
port->line = ret; port->line = ret;
port->irq = irq_of_parse_and_map(np, 0); irq = of_irq_get(np, 0);
if (!port->irq) { if (irq < 0) {
if (irq == -EPROBE_DEFER) {
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
goto err_unprepare; goto err_unprepare;
} }
/* IRQ support not mandatory */
irq = 0;
}
port->irq = irq;
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) { if (IS_ERR(info->rst)) {
ret = PTR_ERR(info->rst); ret = PTR_ERR(info->rst);
goto err_dispose; goto err_unprepare;
} }
ret = reset_control_deassert(info->rst); ret = reset_control_deassert(info->rst);
if (ret) if (ret)
goto err_dispose; goto err_unprepare;
port->type = type; port->type = type;
port->uartclk = clk; port->uartclk = clk;
...@@ -184,8 +190,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ...@@ -184,8 +190,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->handle_irq = fsl8250_handle_irq; port->handle_irq = fsl8250_handle_irq;
return 0; return 0;
err_dispose:
irq_dispose_mapping(port->irq);
err_unprepare: err_unprepare:
clk_disable_unprepare(info->clk); clk_disable_unprepare(info->clk);
err_pmruntime: err_pmruntime:
......
...@@ -552,11 +552,30 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) ...@@ -552,11 +552,30 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
*/ */
static void serial8250_clear_fifos(struct uart_8250_port *p) static void serial8250_clear_fifos(struct uart_8250_port *p)
{ {
unsigned char fcr;
unsigned char clr_mask = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
if (p->capabilities & UART_CAP_FIFO) { if (p->capabilities & UART_CAP_FIFO) {
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); /*
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | * Make sure to avoid changing FCR[7:3] and ENABLE_FIFO bits.
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); * In case ENABLE_FIFO is not set, there is nothing to flush
serial_out(p, UART_FCR, 0); * so just return. Furthermore, on certain implementations of
* the 8250 core, the FCR[7:3] bits may only be changed under
* specific conditions and changing them if those conditions
* are not met can have nasty side effects. One such core is
* the 8250-omap present in TI AM335x.
*/
fcr = serial_in(p, UART_FCR);
/* FIFO is not enabled, there's nothing to clear. */
if (!(fcr & UART_FCR_ENABLE_FIFO))
return;
fcr |= clr_mask;
serial_out(p, UART_FCR, fcr);
fcr &= ~clr_mask;
serial_out(p, UART_FCR, fcr);
} }
} }
...@@ -1448,7 +1467,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) ...@@ -1448,7 +1467,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
* Enable previously disabled RX interrupts. * Enable previously disabled RX interrupts.
*/ */
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
serial8250_clear_and_reinit_fifos(p); serial8250_clear_fifos(p);
p->ier |= UART_IER_RLSI | UART_IER_RDI; p->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_port_out(&p->port, UART_IER, p->ier); serial_port_out(&p->port, UART_IER, p->ier);
......
...@@ -12,9 +12,6 @@ ...@@ -12,9 +12,6 @@
#include "8250.h" #include "8250.h"
/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64
/* /*
* This hardware is similar to 8250, but its register map is a bit different: * This hardware is similar to 8250, but its register map is a bit different:
* - MMIO32 (regshift = 2) * - MMIO32 (regshift = 2)
...@@ -158,42 +155,6 @@ static void uniphier_serial_dl_write(struct uart_8250_port *up, int value) ...@@ -158,42 +155,6 @@ static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
writel(value, up->port.membase + UNIPHIER_UART_DLR); writel(value, up->port.membase + UNIPHIER_UART_DLR);
} }
static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
struct uniphier8250_priv *priv)
{
int ret;
u32 prop;
struct device_node *np = dev->of_node;
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(dev, "failed to get alias id\n");
return ret;
}
port->line = ret;
/* Get clk rate through clk driver */
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret < 0)
return ret;
port->uartclk = clk_get_rate(priv->clk);
/* Check for fifo size */
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
port->fifosize = prop;
else
port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE;
return 0;
}
static int uniphier_uart_probe(struct platform_device *pdev) static int uniphier_uart_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -226,9 +187,24 @@ static int uniphier_uart_probe(struct platform_device *pdev) ...@@ -226,9 +187,24 @@ static int uniphier_uart_probe(struct platform_device *pdev)
memset(&up, 0, sizeof(up)); memset(&up, 0, sizeof(up));
ret = uniphier_of_serial_setup(dev, &up.port, priv); ret = of_alias_get_id(dev->of_node, "serial");
if (ret < 0) if (ret < 0) {
dev_err(dev, "failed to get alias id\n");
return ret; return ret;
}
up.port.line = ret;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
up.port.uartclk = clk_get_rate(priv->clk);
spin_lock_init(&priv->atomic_write_lock); spin_lock_init(&priv->atomic_write_lock);
...@@ -241,10 +217,14 @@ static int uniphier_uart_probe(struct platform_device *pdev) ...@@ -241,10 +217,14 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.port.type = PORT_16550A; up.port.type = PORT_16550A;
up.port.iotype = UPIO_MEM32; up.port.iotype = UPIO_MEM32;
up.port.fifosize = 64;
up.port.regshift = UNIPHIER_UART_REGSHIFT; up.port.regshift = UNIPHIER_UART_REGSHIFT;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE; up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
up.capabilities = UART_CAP_FIFO; up.capabilities = UART_CAP_FIFO;
if (of_property_read_bool(dev->of_node, "auto-flow-control"))
up.capabilities |= UART_CAP_AFE;
up.port.serial_in = uniphier_serial_in; up.port.serial_in = uniphier_serial_in;
up.port.serial_out = uniphier_serial_out; up.port.serial_out = uniphier_serial_out;
up.dl_read = uniphier_serial_dl_read; up.dl_read = uniphier_serial_dl_read;
......
...@@ -375,7 +375,7 @@ config SERIAL_8250_RT288X ...@@ -375,7 +375,7 @@ config SERIAL_8250_RT288X
config SERIAL_8250_OMAP config SERIAL_8250_OMAP
tristate "Support for OMAP internal UART (8250 based driver)" tristate "Support for OMAP internal UART (8250 based driver)"
depends on SERIAL_8250 && ARCH_OMAP2PLUS depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3)
help help
If you have a machine based on an Texas Instruments OMAP CPU you If you have a machine based on an Texas Instruments OMAP CPU you
can enable its onboard serial ports by enabling this option. can enable its onboard serial ports by enabling this option.
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/div64.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
...@@ -147,6 +148,8 @@ struct atmel_uart_port { ...@@ -147,6 +148,8 @@ struct atmel_uart_port {
struct circ_buf rx_ring; struct circ_buf rx_ring;
struct mctrl_gpios *gpios; struct mctrl_gpios *gpios;
u32 backup_mode; /* MR saved during iso7816 operations */
u32 backup_brgr; /* BRGR saved during iso7816 operations */
unsigned int tx_done_mask; unsigned int tx_done_mask;
u32 fifo_size; u32 fifo_size;
u32 rts_high; u32 rts_high;
...@@ -163,6 +166,10 @@ struct atmel_uart_port { ...@@ -163,6 +166,10 @@ struct atmel_uart_port {
unsigned int pending_status; unsigned int pending_status;
spinlock_t lock_suspended; spinlock_t lock_suspended;
/* ISO7816 */
unsigned int fidi_min;
unsigned int fidi_max;
#ifdef CONFIG_PM #ifdef CONFIG_PM
struct { struct {
u32 cr; u32 cr;
...@@ -361,6 +368,127 @@ static int atmel_config_rs485(struct uart_port *port, ...@@ -361,6 +368,127 @@ static int atmel_config_rs485(struct uart_port *port,
return 0; return 0;
} }
static unsigned int atmel_calc_cd(struct uart_port *port,
struct serial_iso7816 *iso7816conf)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int cd;
u64 mck_rate;
mck_rate = (u64)clk_get_rate(atmel_port->clk);
do_div(mck_rate, iso7816conf->clk);
cd = mck_rate;
return cd;
}
static unsigned int atmel_calc_fidi(struct uart_port *port,
struct serial_iso7816 *iso7816conf)
{
u64 fidi = 0;
if (iso7816conf->sc_fi && iso7816conf->sc_di) {
fidi = (u64)iso7816conf->sc_fi;
do_div(fidi, iso7816conf->sc_di);
}
return (u32)fidi;
}
/* Enable or disable the iso7816 support */
/* Called with interrupts disabled */
static int atmel_config_iso7816(struct uart_port *port,
struct serial_iso7816 *iso7816conf)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int mode;
unsigned int cd, fidi;
int ret = 0;
/* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
mode = atmel_uart_readl(port, ATMEL_US_MR);
if (iso7816conf->flags & SER_ISO7816_ENABLED) {
mode &= ~ATMEL_US_USMODE;
if (iso7816conf->tg > 255) {
dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
ret = -EINVAL;
goto err_out;
}
if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
== SER_ISO7816_T(0)) {
mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
} else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
== SER_ISO7816_T(1)) {
mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
} else {
dev_err(port->dev, "ISO7816: Type not supported\n");
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
ret = -EINVAL;
goto err_out;
}
mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);
/* select mck clock, and output */
mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
/* set parity for normal/inverse mode + max iterations */
mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);
cd = atmel_calc_cd(port, iso7816conf);
fidi = atmel_calc_fidi(port, iso7816conf);
if (fidi == 0) {
dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
} else if (fidi < atmel_port->fidi_min
|| fidi > atmel_port->fidi_max) {
dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
ret = -EINVAL;
goto err_out;
}
if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
/* port not yet in iso7816 mode: store configuration */
atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
}
atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
atmel_uart_writel(port, ATMEL_US_BRGR, cd);
atmel_uart_writel(port, ATMEL_US_FIDI, fidi);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
} else {
dev_dbg(port->dev, "Setting UART back to RS232\n");
/* back to last RS232 settings */
mode = atmel_port->backup_mode;
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
atmel_uart_writel(port, ATMEL_US_TTGR, 0);
atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
atmel_uart_writel(port, ATMEL_US_FIDI, 0x174);
if (atmel_use_pdc_tx(port))
atmel_port->tx_done_mask = ATMEL_US_ENDTX |
ATMEL_US_TXBUFE;
else
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
}
port->iso7816 = *iso7816conf;
atmel_uart_writel(port, ATMEL_US_MR, mode);
err_out:
/* Enable interrupts */
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
return ret;
}
/* /*
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
*/ */
...@@ -480,8 +608,9 @@ static void atmel_stop_tx(struct uart_port *port) ...@@ -480,8 +608,9 @@ static void atmel_stop_tx(struct uart_port *port)
/* Disable interrupts */ /* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
if ((port->rs485.flags & SER_RS485_ENABLED) && if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_start_rx(port); atmel_start_rx(port);
} }
...@@ -499,8 +628,9 @@ static void atmel_start_tx(struct uart_port *port) ...@@ -499,8 +628,9 @@ static void atmel_start_tx(struct uart_port *port)
return; return;
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
if ((port->rs485.flags & SER_RS485_ENABLED) && if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_stop_rx(port); atmel_stop_rx(port);
if (atmel_use_pdc_tx(port)) if (atmel_use_pdc_tx(port))
...@@ -798,8 +928,9 @@ static void atmel_complete_tx_dma(void *arg) ...@@ -798,8 +928,9 @@ static void atmel_complete_tx_dma(void *arg)
*/ */
if (!uart_circ_empty(xmit)) if (!uart_circ_empty(xmit))
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
else if ((port->rs485.flags & SER_RS485_ENABLED) && else if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) { !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */ /* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port); atmel_start_rx(port);
} }
...@@ -1282,6 +1413,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, ...@@ -1282,6 +1413,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
wake_up_interruptible(&port->state->port.delta_msr_wait); wake_up_interruptible(&port->state->port.delta_msr_wait);
} }
} }
if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
} }
/* /*
...@@ -1374,8 +1508,9 @@ static void atmel_tx_pdc(struct uart_port *port) ...@@ -1374,8 +1508,9 @@ static void atmel_tx_pdc(struct uart_port *port)
atmel_uart_writel(port, ATMEL_US_IER, atmel_uart_writel(port, ATMEL_US_IER,
atmel_port->tx_done_mask); atmel_port->tx_done_mask);
} else { } else {
if ((port->rs485.flags & SER_RS485_ENABLED) && if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) { !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */ /* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port); atmel_start_rx(port);
} }
...@@ -1727,6 +1862,22 @@ static void atmel_get_ip_name(struct uart_port *port) ...@@ -1727,6 +1862,22 @@ static void atmel_get_ip_name(struct uart_port *port)
atmel_port->has_frac_baudrate = true; atmel_port->has_frac_baudrate = true;
atmel_port->has_hw_timer = true; atmel_port->has_hw_timer = true;
atmel_port->rtor = ATMEL_US_RTOR; atmel_port->rtor = ATMEL_US_RTOR;
version = atmel_uart_readl(port, ATMEL_US_VERSION);
switch (version) {
case 0x814: /* sama5d2 */
/* fall through */
case 0x701: /* sama5d4 */
atmel_port->fidi_min = 3;
atmel_port->fidi_max = 65535;
break;
case 0x502: /* sam9x5, sama5d3 */
atmel_port->fidi_min = 3;
atmel_port->fidi_max = 2047;
break;
default:
atmel_port->fidi_min = 1;
atmel_port->fidi_max = 2047;
}
} else if (name == dbgu_uart) { } else if (name == dbgu_uart) {
dev_dbg(port->dev, "Dbgu or uart without hw timer\n"); dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
} else { } else {
...@@ -2100,6 +2251,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -2100,6 +2251,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
atmel_uart_writel(port, ATMEL_US_TTGR, atmel_uart_writel(port, ATMEL_US_TTGR,
port->rs485.delay_rts_after_send); port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485; mode |= ATMEL_US_USMODE_RS485;
} else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
/* select mck clock, and output */
mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
/* set max iterations */
mode |= ATMEL_US_MAX_ITER(3);
if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
== SER_ISO7816_T(0))
mode |= ATMEL_US_USMODE_ISO7816_T0;
else
mode |= ATMEL_US_USMODE_ISO7816_T1;
} else if (termios->c_cflag & CRTSCTS) { } else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */ /* RS232 with hardware handshake (RTS/CTS) */
if (atmel_use_fifo(port) && if (atmel_use_fifo(port) &&
...@@ -2176,6 +2338,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -2176,6 +2338,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
} }
quot = cd | fp << ATMEL_US_FP_OFFSET; quot = cd | fp << ATMEL_US_FP_OFFSET;
if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
atmel_uart_writel(port, ATMEL_US_BRGR, quot); atmel_uart_writel(port, ATMEL_US_BRGR, quot);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
...@@ -2357,6 +2520,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, ...@@ -2357,6 +2520,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
port->mapbase = mpdev->resource[0].start; port->mapbase = mpdev->resource[0].start;
port->irq = mpdev->resource[1].start; port->irq = mpdev->resource[1].start;
port->rs485_config = atmel_config_rs485; port->rs485_config = atmel_config_rs485;
port->iso7816_config = atmel_config_iso7816;
port->membase = NULL; port->membase = NULL;
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
...@@ -2380,8 +2544,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, ...@@ -2380,8 +2544,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
/* only enable clock when USART is in use */ /* only enable clock when USART is in use */
} }
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */ /*
if (port->rs485.flags & SER_RS485_ENABLED) * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
* ENDTX|TXBUFE
*/
if (port->rs485.flags & SER_RS485_ENABLED ||
port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
else if (atmel_use_pdc_tx(port)) { else if (atmel_use_pdc_tx(port)) {
port->fifosize = PDC_BUFFER_SIZE; port->fifosize = PDC_BUFFER_SIZE;
......
...@@ -78,7 +78,8 @@ ...@@ -78,7 +78,8 @@
#define ATMEL_US_OVER BIT(19) /* Oversampling Mode */ #define ATMEL_US_OVER BIT(19) /* Oversampling Mode */
#define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */ #define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */
#define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */ #define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */
#define ATMEL_US_MAX_ITER GENMASK(26, 24) /* Max Iterations */ #define ATMEL_US_MAX_ITER_MASK GENMASK(26, 24) /* Max Iterations */
#define ATMEL_US_MAX_ITER(n) (((n) << 24) & ATMEL_US_MAX_ITER_MASK)
#define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */ #define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */
#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ #define ATMEL_US_IER 0x08 /* Interrupt Enable Register */
......
...@@ -1155,8 +1155,8 @@ static int cpm_uart_init_port(struct device_node *np, ...@@ -1155,8 +1155,8 @@ static int cpm_uart_init_port(struct device_node *np,
if (!pinfo->clk) { if (!pinfo->clk) {
data = of_get_property(np, "fsl,cpm-brg", &len); data = of_get_property(np, "fsl,cpm-brg", &len);
if (!data || len != 4) { if (!data || len != 4) {
printk(KERN_ERR "CPM UART %s has no/invalid " printk(KERN_ERR "CPM UART %pOFn has no/invalid "
"fsl,cpm-brg property.\n", np->name); "fsl,cpm-brg property.\n", np);
return -EINVAL; return -EINVAL;
} }
pinfo->brg = *data; pinfo->brg = *data;
...@@ -1164,8 +1164,8 @@ static int cpm_uart_init_port(struct device_node *np, ...@@ -1164,8 +1164,8 @@ static int cpm_uart_init_port(struct device_node *np,
data = of_get_property(np, "fsl,cpm-command", &len); data = of_get_property(np, "fsl,cpm-command", &len);
if (!data || len != 4) { if (!data || len != 4) {
printk(KERN_ERR "CPM UART %s has no/invalid " printk(KERN_ERR "CPM UART %pOFn has no/invalid "
"fsl,cpm-command property.\n", np->name); "fsl,cpm-command property.\n", np);
return -EINVAL; return -EINVAL;
} }
pinfo->command = *data; pinfo->command = *data;
......
...@@ -232,6 +232,8 @@ ...@@ -232,6 +232,8 @@
/* IMX lpuart has four extra unused regs located at the beginning */ /* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10 #define IMX_REG_OFF 0x10
static DEFINE_IDA(fsl_lpuart_ida);
struct lpuart_port { struct lpuart_port {
struct uart_port port; struct uart_port port;
struct clk *clk; struct clk *clk;
...@@ -2143,9 +2145,12 @@ static int lpuart_probe(struct platform_device *pdev) ...@@ -2143,9 +2145,12 @@ static int lpuart_probe(struct platform_device *pdev)
ret = of_alias_get_id(np, "serial"); ret = of_alias_get_id(np, "serial");
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
if (ret < 0) {
dev_err(&pdev->dev, "port line is full, add device failed\n");
return ret; return ret;
} }
}
if (ret >= ARRAY_SIZE(lpuart_ports)) { if (ret >= ARRAY_SIZE(lpuart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n", ret); dev_err(&pdev->dev, "serial%d out of range\n", ret);
return -EINVAL; return -EINVAL;
...@@ -2246,6 +2251,8 @@ static int lpuart_remove(struct platform_device *pdev) ...@@ -2246,6 +2251,8 @@ static int lpuart_remove(struct platform_device *pdev)
uart_remove_one_port(&lpuart_reg, &sport->port); uart_remove_one_port(&lpuart_reg, &sport->port);
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
clk_disable_unprepare(sport->clk); clk_disable_unprepare(sport->clk);
if (sport->dma_tx_chan) if (sport->dma_tx_chan)
...@@ -2384,6 +2391,7 @@ static int __init lpuart_serial_init(void) ...@@ -2384,6 +2391,7 @@ static int __init lpuart_serial_init(void)
static void __exit lpuart_serial_exit(void) static void __exit lpuart_serial_exit(void)
{ {
ida_destroy(&fsl_lpuart_ida);
platform_driver_unregister(&lpuart_driver); platform_driver_unregister(&lpuart_driver);
uart_unregister_driver(&lpuart_reg); uart_unregister_driver(&lpuart_reg);
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pinctrl/consumer.h>
#include <linux/rational.h> #include <linux/rational.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -706,27 +707,25 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id) ...@@ -706,27 +707,25 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id)
{ {
struct imx_port *sport = dev_id; struct imx_port *sport = dev_id;
u32 usr1; u32 usr1;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags); spin_lock(&sport->port.lock);
imx_uart_writel(sport, USR1_RTSD, USR1); imx_uart_writel(sport, USR1_RTSD, USR1);
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS; usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
uart_handle_cts_change(&sport->port, !!usr1); uart_handle_cts_change(&sport->port, !!usr1);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait); wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock(&sport->port.lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static irqreturn_t imx_uart_txint(int irq, void *dev_id) static irqreturn_t imx_uart_txint(int irq, void *dev_id)
{ {
struct imx_port *sport = dev_id; struct imx_port *sport = dev_id;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags); spin_lock(&sport->port.lock);
imx_uart_transmit_buffer(sport); imx_uart_transmit_buffer(sport);
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock(&sport->port.lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -735,9 +734,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id) ...@@ -735,9 +734,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
struct imx_port *sport = dev_id; struct imx_port *sport = dev_id;
unsigned int rx, flg, ignored = 0; unsigned int rx, flg, ignored = 0;
struct tty_port *port = &sport->port.state->port; struct tty_port *port = &sport->port.state->port;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags); spin_lock(&sport->port.lock);
while (imx_uart_readl(sport, USR2) & USR2_RDR) { while (imx_uart_readl(sport, USR2) & USR2_RDR) {
u32 usr2; u32 usr2;
...@@ -797,7 +795,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id) ...@@ -797,7 +795,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
} }
out: out:
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock(&sport->port.lock);
tty_flip_buffer_push(port); tty_flip_buffer_push(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -903,13 +901,11 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) ...@@ -903,13 +901,11 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
} }
if (usr1 & USR1_DTRD) { if (usr1 & USR1_DTRD) {
unsigned long flags;
imx_uart_writel(sport, USR1_DTRD, USR1); imx_uart_writel(sport, USR1_DTRD, USR1);
spin_lock_irqsave(&sport->port.lock, flags); spin_lock(&sport->port.lock);
imx_uart_mctrl_check(sport); imx_uart_mctrl_check(sport);
spin_unlock_irqrestore(&sport->port.lock, flags); spin_unlock(&sport->port.lock);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
...@@ -2384,8 +2380,13 @@ static int imx_uart_remove(struct platform_device *pdev) ...@@ -2384,8 +2380,13 @@ static int imx_uart_remove(struct platform_device *pdev)
static void imx_uart_restore_context(struct imx_port *sport) static void imx_uart_restore_context(struct imx_port *sport)
{ {
if (!sport->context_saved) unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
if (!sport->context_saved) {
spin_unlock_irqrestore(&sport->port.lock, flags);
return; return;
}
imx_uart_writel(sport, sport->saved_reg[4], UFCR); imx_uart_writel(sport, sport->saved_reg[4], UFCR);
imx_uart_writel(sport, sport->saved_reg[5], UESC); imx_uart_writel(sport, sport->saved_reg[5], UESC);
...@@ -2398,11 +2399,15 @@ static void imx_uart_restore_context(struct imx_port *sport) ...@@ -2398,11 +2399,15 @@ static void imx_uart_restore_context(struct imx_port *sport)
imx_uart_writel(sport, sport->saved_reg[2], UCR3); imx_uart_writel(sport, sport->saved_reg[2], UCR3);
imx_uart_writel(sport, sport->saved_reg[3], UCR4); imx_uart_writel(sport, sport->saved_reg[3], UCR4);
sport->context_saved = false; sport->context_saved = false;
spin_unlock_irqrestore(&sport->port.lock, flags);
} }
static void imx_uart_save_context(struct imx_port *sport) static void imx_uart_save_context(struct imx_port *sport)
{ {
unsigned long flags;
/* Save necessary regs */ /* Save necessary regs */
spin_lock_irqsave(&sport->port.lock, flags);
sport->saved_reg[0] = imx_uart_readl(sport, UCR1); sport->saved_reg[0] = imx_uart_readl(sport, UCR1);
sport->saved_reg[1] = imx_uart_readl(sport, UCR2); sport->saved_reg[1] = imx_uart_readl(sport, UCR2);
sport->saved_reg[2] = imx_uart_readl(sport, UCR3); sport->saved_reg[2] = imx_uart_readl(sport, UCR3);
...@@ -2414,6 +2419,7 @@ static void imx_uart_save_context(struct imx_port *sport) ...@@ -2414,6 +2419,7 @@ static void imx_uart_save_context(struct imx_port *sport)
sport->saved_reg[8] = imx_uart_readl(sport, UBMR); sport->saved_reg[8] = imx_uart_readl(sport, UBMR);
sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS); sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS);
sport->context_saved = true; sport->context_saved = true;
spin_unlock_irqrestore(&sport->port.lock, flags);
} }
static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
...@@ -2447,6 +2453,8 @@ static int imx_uart_suspend_noirq(struct device *dev) ...@@ -2447,6 +2453,8 @@ static int imx_uart_suspend_noirq(struct device *dev)
clk_disable(sport->clk_ipg); clk_disable(sport->clk_ipg);
pinctrl_pm_select_sleep_state(dev);
return 0; return 0;
} }
...@@ -2455,6 +2463,8 @@ static int imx_uart_resume_noirq(struct device *dev) ...@@ -2455,6 +2463,8 @@ static int imx_uart_resume_noirq(struct device *dev)
struct imx_port *sport = dev_get_drvdata(dev); struct imx_port *sport = dev_get_drvdata(dev);
int ret; int ret;
pinctrl_pm_select_default_state(dev);
ret = clk_enable(sport->clk_ipg); ret = clk_enable(sport->clk_ipg);
if (ret) if (ret)
return ret; return ret;
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
* *
* 2007-2008 (c) Jason Wessel - Wind River Systems, Inc. * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/kgdb.h> #include <linux/kgdb.h>
...@@ -128,19 +131,6 @@ static void kgdboc_unregister_kbd(void) ...@@ -128,19 +131,6 @@ static void kgdboc_unregister_kbd(void)
#define kgdboc_restore_input() #define kgdboc_restore_input()
#endif /* ! CONFIG_KDB_KEYBOARD */ #endif /* ! CONFIG_KDB_KEYBOARD */
static int kgdboc_option_setup(char *opt)
{
if (strlen(opt) >= MAX_CONFIG_LEN) {
printk(KERN_ERR "kgdboc: config string too long\n");
return -ENOSPC;
}
strcpy(config, opt);
return 0;
}
__setup("kgdboc=", kgdboc_option_setup);
static void cleanup_kgdboc(void) static void cleanup_kgdboc(void)
{ {
if (kgdb_unregister_nmi_console()) if (kgdb_unregister_nmi_console())
...@@ -154,15 +144,13 @@ static int configure_kgdboc(void) ...@@ -154,15 +144,13 @@ static int configure_kgdboc(void)
{ {
struct tty_driver *p; struct tty_driver *p;
int tty_line = 0; int tty_line = 0;
int err; int err = -ENODEV;
char *cptr = config; char *cptr = config;
struct console *cons; struct console *cons;
err = kgdboc_option_setup(config); if (!strlen(config) || isspace(config[0]))
if (err || !strlen(config) || isspace(config[0]))
goto noconfig; goto noconfig;
err = -ENODEV;
kgdboc_io_ops.is_console = 0; kgdboc_io_ops.is_console = 0;
kgdb_tty_driver = NULL; kgdb_tty_driver = NULL;
...@@ -248,7 +236,7 @@ static int param_set_kgdboc_var(const char *kmessage, ...@@ -248,7 +236,7 @@ static int param_set_kgdboc_var(const char *kmessage,
int len = strlen(kmessage); int len = strlen(kmessage);
if (len >= MAX_CONFIG_LEN) { if (len >= MAX_CONFIG_LEN) {
printk(KERN_ERR "kgdboc: config string too long\n"); pr_err("config string too long\n");
return -ENOSPC; return -ENOSPC;
} }
...@@ -259,8 +247,7 @@ static int param_set_kgdboc_var(const char *kmessage, ...@@ -259,8 +247,7 @@ static int param_set_kgdboc_var(const char *kmessage,
} }
if (kgdb_connected) { if (kgdb_connected) {
printk(KERN_ERR pr_err("Cannot reconfigure while KGDB is connected.\n");
"kgdboc: Cannot reconfigure while KGDB is connected.\n");
return -EBUSY; return -EBUSY;
} }
...@@ -311,6 +298,25 @@ static struct kgdb_io kgdboc_io_ops = { ...@@ -311,6 +298,25 @@ static struct kgdb_io kgdboc_io_ops = {
}; };
#ifdef CONFIG_KGDB_SERIAL_CONSOLE #ifdef CONFIG_KGDB_SERIAL_CONSOLE
static int kgdboc_option_setup(char *opt)
{
if (!opt) {
pr_err("config string not provided\n");
return -EINVAL;
}
if (strlen(opt) >= MAX_CONFIG_LEN) {
pr_err("config string too long\n");
return -ENOSPC;
}
strcpy(config, opt);
return 0;
}
__setup("kgdboc=", kgdboc_option_setup);
/* This is only available if kgdboc is a built in for early debugging */ /* This is only available if kgdboc is a built in for early debugging */
static int __init kgdboc_early_init(char *opt) static int __init kgdboc_early_init(char *opt)
{ {
......
...@@ -1634,8 +1634,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s) ...@@ -1634,8 +1634,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
/* /*
* If something went wrong, rollback. * If something went wrong, rollback.
* Be careful: i may be unsigned.
*/ */
while (err && (--i >= 0)) while (err && (i-- > 0))
if (irq[i] >= 0) if (irq[i] >= 0)
free_irq(irq[i], s); free_irq(irq[i], s);
......
...@@ -219,7 +219,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable) ...@@ -219,7 +219,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
static bool pmz_receive_chars(struct uart_pmac_port *uap) static bool pmz_receive_chars(struct uart_pmac_port *uap)
{ {
struct tty_port *port; struct tty_port *port;
unsigned char ch, r1, drop, error, flag; unsigned char ch, r1, drop, flag;
int loops = 0; int loops = 0;
/* Sanity check, make sure the old bug is no longer happening */ /* Sanity check, make sure the old bug is no longer happening */
...@@ -231,7 +231,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) ...@@ -231,7 +231,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
port = &uap->port.state->port; port = &uap->port.state->port;
while (1) { while (1) {
error = 0;
drop = 0; drop = 0;
r1 = read_zsreg(uap, R1); r1 = read_zsreg(uap, R1);
...@@ -273,7 +272,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap) ...@@ -273,7 +272,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
uap->port.icount.rx++; uap->port.icount.rx++;
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) { if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
error = 1;
if (r1 & BRK_ABRT) { if (r1 & BRK_ABRT) {
pmz_debug("pmz: got break !\n"); pmz_debug("pmz: got break !\n");
r1 &= ~(PAR_ERR | CRC_ERR); r1 &= ~(PAR_ERR | CRC_ERR);
...@@ -1566,9 +1564,9 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match) ...@@ -1566,9 +1564,9 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
* to work around bugs in ancient Apple device-trees * to work around bugs in ancient Apple device-trees
*/ */
if (macio_request_resources(uap->dev, "pmac_zilog")) if (macio_request_resources(uap->dev, "pmac_zilog"))
printk(KERN_WARNING "%s: Failed to request resource" printk(KERN_WARNING "%pOFn: Failed to request resource"
", port still active\n", ", port still active\n",
uap->node->name); uap->node);
else else
uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED; uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;
......
...@@ -851,6 +851,23 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) ...@@ -851,6 +851,23 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
{ {
struct qcom_geni_serial_port *port = to_dev_port(uport, uport); struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
u32 proto;
if (uart_console(uport))
port->tx_bytes_pw = 1;
else
port->tx_bytes_pw = 4;
port->rx_bytes_pw = RX_BYTES_PW;
proto = geni_se_read_proto(&port->se);
if (proto != GENI_SE_UART) {
dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
return -ENXIO;
}
qcom_geni_serial_stop_rx(uport);
get_tx_fifo_size(port);
set_rfr_wm(port); set_rfr_wm(port);
writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT); writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
...@@ -874,30 +891,19 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) ...@@ -874,30 +891,19 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
return -ENOMEM; return -ENOMEM;
} }
port->setup = true; port->setup = true;
return 0; return 0;
} }
static int qcom_geni_serial_startup(struct uart_port *uport) static int qcom_geni_serial_startup(struct uart_port *uport)
{ {
int ret; int ret;
u32 proto;
struct qcom_geni_serial_port *port = to_dev_port(uport, uport); struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
scnprintf(port->name, sizeof(port->name), scnprintf(port->name, sizeof(port->name),
"qcom_serial_%s%d", "qcom_serial_%s%d",
(uart_console(uport) ? "console" : "uart"), uport->line); (uart_console(uport) ? "console" : "uart"), uport->line);
if (!uart_console(uport)) {
port->tx_bytes_pw = 4;
port->rx_bytes_pw = RX_BYTES_PW;
}
proto = geni_se_read_proto(&port->se);
if (proto != GENI_SE_UART) {
dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
return -ENXIO;
}
get_tx_fifo_size(port);
if (!port->setup) { if (!port->setup) {
ret = qcom_geni_serial_port_setup(uport); ret = qcom_geni_serial_port_setup(uport);
if (ret) if (ret)
...@@ -1056,6 +1062,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options) ...@@ -1056,6 +1062,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
int bits = 8; int bits = 8;
int parity = 'n'; int parity = 'n';
int flow = 'n'; int flow = 'n';
int ret;
if (co->index >= GENI_UART_CONS_PORTS || co->index < 0) if (co->index >= GENI_UART_CONS_PORTS || co->index < 0)
return -ENXIO; return -ENXIO;
...@@ -1071,21 +1078,10 @@ static int __init qcom_geni_console_setup(struct console *co, char *options) ...@@ -1071,21 +1078,10 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
if (unlikely(!uport->membase)) if (unlikely(!uport->membase))
return -ENXIO; return -ENXIO;
if (geni_se_resources_on(&port->se)) {
dev_err(port->se.dev, "Error turning on resources\n");
return -ENXIO;
}
if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) {
geni_se_resources_off(&port->se);
return -ENXIO;
}
if (!port->setup) { if (!port->setup) {
port->tx_bytes_pw = 1; ret = qcom_geni_serial_port_setup(uport);
port->rx_bytes_pw = RX_BYTES_PW; if (ret)
qcom_geni_serial_stop_rx(uport); return ret;
qcom_geni_serial_port_setup(uport);
} }
if (options) if (options)
...@@ -1203,11 +1199,12 @@ static void qcom_geni_serial_pm(struct uart_port *uport, ...@@ -1203,11 +1199,12 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
{ {
struct qcom_geni_serial_port *port = to_dev_port(uport, uport); struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
/* If we've never been called, treat it as off */
if (old_state == UART_PM_STATE_UNDEFINED)
old_state = UART_PM_STATE_OFF;
if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
geni_se_resources_on(&port->se); geni_se_resources_on(&port->se);
else if (!uart_console(uport) && (new_state == UART_PM_STATE_ON &&
old_state == UART_PM_STATE_UNDEFINED))
geni_se_resources_on(&port->se);
else if (new_state == UART_PM_STATE_OFF && else if (new_state == UART_PM_STATE_OFF &&
old_state == UART_PM_STATE_ON) old_state == UART_PM_STATE_ON)
geni_se_resources_off(&port->se); geni_se_resources_off(&port->se);
...@@ -1263,7 +1260,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) ...@@ -1263,7 +1260,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart")) if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart"))
console = true; console = true;
if (pdev->dev.of_node) {
if (console) { if (console) {
drv = &qcom_geni_console_driver; drv = &qcom_geni_console_driver;
line = of_alias_get_id(pdev->dev.of_node, "serial"); line = of_alias_get_id(pdev->dev.of_node, "serial");
...@@ -1271,7 +1267,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) ...@@ -1271,7 +1267,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
drv = &qcom_geni_uart_driver; drv = &qcom_geni_uart_driver;
line = of_alias_get_id(pdev->dev.of_node, "hsuart"); line = of_alias_get_id(pdev->dev.of_node, "hsuart");
} }
}
port = get_port_from_line(line, console); port = get_port_from_line(line, console);
if (IS_ERR(port)) { if (IS_ERR(port)) {
......
...@@ -1941,7 +1941,11 @@ static int s3c24xx_serial_resume(struct device *dev) ...@@ -1941,7 +1941,11 @@ static int s3c24xx_serial_resume(struct device *dev)
if (port) { if (port) {
clk_prepare_enable(ourport->clk); clk_prepare_enable(ourport->clk);
if (!IS_ERR(ourport->baudclk))
clk_prepare_enable(ourport->baudclk);
s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port)); s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
if (!IS_ERR(ourport->baudclk))
clk_disable_unprepare(ourport->baudclk);
clk_disable_unprepare(ourport->clk); clk_disable_unprepare(ourport->clk);
uart_resume_port(&s3c24xx_uart_drv, port); uart_resume_port(&s3c24xx_uart_drv, port);
...@@ -1964,7 +1968,11 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) ...@@ -1964,7 +1968,11 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
if (rx_enabled(port)) if (rx_enabled(port))
uintm &= ~S3C64XX_UINTM_RXD_MSK; uintm &= ~S3C64XX_UINTM_RXD_MSK;
clk_prepare_enable(ourport->clk); clk_prepare_enable(ourport->clk);
if (!IS_ERR(ourport->baudclk))
clk_prepare_enable(ourport->baudclk);
wr_regl(port, S3C64XX_UINTM, uintm); wr_regl(port, S3C64XX_UINTM, uintm);
if (!IS_ERR(ourport->baudclk))
clk_disable_unprepare(ourport->baudclk);
clk_disable_unprepare(ourport->clk); clk_disable_unprepare(ourport->clk);
} }
} }
......
...@@ -328,6 +328,7 @@ struct sc16is7xx_port { ...@@ -328,6 +328,7 @@ struct sc16is7xx_port {
struct kthread_worker kworker; struct kthread_worker kworker;
struct task_struct *kworker_task; struct task_struct *kworker_task;
struct kthread_work irq_work; struct kthread_work irq_work;
struct mutex efr_lock;
struct sc16is7xx_one p[0]; struct sc16is7xx_one p[0];
}; };
...@@ -499,6 +500,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) ...@@ -499,6 +500,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
div /= 4; div /= 4;
} }
/* In an amazing feat of design, the Enhanced Features Register shares
* the address of the Interrupt Identification Register, and is
* switched in by writing a magic value (0xbf) to the Line Control
* Register. Any interrupt firing during this time will see the EFR
* where it expects the IIR to be, leading to "Unexpected interrupt"
* messages.
*
* Prevent this possibility by claiming a mutex while accessing the
* EFR, and claiming the same mutex from within the interrupt handler.
* This is similar to disabling the interrupt, but that doesn't work
* because the bulk of the interrupt processing is run as a workqueue
* job in thread context.
*/
mutex_lock(&s->efr_lock);
lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG); lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
/* Open the LCR divisors for configuration */ /* Open the LCR divisors for configuration */
...@@ -514,6 +530,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud) ...@@ -514,6 +530,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
/* Put LCR back to the normal mode */ /* Put LCR back to the normal mode */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
mutex_unlock(&s->efr_lock);
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_CLKSEL_BIT, SC16IS7XX_MCR_CLKSEL_BIT,
prescaler); prescaler);
...@@ -657,7 +675,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port) ...@@ -657,7 +675,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
uart_write_wakeup(port); uart_write_wakeup(port);
} }
static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{ {
struct uart_port *port = &s->p[portno].port; struct uart_port *port = &s->p[portno].port;
...@@ -666,7 +684,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) ...@@ -666,7 +684,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG); iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
if (iir & SC16IS7XX_IIR_NO_INT_BIT) if (iir & SC16IS7XX_IIR_NO_INT_BIT)
break; return false;
iir &= SC16IS7XX_IIR_ID_MASK; iir &= SC16IS7XX_IIR_ID_MASK;
...@@ -688,16 +706,27 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) ...@@ -688,16 +706,27 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
port->line, iir); port->line, iir);
break; break;
} }
} while (1); } while (0);
return true;
} }
static void sc16is7xx_ist(struct kthread_work *ws) static void sc16is7xx_ist(struct kthread_work *ws)
{ {
struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
mutex_lock(&s->efr_lock);
while (1) {
bool keep_polling = false;
int i; int i;
for (i = 0; i < s->devtype->nr_uart; ++i) for (i = 0; i < s->devtype->nr_uart; ++i)
sc16is7xx_port_irq(s, i); keep_polling |= sc16is7xx_port_irq(s, i);
if (!keep_polling)
break;
}
mutex_unlock(&s->efr_lock);
} }
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
...@@ -892,6 +921,9 @@ static void sc16is7xx_set_termios(struct uart_port *port, ...@@ -892,6 +921,9 @@ static void sc16is7xx_set_termios(struct uart_port *port,
if (!(termios->c_cflag & CREAD)) if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK; port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
/* As above, claim the mutex while accessing the EFR. */
mutex_lock(&s->efr_lock);
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_B); SC16IS7XX_LCR_CONF_MODE_B);
...@@ -913,6 +945,8 @@ static void sc16is7xx_set_termios(struct uart_port *port, ...@@ -913,6 +945,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
/* Update LCR register */ /* Update LCR register */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr); sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
mutex_unlock(&s->efr_lock);
/* Get baud rate generator configuration */ /* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old, baud = uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 4 / 0xffff, port->uartclk / 16 / 4 / 0xffff,
...@@ -1178,6 +1212,7 @@ static int sc16is7xx_probe(struct device *dev, ...@@ -1178,6 +1212,7 @@ static int sc16is7xx_probe(struct device *dev,
s->regmap = regmap; s->regmap = regmap;
s->devtype = devtype; s->devtype = devtype;
dev_set_drvdata(dev, s); dev_set_drvdata(dev, s);
mutex_init(&s->efr_lock);
kthread_init_worker(&s->kworker); kthread_init_worker(&s->kworker);
kthread_init_work(&s->irq_work, sc16is7xx_ist); kthread_init_work(&s->irq_work, sc16is7xx_ist);
......
...@@ -1302,6 +1302,58 @@ static int uart_set_rs485_config(struct uart_port *port, ...@@ -1302,6 +1302,58 @@ static int uart_set_rs485_config(struct uart_port *port,
return 0; return 0;
} }
static int uart_get_iso7816_config(struct uart_port *port,
struct serial_iso7816 __user *iso7816)
{
unsigned long flags;
struct serial_iso7816 aux;
if (!port->iso7816_config)
return -ENOIOCTLCMD;
spin_lock_irqsave(&port->lock, flags);
aux = port->iso7816;
spin_unlock_irqrestore(&port->lock, flags);
if (copy_to_user(iso7816, &aux, sizeof(aux)))
return -EFAULT;
return 0;
}
static int uart_set_iso7816_config(struct uart_port *port,
struct serial_iso7816 __user *iso7816_user)
{
struct serial_iso7816 iso7816;
int i, ret;
unsigned long flags;
if (!port->iso7816_config)
return -ENOIOCTLCMD;
if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user)))
return -EFAULT;
/*
* There are 5 words reserved for future use. Check that userspace
* doesn't put stuff in there to prevent breakages in the future.
*/
for (i = 0; i < 5; i++)
if (iso7816.reserved[i])
return -EINVAL;
spin_lock_irqsave(&port->lock, flags);
ret = port->iso7816_config(port, &iso7816);
spin_unlock_irqrestore(&port->lock, flags);
if (ret)
return ret;
if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816)))
return -EFAULT;
return 0;
}
/* /*
* Called via sys_ioctl. We can use spin_lock_irq() here. * Called via sys_ioctl. We can use spin_lock_irq() here.
*/ */
...@@ -1371,6 +1423,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) ...@@ -1371,6 +1423,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
case TIOCSRS485: case TIOCSRS485:
ret = uart_set_rs485_config(uport, uarg); ret = uart_set_rs485_config(uport, uarg);
break; break;
case TIOCSISO7816:
ret = uart_set_iso7816_config(state->uart_port, uarg);
break;
case TIOCGISO7816:
ret = uart_get_iso7816_config(state->uart_port, uarg);
break;
default: default:
if (uport->ops->ioctl) if (uport->ops->ioctl)
ret = uport->ops->ioctl(uport, cmd, arg); ret = uport->ops->ioctl(uport, cmd, arg);
......
...@@ -1516,7 +1516,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port, ...@@ -1516,7 +1516,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
chan = dma_request_slave_channel(port->dev, chan = dma_request_slave_channel(port->dev,
dir == DMA_MEM_TO_DEV ? "tx" : "rx"); dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) { if (!chan) {
dev_warn(port->dev, "dma_request_slave_channel failed\n"); dev_dbg(port->dev, "dma_request_slave_channel failed\n");
return NULL; return NULL;
} }
...@@ -3414,6 +3414,12 @@ static int __init scif_early_console_setup(struct earlycon_device *device, ...@@ -3414,6 +3414,12 @@ static int __init scif_early_console_setup(struct earlycon_device *device,
{ {
return early_console_setup(device, PORT_SCIF); return early_console_setup(device, PORT_SCIF);
} }
static int __init rzscifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
return early_console_setup(device, PORT_SCIF);
}
static int __init scifa_early_console_setup(struct earlycon_device *device, static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt) const char *opt)
{ {
...@@ -3432,6 +3438,7 @@ static int __init hscif_early_console_setup(struct earlycon_device *device, ...@@ -3432,6 +3438,7 @@ static int __init hscif_early_console_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup); OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup); OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup); OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup); OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
......
...@@ -888,7 +888,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) ...@@ -888,7 +888,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
/* somebody really wants this output, might be an /* somebody really wants this output, might be an
* oops, kdb, panic, etc. make sure they get it. */ * oops, kdb, panic, etc. make sure they get it. */
if (spin_is_locked(&port->sc_port.lock)) { if (!spin_trylock_irqsave(&port->sc_port.lock, flags)) {
int lhead = port->sc_port.state->xmit.head; int lhead = port->sc_port.state->xmit.head;
int ltail = port->sc_port.state->xmit.tail; int ltail = port->sc_port.state->xmit.tail;
int counter, got_lock = 0; int counter, got_lock = 0;
...@@ -905,13 +905,11 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) ...@@ -905,13 +905,11 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
*/ */
for (counter = 0; counter < 150; mdelay(125), counter++) { for (counter = 0; counter < 150; mdelay(125), counter++) {
if (!spin_is_locked(&port->sc_port.lock) if (stole_lock)
|| stole_lock) { break;
if (!stole_lock) {
spin_lock_irqsave(&port->sc_port.lock, if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
flags);
got_lock = 1; got_lock = 1;
}
break; break;
} else { } else {
/* still locked */ /* still locked */
...@@ -938,7 +936,6 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) ...@@ -938,7 +936,6 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count); puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
} else { } else {
stole_lock = 0; stole_lock = 0;
spin_lock_irqsave(&port->sc_port.lock, flags);
sn_transmit_chars(port, 1); sn_transmit_chars(port, 1);
spin_unlock_irqrestore(&port->sc_port.lock, flags); spin_unlock_irqrestore(&port->sc_port.lock, flags);
......
...@@ -45,6 +45,8 @@ ...@@ -45,6 +45,8 @@
/* data number in TX and RX fifo */ /* data number in TX and RX fifo */
#define SPRD_STS1 0x000C #define SPRD_STS1 0x000C
#define SPRD_RX_FIFO_CNT_MASK GENMASK(7, 0)
#define SPRD_TX_FIFO_CNT_MASK GENMASK(15, 8)
/* interrupt enable register and its BITs */ /* interrupt enable register and its BITs */
#define SPRD_IEN 0x0010 #define SPRD_IEN 0x0010
...@@ -82,11 +84,15 @@ ...@@ -82,11 +84,15 @@
/* fifo threshold register */ /* fifo threshold register */
#define SPRD_CTL2 0x0020 #define SPRD_CTL2 0x0020
#define THLD_TX_EMPTY 0x40 #define THLD_TX_EMPTY 0x40
#define THLD_TX_EMPTY_SHIFT 8
#define THLD_RX_FULL 0x40 #define THLD_RX_FULL 0x40
/* config baud rate register */ /* config baud rate register */
#define SPRD_CLKD0 0x0024 #define SPRD_CLKD0 0x0024
#define SPRD_CLKD0_MASK GENMASK(15, 0)
#define SPRD_CLKD1 0x0028 #define SPRD_CLKD1 0x0028
#define SPRD_CLKD1_MASK GENMASK(20, 16)
#define SPRD_CLKD1_SHIFT 16
/* interrupt mask status register */ /* interrupt mask status register */
#define SPRD_IMSR 0x002C #define SPRD_IMSR 0x002C
...@@ -95,38 +101,29 @@ ...@@ -95,38 +101,29 @@
#define SPRD_IMSR_BREAK_DETECT BIT(7) #define SPRD_IMSR_BREAK_DETECT BIT(7)
#define SPRD_IMSR_TIMEOUT BIT(13) #define SPRD_IMSR_TIMEOUT BIT(13)
struct reg_backup {
u32 ien;
u32 ctrl0;
u32 ctrl1;
u32 ctrl2;
u32 clkd0;
u32 clkd1;
u32 dspwait;
};
struct sprd_uart_port { struct sprd_uart_port {
struct uart_port port; struct uart_port port;
struct reg_backup reg_bak;
char name[16]; char name[16];
}; };
static struct sprd_uart_port *sprd_port[UART_NR_MAX]; static struct sprd_uart_port *sprd_port[UART_NR_MAX];
static int sprd_ports_num; static int sprd_ports_num;
static inline unsigned int serial_in(struct uart_port *port, int offset) static inline unsigned int serial_in(struct uart_port *port,
unsigned int offset)
{ {
return readl_relaxed(port->membase + offset); return readl_relaxed(port->membase + offset);
} }
static inline void serial_out(struct uart_port *port, int offset, int value) static inline void serial_out(struct uart_port *port, unsigned int offset,
int value)
{ {
writel_relaxed(value, port->membase + offset); writel_relaxed(value, port->membase + offset);
} }
static unsigned int sprd_tx_empty(struct uart_port *port) static unsigned int sprd_tx_empty(struct uart_port *port)
{ {
if (serial_in(port, SPRD_STS1) & 0xff00) if (serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
return 0; return 0;
else else
return TIOCSER_TEMT; return TIOCSER_TEMT;
...@@ -224,7 +221,8 @@ static inline void sprd_rx(struct uart_port *port) ...@@ -224,7 +221,8 @@ static inline void sprd_rx(struct uart_port *port)
struct tty_port *tty = &port->state->port; struct tty_port *tty = &port->state->port;
unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT; unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) { while ((serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK) &&
max_count--) {
lsr = serial_in(port, SPRD_LSR); lsr = serial_in(port, SPRD_LSR);
ch = serial_in(port, SPRD_RXD); ch = serial_in(port, SPRD_RXD);
flag = TTY_NORMAL; flag = TTY_NORMAL;
...@@ -294,8 +292,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) ...@@ -294,8 +292,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
if (ims & SPRD_IMSR_TIMEOUT) if (ims & SPRD_IMSR_TIMEOUT)
serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT); serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
if (ims & (SPRD_IMSR_RX_FIFO_FULL | if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT |
SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT)) SPRD_IMSR_TIMEOUT))
sprd_rx(port); sprd_rx(port);
if (ims & SPRD_IMSR_TX_FIFO_EMPTY) if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
...@@ -314,16 +312,17 @@ static int sprd_startup(struct uart_port *port) ...@@ -314,16 +312,17 @@ static int sprd_startup(struct uart_port *port)
struct sprd_uart_port *sp; struct sprd_uart_port *sp;
unsigned long flags; unsigned long flags;
serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL)); serial_out(port, SPRD_CTL2,
THLD_TX_EMPTY << THLD_TX_EMPTY_SHIFT | THLD_RX_FULL);
/* clear rx fifo */ /* clear rx fifo */
timeout = SPRD_TIMEOUT; timeout = SPRD_TIMEOUT;
while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff) while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK)
serial_in(port, SPRD_RXD); serial_in(port, SPRD_RXD);
/* clear tx fifo */ /* clear tx fifo */
timeout = SPRD_TIMEOUT; timeout = SPRD_TIMEOUT;
while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00) while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
cpu_relax(); cpu_relax();
/* clear interrupt */ /* clear interrupt */
...@@ -444,10 +443,11 @@ static void sprd_set_termios(struct uart_port *port, ...@@ -444,10 +443,11 @@ static void sprd_set_termios(struct uart_port *port,
} }
/* clock divider bit0~bit15 */ /* clock divider bit0~bit15 */
serial_out(port, SPRD_CLKD0, quot & 0xffff); serial_out(port, SPRD_CLKD0, quot & SPRD_CLKD0_MASK);
/* clock divider bit16~bit20 */ /* clock divider bit16~bit20 */
serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16); serial_out(port, SPRD_CLKD1,
(quot & SPRD_CLKD1_MASK) >> SPRD_CLKD1_SHIFT);
serial_out(port, SPRD_LCR, lcr); serial_out(port, SPRD_LCR, lcr);
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF; fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
serial_out(port, SPRD_CTL1, fc); serial_out(port, SPRD_CTL1, fc);
...@@ -480,8 +480,7 @@ static void sprd_config_port(struct uart_port *port, int flags) ...@@ -480,8 +480,7 @@ static void sprd_config_port(struct uart_port *port, int flags)
port->type = PORT_SPRD; port->type = PORT_SPRD;
} }
static int sprd_verify_port(struct uart_port *port, static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser)
struct serial_struct *ser)
{ {
if (ser->type != PORT_SPRD) if (ser->type != PORT_SPRD)
return -EINVAL; return -EINVAL;
...@@ -521,7 +520,7 @@ static void wait_for_xmitr(struct uart_port *port) ...@@ -521,7 +520,7 @@ static void wait_for_xmitr(struct uart_port *port)
if (--tmout == 0) if (--tmout == 0)
break; break;
udelay(1); udelay(1);
} while (status & 0xff00); } while (status & SPRD_TX_FIFO_CNT_MASK);
} }
static void sprd_console_putchar(struct uart_port *port, int ch) static void sprd_console_putchar(struct uart_port *port, int ch)
...@@ -600,16 +599,14 @@ static void sprd_putc(struct uart_port *port, int c) ...@@ -600,16 +599,14 @@ static void sprd_putc(struct uart_port *port, int c)
writeb(c, port->membase + SPRD_TXD); writeb(c, port->membase + SPRD_TXD);
} }
static void sprd_early_write(struct console *con, const char *s, static void sprd_early_write(struct console *con, const char *s, unsigned int n)
unsigned n)
{ {
struct earlycon_device *dev = con->data; struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, sprd_putc); uart_console_write(&dev->port, s, n, sprd_putc);
} }
static int __init sprd_early_console_setup( static int __init sprd_early_console_setup(struct earlycon_device *device,
struct earlycon_device *device,
const char *opt) const char *opt)
{ {
if (!device->port.membase) if (!device->port.membase)
...@@ -692,8 +689,8 @@ static int sprd_probe(struct platform_device *pdev) ...@@ -692,8 +689,8 @@ static int sprd_probe(struct platform_device *pdev)
index = sprd_probe_dt_alias(index, &pdev->dev); index = sprd_probe_dt_alias(index, &pdev->dev);
sprd_port[index] = devm_kzalloc(&pdev->dev, sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
sizeof(*sprd_port[index]), GFP_KERNEL); GFP_KERNEL);
if (!sprd_port[index]) if (!sprd_port[index])
return -ENOMEM; return -ENOMEM;
...@@ -712,15 +709,12 @@ static int sprd_probe(struct platform_device *pdev) ...@@ -712,15 +709,12 @@ static int sprd_probe(struct platform_device *pdev)
up->uartclk = clk_get_rate(clk); up->uartclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "not provide mem resource\n");
return -ENODEV;
}
up->mapbase = res->start;
up->membase = devm_ioremap_resource(&pdev->dev, res); up->membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(up->membase)) if (IS_ERR(up->membase))
return PTR_ERR(up->membase); return PTR_ERR(up->membase);
up->mapbase = res->start;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(&pdev->dev, "not provide irq resource: %d\n", irq); dev_err(&pdev->dev, "not provide irq resource: %d\n", irq);
......
...@@ -55,6 +55,11 @@ ...@@ -55,6 +55,11 @@
#define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_RST_RX 0x02
#define ULITE_CONTROL_IE 0x10 #define ULITE_CONTROL_IE 0x10
/* Static pointer to console port */
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static struct uart_port *console_port;
#endif
struct uartlite_data { struct uartlite_data {
const struct uartlite_reg_ops *reg_ops; const struct uartlite_reg_ops *reg_ops;
struct clk *clk; struct clk *clk;
...@@ -472,7 +477,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch) ...@@ -472,7 +477,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch)
static void ulite_console_write(struct console *co, const char *s, static void ulite_console_write(struct console *co, const char *s,
unsigned int count) unsigned int count)
{ {
struct uart_port *port = &ulite_ports[co->index]; struct uart_port *port = console_port;
unsigned long flags; unsigned long flags;
unsigned int ier; unsigned int ier;
int locked = 1; int locked = 1;
...@@ -506,10 +511,8 @@ static int ulite_console_setup(struct console *co, char *options) ...@@ -506,10 +511,8 @@ static int ulite_console_setup(struct console *co, char *options)
int parity = 'n'; int parity = 'n';
int flow = 'n'; int flow = 'n';
if (co->index < 0 || co->index >= ULITE_NR_UARTS)
return -EINVAL;
port = &ulite_ports[co->index]; port = console_port;
/* Has the device been initialized yet? */ /* Has the device been initialized yet? */
if (!port->mapbase) { if (!port->mapbase) {
...@@ -541,14 +544,6 @@ static struct console ulite_console = { ...@@ -541,14 +544,6 @@ static struct console ulite_console = {
.data = &ulite_uart_driver, .data = &ulite_uart_driver,
}; };
static int __init ulite_console_init(void)
{
register_console(&ulite_console);
return 0;
}
console_initcall(ulite_console_init);
static void early_uartlite_putc(struct uart_port *port, int c) static void early_uartlite_putc(struct uart_port *port, int c)
{ {
/* /*
...@@ -660,6 +655,17 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, ...@@ -660,6 +655,17 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
dev_set_drvdata(dev, port); dev_set_drvdata(dev, port);
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
/*
* If console hasn't been found yet try to assign this port
* because it is required to be assigned for console setup function.
* If register_console() don't assign value, then console_port pointer
* is cleanup.
*/
if (ulite_uart_driver.cons->index == -1)
console_port = port;
#endif
/* Register the port */ /* Register the port */
rc = uart_add_one_port(&ulite_uart_driver, port); rc = uart_add_one_port(&ulite_uart_driver, port);
if (rc) { if (rc) {
...@@ -669,6 +675,12 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, ...@@ -669,6 +675,12 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
return rc; return rc;
} }
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
/* This is not port which is used for console that's why clean it up */
if (ulite_uart_driver.cons->index == -1)
console_port = NULL;
#endif
return 0; return 0;
} }
...@@ -776,13 +788,26 @@ static int ulite_probe(struct platform_device *pdev) ...@@ -776,13 +788,26 @@ static int ulite_probe(struct platform_device *pdev)
pdata->clk = NULL; pdata->clk = NULL;
} }
ret = clk_prepare(pdata->clk); ret = clk_prepare_enable(pdata->clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to prepare clock\n"); dev_err(&pdev->dev, "Failed to prepare clock\n");
return ret; return ret;
} }
return ulite_assign(&pdev->dev, id, res->start, irq, pdata); if (!ulite_uart_driver.state) {
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register driver\n");
return ret;
}
}
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
clk_disable(pdata->clk);
return ret;
} }
static int ulite_remove(struct platform_device *pdev) static int ulite_remove(struct platform_device *pdev)
...@@ -813,25 +838,9 @@ static struct platform_driver ulite_platform_driver = { ...@@ -813,25 +838,9 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void) static int __init ulite_init(void)
{ {
int ret;
pr_debug("uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret)
goto err_uart;
pr_debug("uartlite: calling platform_driver_register()\n"); pr_debug("uartlite: calling platform_driver_register()\n");
ret = platform_driver_register(&ulite_platform_driver); return platform_driver_register(&ulite_platform_driver);
if (ret)
goto err_plat;
return 0;
err_plat:
uart_unregister_driver(&ulite_uart_driver);
err_uart:
pr_err("registering uartlite driver failed: err=%i\n", ret);
return ret;
} }
static void __exit ulite_exit(void) static void __exit ulite_exit(void)
......
This diff is collapsed.
...@@ -118,9 +118,12 @@ void tty_buffer_free_all(struct tty_port *port) ...@@ -118,9 +118,12 @@ void tty_buffer_free_all(struct tty_port *port)
struct tty_bufhead *buf = &port->buf; struct tty_bufhead *buf = &port->buf;
struct tty_buffer *p, *next; struct tty_buffer *p, *next;
struct llist_node *llist; struct llist_node *llist;
unsigned int freed = 0;
int still_used;
while ((p = buf->head) != NULL) { while ((p = buf->head) != NULL) {
buf->head = p->next; buf->head = p->next;
freed += p->size;
if (p->size > 0) if (p->size > 0)
kfree(p); kfree(p);
} }
...@@ -132,7 +135,9 @@ void tty_buffer_free_all(struct tty_port *port) ...@@ -132,7 +135,9 @@ void tty_buffer_free_all(struct tty_port *port)
buf->head = &buf->sentinel; buf->head = &buf->sentinel;
buf->tail = &buf->sentinel; buf->tail = &buf->sentinel;
atomic_set(&buf->mem_used, 0); still_used = atomic_xchg(&buf->mem_used, 0);
WARN(still_used != freed, "we still have not freed %d bytes!",
still_used - freed);
} }
/** /**
...@@ -468,11 +473,15 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count) ...@@ -468,11 +473,15 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
{ {
unsigned char *p = char_buf_ptr(head, head->read); unsigned char *p = char_buf_ptr(head, head->read);
char *f = NULL; char *f = NULL;
int n;
if (~head->flags & TTYB_NORMAL) if (~head->flags & TTYB_NORMAL)
f = flag_buf_ptr(head, head->read); f = flag_buf_ptr(head, head->read);
return port->client_ops->receive_buf(port, p, f, count); n = port->client_ops->receive_buf(port, p, f, count);
if (n > 0)
memset(p, 0, n);
return n;
} }
/** /**
......
...@@ -409,7 +409,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) ...@@ -409,7 +409,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
/* Search through the tty devices to look for a match */ /* Search through the tty devices to look for a match */
list_for_each_entry(p, &tty_drivers, tty_drivers) { list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (strncmp(name, p->name, len) != 0) if (!len || strncmp(name, p->name, len) != 0)
continue; continue;
stp = str; stp = str;
if (*stp == ',') if (*stp == ',')
......
...@@ -279,7 +279,6 @@ EXPORT_SYMBOL(tty_port_put); ...@@ -279,7 +279,6 @@ EXPORT_SYMBOL(tty_port_put);
* Return a refcount protected tty instance or NULL if the port is not * Return a refcount protected tty instance or NULL if the port is not
* associated with a tty (eg due to close or hangup) * associated with a tty (eg due to close or hangup)
*/ */
struct tty_struct *tty_port_tty_get(struct tty_port *port) struct tty_struct *tty_port_tty_get(struct tty_port *port)
{ {
unsigned long flags; unsigned long flags;
...@@ -300,7 +299,6 @@ EXPORT_SYMBOL(tty_port_tty_get); ...@@ -300,7 +299,6 @@ EXPORT_SYMBOL(tty_port_tty_get);
* Associate the port and tty pair. Manages any internal refcounts. * Associate the port and tty pair. Manages any internal refcounts.
* Pass NULL to deassociate a port * Pass NULL to deassociate a port
*/ */
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
{ {
unsigned long flags; unsigned long flags;
...@@ -343,7 +341,6 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) ...@@ -343,7 +341,6 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
* *
* Caller holds tty lock. * Caller holds tty lock.
*/ */
void tty_port_hangup(struct tty_port *port) void tty_port_hangup(struct tty_port *port)
{ {
struct tty_struct *tty; struct tty_struct *tty;
...@@ -399,7 +396,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup); ...@@ -399,7 +396,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
* to hide some internal details. This will eventually become entirely * to hide some internal details. This will eventually become entirely
* internal to the tty port. * internal to the tty port.
*/ */
int tty_port_carrier_raised(struct tty_port *port) int tty_port_carrier_raised(struct tty_port *port)
{ {
if (port->ops->carrier_raised == NULL) if (port->ops->carrier_raised == NULL)
...@@ -416,7 +412,6 @@ EXPORT_SYMBOL(tty_port_carrier_raised); ...@@ -416,7 +412,6 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
* to hide some internal details. This will eventually become entirely * to hide some internal details. This will eventually become entirely
* internal to the tty port. * internal to the tty port.
*/ */
void tty_port_raise_dtr_rts(struct tty_port *port) void tty_port_raise_dtr_rts(struct tty_port *port)
{ {
if (port->ops->dtr_rts) if (port->ops->dtr_rts)
...@@ -432,7 +427,6 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts); ...@@ -432,7 +427,6 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
* to hide some internal details. This will eventually become entirely * to hide some internal details. This will eventually become entirely
* internal to the tty port. * internal to the tty port.
*/ */
void tty_port_lower_dtr_rts(struct tty_port *port) void tty_port_lower_dtr_rts(struct tty_port *port)
{ {
if (port->ops->dtr_rts) if (port->ops->dtr_rts)
...@@ -464,7 +458,6 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts); ...@@ -464,7 +458,6 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
* NB: May drop and reacquire tty lock when blocking, so tty and tty_port * NB: May drop and reacquire tty lock when blocking, so tty and tty_port
* may have changed state (eg., may have been hung up). * may have changed state (eg., may have been hung up).
*/ */
int tty_port_block_til_ready(struct tty_port *port, int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp) struct tty_struct *tty, struct file *filp)
{ {
......
...@@ -388,6 +388,9 @@ extern int of_phandle_iterator_args(struct of_phandle_iterator *it, ...@@ -388,6 +388,9 @@ extern int of_phandle_iterator_args(struct of_phandle_iterator *it,
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)); extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
extern int of_alias_get_id(struct device_node *np, const char *stem); extern int of_alias_get_id(struct device_node *np, const char *stem);
extern int of_alias_get_highest_id(const char *stem); extern int of_alias_get_highest_id(const char *stem);
extern int of_alias_get_alias_list(const struct of_device_id *matches,
const char *stem, unsigned long *bitmap,
unsigned int nbits);
extern int of_machine_is_compatible(const char *compat); extern int of_machine_is_compatible(const char *compat);
...@@ -898,6 +901,13 @@ static inline int of_alias_get_highest_id(const char *stem) ...@@ -898,6 +901,13 @@ static inline int of_alias_get_highest_id(const char *stem)
return -ENOSYS; return -ENOSYS;
} }
static inline int of_alias_get_alias_list(const struct of_device_id *matches,
const char *stem, unsigned long *bitmap,
unsigned int nbits)
{
return -ENOSYS;
}
static inline int of_machine_is_compatible(const char *compat) static inline int of_machine_is_compatible(const char *compat)
{ {
return 0; return 0;
......
...@@ -144,6 +144,8 @@ struct uart_port { ...@@ -144,6 +144,8 @@ struct uart_port {
void (*handle_break)(struct uart_port *); void (*handle_break)(struct uart_port *);
int (*rs485_config)(struct uart_port *, int (*rs485_config)(struct uart_port *,
struct serial_rs485 *rs485); struct serial_rs485 *rs485);
int (*iso7816_config)(struct uart_port *,
struct serial_iso7816 *iso7816);
unsigned int irq; /* irq number */ unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */ unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */ unsigned int uartclk; /* base uart clock */
...@@ -260,6 +262,7 @@ struct uart_port { ...@@ -260,6 +262,7 @@ struct uart_port {
struct attribute_group *attr_group; /* port specific attributes */ struct attribute_group *attr_group; /* port specific attributes */
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */ const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
struct serial_rs485 rs485; struct serial_rs485 rs485;
struct serial_iso7816 iso7816;
void *private_data; /* generic platform data pointer */ void *private_data; /* generic platform data pointer */
}; };
......
...@@ -79,6 +79,8 @@ ...@@ -79,6 +79,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ #define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ #define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */ #define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define FIONCLEX 0x5450 #define FIONCLEX 0x5450
#define FIOCLEX 0x5451 #define FIOCLEX 0x5451
......
...@@ -132,4 +132,21 @@ struct serial_rs485 { ...@@ -132,4 +132,21 @@ struct serial_rs485 {
are a royal PITA .. */ are a royal PITA .. */
}; };
/*
* Serial interface for controlling ISO7816 settings on chips with suitable
* support. Set with TIOCSISO7816 and get with TIOCGISO7816 if supported by
* your platform.
*/
struct serial_iso7816 {
__u32 flags; /* ISO7816 feature flags */
#define SER_ISO7816_ENABLED (1 << 0)
#define SER_ISO7816_T_PARAM (0x0f << 4)
#define SER_ISO7816_T(t) (((t) & 0x0f) << 4)
__u32 tg;
__u32 sc_fi;
__u32 sc_di;
__u32 clk;
__u32 reserved[5];
};
#endif /* _UAPI_LINUX_SERIAL_H */ #endif /* _UAPI_LINUX_SERIAL_H */
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