forked from luck/tmp_suning_uos_patched
TTY/Serial patches for 4.20-rc1
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW9bW0w8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymYhgCfbxr0T+4lF/rpGxNXNnV4u5boRJUAn2L8R+1y URbAWHvKfaby2AVfQ1z0 =qTHH -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
5bd4af34a0
|
@ -14,6 +14,10 @@ Required properties:
|
|||
- "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB 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,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
|
||||
|
@ -50,6 +54,8 @@ Required properties:
|
|||
- "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF 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,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,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART.
|
||||
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||
|
|
|
@ -7,7 +7,7 @@ Required properties:
|
|||
- clocks: phandle to the input clock.
|
||||
|
||||
Optional properties:
|
||||
- fifo-size: the RX/TX FIFO size. Defaults to 64 if not specified.
|
||||
-auto-flow-control: enable automatic flow control support.
|
||||
|
||||
Example:
|
||||
aliases {
|
||||
|
@ -19,5 +19,4 @@ Example:
|
|||
reg = <0x54006800 0x40>;
|
||||
interrupts = <0 33 4>;
|
||||
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
|
|||
driver. It is not complete, any questions you have should be directed to
|
||||
<rmk@arm.linux.org.uk>
|
||||
|
||||
The reference implementation is contained within amba_pl011.c.
|
||||
The reference implementation is contained within amba-pl011.c.
|
||||
|
||||
|
||||
|
||||
|
|
83
Documentation/serial/serial-iso7816.txt
Normal file
83
Documentation/serial/serial-iso7816.txt
Normal file
|
@ -0,0 +1,83 @@
|
|||
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 @@
|
|||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#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 TIOCSERGWILD 0x5454
|
||||
|
|
|
@ -93,6 +93,8 @@
|
|||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#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 ... */
|
||||
#define TIOCSCTTY 0x5480 /* become controlling tty */
|
||||
|
|
|
@ -62,6 +62,8 @@
|
|||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#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 FIOCLEX 0x5451
|
||||
|
|
|
@ -102,6 +102,8 @@
|
|||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#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 TIOCSERGWILD 0x5454
|
||||
|
|
|
@ -95,6 +95,8 @@
|
|||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#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 TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGRS485 _IOR('T', 0x41, 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
|
||||
* double underscore on the front to: a) avoid some programs to
|
||||
|
|
|
@ -107,6 +107,8 @@
|
|||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#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 TIOCSERGWILD _IOR('T', 84, int)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#define pr_fmt(fmt) "OF: " fmt
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/cpu.h>
|
||||
|
@ -1985,6 +1986,59 @@ int of_alias_get_id(struct device_node *np, const char *stem)
|
|||
}
|
||||
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
|
||||
* @stem: Alias stem to be examined
|
||||
|
|
|
@ -128,8 +128,8 @@ static int find_console_handle(void)
|
|||
*/
|
||||
iprop = of_get_property(np, "hv-handle", NULL);
|
||||
if (!iprop) {
|
||||
pr_err("ehv-bc: no 'hv-handle' property in %s node\n",
|
||||
np->name);
|
||||
pr_err("ehv-bc: no 'hv-handle' property in %pOFn node\n",
|
||||
np);
|
||||
return 0;
|
||||
}
|
||||
stdout_bc = be32_to_cpu(*iprop);
|
||||
|
@ -661,8 +661,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
|
|||
|
||||
iprop = of_get_property(np, "hv-handle", NULL);
|
||||
if (!iprop) {
|
||||
dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n",
|
||||
np->name);
|
||||
dev_err(&pdev->dev, "no 'hv-handle' property in %pOFn node\n",
|
||||
np);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -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->tx_irq = irq_of_parse_and_map(np, 1);
|
||||
if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
|
||||
dev_err(&pdev->dev, "no 'interrupts' property in %s node\n",
|
||||
np->name);
|
||||
dev_err(&pdev->dev, "no 'interrupts' property in %pOFn node\n",
|
||||
np);
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
|
|
@ -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)];
|
||||
}
|
||||
|
||||
/* 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,
|
||||
size_t tail, size_t n)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
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;
|
||||
|
||||
if (n > size) {
|
||||
tty_audit_add_data(tty, from, size);
|
||||
uncopied = copy_to_user(to, from, size);
|
||||
zero_buffer(tty, from, size - uncopied);
|
||||
if (uncopied)
|
||||
return uncopied;
|
||||
to += size;
|
||||
|
@ -171,7 +182,9 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
|
|||
}
|
||||
|
||||
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,
|
|||
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
|
||||
n = min(*nr, 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);
|
||||
n -= retval;
|
||||
is_eof = n == 1 && *from == EOF_CHAR(tty);
|
||||
tty_audit_add_data(tty, from, n);
|
||||
zero_buffer(tty, from, n);
|
||||
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
|
||||
/* Turn single EOF into zero-length read */
|
||||
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
|
||||
|
|
|
@ -130,12 +130,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
|
|||
|
||||
l = l->next;
|
||||
|
||||
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);
|
||||
if (l == i->head && pass_counter++ > PASS_LIMIT)
|
||||
break;
|
||||
}
|
||||
} while (l != end);
|
||||
|
||||
spin_unlock(&i->lock);
|
||||
|
|
|
@ -58,7 +58,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||
struct resource resource;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
u32 clk, spd, prop;
|
||||
int ret;
|
||||
int ret, irq;
|
||||
|
||||
memset(port, 0, sizeof *port);
|
||||
|
||||
|
@ -143,21 +143,27 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||
if (ret >= 0)
|
||||
port->line = ret;
|
||||
|
||||
port->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!port->irq) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_unprepare;
|
||||
irq = of_irq_get(np, 0);
|
||||
if (irq < 0) {
|
||||
if (irq == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_unprepare;
|
||||
}
|
||||
/* IRQ support not mandatory */
|
||||
irq = 0;
|
||||
}
|
||||
|
||||
port->irq = irq;
|
||||
|
||||
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
|
||||
if (IS_ERR(info->rst)) {
|
||||
ret = PTR_ERR(info->rst);
|
||||
goto err_dispose;
|
||||
goto err_unprepare;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(info->rst);
|
||||
if (ret)
|
||||
goto err_dispose;
|
||||
goto err_unprepare;
|
||||
|
||||
port->type = type;
|
||||
port->uartclk = clk;
|
||||
|
@ -184,8 +190,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||
port->handle_irq = fsl8250_handle_irq;
|
||||
|
||||
return 0;
|
||||
err_dispose:
|
||||
irq_dispose_mapping(port->irq);
|
||||
err_unprepare:
|
||||
clk_disable_unprepare(info->clk);
|
||||
err_pmruntime:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
unsigned char fcr;
|
||||
unsigned char clr_mask = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
|
||||
|
||||
if (p->capabilities & UART_CAP_FIFO) {
|
||||
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO |
|
||||
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||
serial_out(p, UART_FCR, 0);
|
||||
/*
|
||||
* Make sure to avoid changing FCR[7:3] and ENABLE_FIFO bits.
|
||||
* In case ENABLE_FIFO is not set, there is nothing to flush
|
||||
* 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)
|
|||
* Enable previously disabled RX interrupts.
|
||||
*/
|
||||
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;
|
||||
serial_port_out(&p->port, UART_IER, p->ier);
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
|
||||
#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:
|
||||
* - MMIO32 (regshift = 2)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
@ -226,9 +187,24 @@ static int uniphier_uart_probe(struct platform_device *pdev)
|
|||
|
||||
memset(&up, 0, sizeof(up));
|
||||
|
||||
ret = uniphier_of_serial_setup(dev, &up.port, priv);
|
||||
if (ret < 0)
|
||||
ret = of_alias_get_id(dev->of_node, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get alias id\n");
|
||||
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);
|
||||
|
||||
|
@ -241,10 +217,14 @@ static int uniphier_uart_probe(struct platform_device *pdev)
|
|||
|
||||
up.port.type = PORT_16550A;
|
||||
up.port.iotype = UPIO_MEM32;
|
||||
up.port.fifosize = 64;
|
||||
up.port.regshift = UNIPHIER_UART_REGSHIFT;
|
||||
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
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_out = uniphier_serial_out;
|
||||
up.dl_read = uniphier_serial_dl_read;
|
||||
|
|
|
@ -375,7 +375,7 @@ config SERIAL_8250_RT288X
|
|||
|
||||
config SERIAL_8250_OMAP
|
||||
tristate "Support for OMAP internal UART (8250 based driver)"
|
||||
depends on SERIAL_8250 && ARCH_OMAP2PLUS
|
||||
depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3)
|
||||
help
|
||||
If you have a machine based on an Texas Instruments OMAP CPU you
|
||||
can enable its onboard serial ports by enabling this option.
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/suspend.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/ioctls.h>
|
||||
|
||||
|
@ -147,6 +148,8 @@ struct atmel_uart_port {
|
|||
struct circ_buf rx_ring;
|
||||
|
||||
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;
|
||||
u32 fifo_size;
|
||||
u32 rts_high;
|
||||
|
@ -163,6 +166,10 @@ struct atmel_uart_port {
|
|||
unsigned int pending_status;
|
||||
spinlock_t lock_suspended;
|
||||
|
||||
/* ISO7816 */
|
||||
unsigned int fidi_min;
|
||||
unsigned int fidi_max;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct {
|
||||
u32 cr;
|
||||
|
@ -361,6 +368,127 @@ static int atmel_config_rs485(struct uart_port *port,
|
|||
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.
|
||||
*/
|
||||
|
@ -480,8 +608,9 @@ static void atmel_stop_tx(struct uart_port *port)
|
|||
/* Disable interrupts */
|
||||
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
|
||||
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
if (((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
|
||||
port->iso7816.flags & SER_ISO7816_ENABLED)
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
|
||||
|
@ -499,8 +628,9 @@ static void atmel_start_tx(struct uart_port *port)
|
|||
return;
|
||||
|
||||
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
if (((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
|
||||
port->iso7816.flags & SER_ISO7816_ENABLED)
|
||||
atmel_stop_rx(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port))
|
||||
|
@ -798,8 +928,9 @@ static void atmel_complete_tx_dma(void *arg)
|
|||
*/
|
||||
if (!uart_circ_empty(xmit))
|
||||
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
|
||||
else if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
else if (((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
|
||||
port->iso7816.flags & SER_ISO7816_ENABLED) {
|
||||
/* DMA done, stop TX, start RX for RS485 */
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
|
@ -1282,6 +1413,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
|
|||
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)
|
|||
atmel_uart_writel(port, ATMEL_US_IER,
|
||||
atmel_port->tx_done_mask);
|
||||
} else {
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
if (((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
|
||||
port->iso7816.flags & SER_ISO7816_ENABLED) {
|
||||
/* DMA done, stop TX, start RX for RS485 */
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
|
@ -1727,6 +1862,22 @@ static void atmel_get_ip_name(struct uart_port *port)
|
|||
atmel_port->has_frac_baudrate = true;
|
||||
atmel_port->has_hw_timer = true;
|
||||
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) {
|
||||
dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
|
||||
} else {
|
||||
|
@ -2100,6 +2251,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
atmel_uart_writel(port, ATMEL_US_TTGR,
|
||||
port->rs485.delay_rts_after_send);
|
||||
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) {
|
||||
/* RS232 with hardware handshake (RTS/CTS) */
|
||||
if (atmel_use_fifo(port) &&
|
||||
|
@ -2176,7 +2338,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
}
|
||||
quot = cd | fp << ATMEL_US_FP_OFFSET;
|
||||
|
||||
atmel_uart_writel(port, ATMEL_US_BRGR, quot);
|
||||
if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
|
||||
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_TXEN | ATMEL_US_RXEN);
|
||||
atmel_port->tx_stopped = false;
|
||||
|
@ -2357,6 +2520,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||
port->mapbase = mpdev->resource[0].start;
|
||||
port->irq = mpdev->resource[1].start;
|
||||
port->rs485_config = atmel_config_rs485;
|
||||
port->iso7816_config = atmel_config_iso7816;
|
||||
port->membase = NULL;
|
||||
|
||||
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,
|
|||
/* 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;
|
||||
else if (atmel_use_pdc_tx(port)) {
|
||||
port->fifosize = PDC_BUFFER_SIZE;
|
||||
|
|
|
@ -78,7 +78,8 @@
|
|||
#define ATMEL_US_OVER BIT(19) /* Oversampling Mode */
|
||||
#define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */
|
||||
#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_IER 0x08 /* Interrupt Enable Register */
|
||||
|
|
|
@ -1155,8 +1155,8 @@ static int cpm_uart_init_port(struct device_node *np,
|
|||
if (!pinfo->clk) {
|
||||
data = of_get_property(np, "fsl,cpm-brg", &len);
|
||||
if (!data || len != 4) {
|
||||
printk(KERN_ERR "CPM UART %s has no/invalid "
|
||||
"fsl,cpm-brg property.\n", np->name);
|
||||
printk(KERN_ERR "CPM UART %pOFn has no/invalid "
|
||||
"fsl,cpm-brg property.\n", np);
|
||||
return -EINVAL;
|
||||
}
|
||||
pinfo->brg = *data;
|
||||
|
@ -1164,8 +1164,8 @@ static int cpm_uart_init_port(struct device_node *np,
|
|||
|
||||
data = of_get_property(np, "fsl,cpm-command", &len);
|
||||
if (!data || len != 4) {
|
||||
printk(KERN_ERR "CPM UART %s has no/invalid "
|
||||
"fsl,cpm-command property.\n", np->name);
|
||||
printk(KERN_ERR "CPM UART %pOFn has no/invalid "
|
||||
"fsl,cpm-command property.\n", np);
|
||||
return -EINVAL;
|
||||
}
|
||||
pinfo->command = *data;
|
||||
|
|
|
@ -232,6 +232,8 @@
|
|||
/* IMX lpuart has four extra unused regs located at the beginning */
|
||||
#define IMX_REG_OFF 0x10
|
||||
|
||||
static DEFINE_IDA(fsl_lpuart_ida);
|
||||
|
||||
struct lpuart_port {
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
|
@ -2143,8 +2145,11 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
|
||||
return 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;
|
||||
}
|
||||
}
|
||||
if (ret >= ARRAY_SIZE(lpuart_ports)) {
|
||||
dev_err(&pdev->dev, "serial%d out of range\n", ret);
|
||||
|
@ -2246,6 +2251,8 @@ static int lpuart_remove(struct platform_device *pdev)
|
|||
|
||||
uart_remove_one_port(&lpuart_reg, &sport->port);
|
||||
|
||||
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
|
||||
|
||||
clk_disable_unprepare(sport->clk);
|
||||
|
||||
if (sport->dma_tx_chan)
|
||||
|
@ -2384,6 +2391,7 @@ static int __init lpuart_serial_init(void)
|
|||
|
||||
static void __exit lpuart_serial_exit(void)
|
||||
{
|
||||
ida_destroy(&fsl_lpuart_ida);
|
||||
platform_driver_unregister(&lpuart_driver);
|
||||
uart_unregister_driver(&lpuart_reg);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/rational.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -706,27 +707,25 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id)
|
|||
{
|
||||
struct imx_port *sport = dev_id;
|
||||
u32 usr1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
spin_lock(&sport->port.lock);
|
||||
|
||||
imx_uart_writel(sport, USR1_RTSD, USR1);
|
||||
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
|
||||
uart_handle_cts_change(&sport->port, !!usr1);
|
||||
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;
|
||||
}
|
||||
|
||||
static irqreturn_t imx_uart_txint(int irq, void *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);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
spin_unlock(&sport->port.lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -735,9 +734,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
|
|||
struct imx_port *sport = dev_id;
|
||||
unsigned int rx, flg, ignored = 0;
|
||||
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) {
|
||||
u32 usr2;
|
||||
|
@ -797,7 +795,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
spin_unlock(&sport->port.lock);
|
||||
tty_flip_buffer_push(port);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -903,13 +901,11 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
if (usr1 & USR1_DTRD) {
|
||||
unsigned long flags;
|
||||
|
||||
imx_uart_writel(sport, USR1_DTRD, USR1);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
spin_lock(&sport->port.lock);
|
||||
imx_uart_mctrl_check(sport);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
spin_unlock(&sport->port.lock);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
@ -2384,8 +2380,13 @@ static int imx_uart_remove(struct platform_device *pdev)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
imx_uart_writel(sport, sport->saved_reg[4], UFCR);
|
||||
imx_uart_writel(sport, sport->saved_reg[5], UESC);
|
||||
|
@ -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[3], UCR4);
|
||||
sport->context_saved = false;
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static void imx_uart_save_context(struct imx_port *sport)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* Save necessary regs */
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
sport->saved_reg[0] = imx_uart_readl(sport, UCR1);
|
||||
sport->saved_reg[1] = imx_uart_readl(sport, UCR2);
|
||||
sport->saved_reg[2] = imx_uart_readl(sport, UCR3);
|
||||
|
@ -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[9] = imx_uart_readl(sport, IMX21_UTS);
|
||||
sport->context_saved = true;
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
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)
|
|||
|
||||
clk_disable(sport->clk_ipg);
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2455,6 +2463,8 @@ static int imx_uart_resume_noirq(struct device *dev)
|
|||
struct imx_port *sport = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
ret = clk_enable(sport->clk_ipg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
*
|
||||
* 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kgdb.h>
|
||||
|
@ -128,19 +131,6 @@ static void kgdboc_unregister_kbd(void)
|
|||
#define kgdboc_restore_input()
|
||||
#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)
|
||||
{
|
||||
if (kgdb_unregister_nmi_console())
|
||||
|
@ -154,15 +144,13 @@ static int configure_kgdboc(void)
|
|||
{
|
||||
struct tty_driver *p;
|
||||
int tty_line = 0;
|
||||
int err;
|
||||
int err = -ENODEV;
|
||||
char *cptr = config;
|
||||
struct console *cons;
|
||||
|
||||
err = kgdboc_option_setup(config);
|
||||
if (err || !strlen(config) || isspace(config[0]))
|
||||
if (!strlen(config) || isspace(config[0]))
|
||||
goto noconfig;
|
||||
|
||||
err = -ENODEV;
|
||||
kgdboc_io_ops.is_console = 0;
|
||||
kgdb_tty_driver = NULL;
|
||||
|
||||
|
@ -248,7 +236,7 @@ static int param_set_kgdboc_var(const char *kmessage,
|
|||
int len = strlen(kmessage);
|
||||
|
||||
if (len >= MAX_CONFIG_LEN) {
|
||||
printk(KERN_ERR "kgdboc: config string too long\n");
|
||||
pr_err("config string too long\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
|
@ -259,8 +247,7 @@ static int param_set_kgdboc_var(const char *kmessage,
|
|||
}
|
||||
|
||||
if (kgdb_connected) {
|
||||
printk(KERN_ERR
|
||||
"kgdboc: Cannot reconfigure while KGDB is connected.\n");
|
||||
pr_err("Cannot reconfigure while KGDB is connected.\n");
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -311,6 +298,25 @@ static struct kgdb_io kgdboc_io_ops = {
|
|||
};
|
||||
|
||||
#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 */
|
||||
static int __init kgdboc_early_init(char *opt)
|
||||
{
|
||||
|
|
|
@ -1634,8 +1634,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
|
|||
|
||||
/*
|
||||
* If something went wrong, rollback.
|
||||
* Be careful: i may be unsigned.
|
||||
*/
|
||||
while (err && (--i >= 0))
|
||||
while (err && (i-- > 0))
|
||||
if (irq[i] >= 0)
|
||||
free_irq(irq[i], s);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
struct tty_port *port;
|
||||
unsigned char ch, r1, drop, error, flag;
|
||||
unsigned char ch, r1, drop, flag;
|
||||
int loops = 0;
|
||||
|
||||
/* 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)
|
|||
port = &uap->port.state->port;
|
||||
|
||||
while (1) {
|
||||
error = 0;
|
||||
drop = 0;
|
||||
|
||||
r1 = read_zsreg(uap, R1);
|
||||
|
@ -273,7 +272,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
|
|||
uap->port.icount.rx++;
|
||||
|
||||
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
|
||||
error = 1;
|
||||
if (r1 & BRK_ABRT) {
|
||||
pmz_debug("pmz: got break !\n");
|
||||
r1 &= ~(PAR_ERR | CRC_ERR);
|
||||
|
@ -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
|
||||
*/
|
||||
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",
|
||||
uap->node->name);
|
||||
uap->node);
|
||||
else
|
||||
uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;
|
||||
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
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)
|
|||
return -ENOMEM;
|
||||
}
|
||||
port->setup = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_startup(struct uart_port *uport)
|
||||
{
|
||||
int ret;
|
||||
u32 proto;
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
|
||||
|
||||
scnprintf(port->name, sizeof(port->name),
|
||||
"qcom_serial_%s%d",
|
||||
(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) {
|
||||
ret = qcom_geni_serial_port_setup(uport);
|
||||
if (ret)
|
||||
|
@ -1056,6 +1062,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
|
|||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
int ret;
|
||||
|
||||
if (co->index >= GENI_UART_CONS_PORTS || co->index < 0)
|
||||
return -ENXIO;
|
||||
|
@ -1071,21 +1078,10 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
|
|||
if (unlikely(!uport->membase))
|
||||
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) {
|
||||
port->tx_bytes_pw = 1;
|
||||
port->rx_bytes_pw = RX_BYTES_PW;
|
||||
qcom_geni_serial_stop_rx(uport);
|
||||
qcom_geni_serial_port_setup(uport);
|
||||
ret = qcom_geni_serial_port_setup(uport);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (options)
|
||||
|
@ -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);
|
||||
|
||||
/* 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)
|
||||
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 &&
|
||||
old_state == UART_PM_STATE_ON)
|
||||
geni_se_resources_off(&port->se);
|
||||
|
@ -1263,14 +1260,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
|||
if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart"))
|
||||
console = true;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
if (console) {
|
||||
drv = &qcom_geni_console_driver;
|
||||
line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
} else {
|
||||
drv = &qcom_geni_uart_driver;
|
||||
line = of_alias_get_id(pdev->dev.of_node, "hsuart");
|
||||
}
|
||||
if (console) {
|
||||
drv = &qcom_geni_console_driver;
|
||||
line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
} else {
|
||||
drv = &qcom_geni_uart_driver;
|
||||
line = of_alias_get_id(pdev->dev.of_node, "hsuart");
|
||||
}
|
||||
|
||||
port = get_port_from_line(line, console);
|
||||
|
|
|
@ -1941,7 +1941,11 @@ static int s3c24xx_serial_resume(struct device *dev)
|
|||
|
||||
if (port) {
|
||||
clk_prepare_enable(ourport->clk);
|
||||
if (!IS_ERR(ourport->baudclk))
|
||||
clk_prepare_enable(ourport->baudclk);
|
||||
s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
|
||||
if (!IS_ERR(ourport->baudclk))
|
||||
clk_disable_unprepare(ourport->baudclk);
|
||||
clk_disable_unprepare(ourport->clk);
|
||||
|
||||
uart_resume_port(&s3c24xx_uart_drv, port);
|
||||
|
@ -1964,7 +1968,11 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
|
|||
if (rx_enabled(port))
|
||||
uintm &= ~S3C64XX_UINTM_RXD_MSK;
|
||||
clk_prepare_enable(ourport->clk);
|
||||
if (!IS_ERR(ourport->baudclk))
|
||||
clk_prepare_enable(ourport->baudclk);
|
||||
wr_regl(port, S3C64XX_UINTM, uintm);
|
||||
if (!IS_ERR(ourport->baudclk))
|
||||
clk_disable_unprepare(ourport->baudclk);
|
||||
clk_disable_unprepare(ourport->clk);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -328,6 +328,7 @@ struct sc16is7xx_port {
|
|||
struct kthread_worker kworker;
|
||||
struct task_struct *kworker_task;
|
||||
struct kthread_work irq_work;
|
||||
struct mutex efr_lock;
|
||||
struct sc16is7xx_one p[0];
|
||||
};
|
||||
|
||||
|
@ -499,6 +500,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
|
|||
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);
|
||||
|
||||
/* Open the LCR divisors for configuration */
|
||||
|
@ -514,6 +530,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
|
|||
/* Put LCR back to the normal mode */
|
||||
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
|
||||
|
||||
mutex_unlock(&s->efr_lock);
|
||||
|
||||
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_CLKSEL_BIT,
|
||||
prescaler);
|
||||
|
@ -657,7 +675,7 @@ static void sc16is7xx_handle_tx(struct uart_port *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;
|
||||
|
||||
|
@ -666,7 +684,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
|||
|
||||
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
|
||||
if (iir & SC16IS7XX_IIR_NO_INT_BIT)
|
||||
break;
|
||||
return false;
|
||||
|
||||
iir &= SC16IS7XX_IIR_ID_MASK;
|
||||
|
||||
|
@ -688,16 +706,27 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
|||
port->line, iir);
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
} while (0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sc16is7xx_ist(struct kthread_work *ws)
|
||||
{
|
||||
struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->devtype->nr_uart; ++i)
|
||||
sc16is7xx_port_irq(s, i);
|
||||
mutex_lock(&s->efr_lock);
|
||||
|
||||
while (1) {
|
||||
bool keep_polling = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->devtype->nr_uart; ++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)
|
||||
|
@ -892,6 +921,9 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
|||
if (!(termios->c_cflag & CREAD))
|
||||
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_LCR_CONF_MODE_B);
|
||||
|
||||
|
@ -913,6 +945,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
|||
/* Update LCR register */
|
||||
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
|
||||
|
||||
mutex_unlock(&s->efr_lock);
|
||||
|
||||
/* Get baud rate generator configuration */
|
||||
baud = uart_get_baud_rate(port, termios, old,
|
||||
port->uartclk / 16 / 4 / 0xffff,
|
||||
|
@ -1178,6 +1212,7 @@ static int sc16is7xx_probe(struct device *dev,
|
|||
s->regmap = regmap;
|
||||
s->devtype = devtype;
|
||||
dev_set_drvdata(dev, s);
|
||||
mutex_init(&s->efr_lock);
|
||||
|
||||
kthread_init_worker(&s->kworker);
|
||||
kthread_init_work(&s->irq_work, sc16is7xx_ist);
|
||||
|
|
|
@ -1302,6 +1302,58 @@ static int uart_set_rs485_config(struct uart_port *port,
|
|||
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.
|
||||
*/
|
||||
|
@ -1371,6 +1423,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
|||
case TIOCSRS485:
|
||||
ret = uart_set_rs485_config(uport, uarg);
|
||||
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:
|
||||
if (uport->ops->ioctl)
|
||||
ret = uport->ops->ioctl(uport, cmd, arg);
|
||||
|
|
|
@ -1516,7 +1516,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
|
|||
chan = dma_request_slave_channel(port->dev,
|
||||
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
|
||||
if (!chan) {
|
||||
dev_warn(port->dev, "dma_request_slave_channel failed\n");
|
||||
dev_dbg(port->dev, "dma_request_slave_channel failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -3414,6 +3414,12 @@ static int __init scif_early_console_setup(struct earlycon_device *device,
|
|||
{
|
||||
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,
|
||||
const char *opt)
|
||||
{
|
||||
|
@ -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(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(scifb, "renesas,scifb", scifb_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)
|
|||
|
||||
/* somebody really wants this output, might be an
|
||||
* 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 ltail = port->sc_port.state->xmit.tail;
|
||||
int counter, got_lock = 0;
|
||||
|
@ -905,13 +905,11 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
|
|||
*/
|
||||
|
||||
for (counter = 0; counter < 150; mdelay(125), counter++) {
|
||||
if (!spin_is_locked(&port->sc_port.lock)
|
||||
|| stole_lock) {
|
||||
if (!stole_lock) {
|
||||
spin_lock_irqsave(&port->sc_port.lock,
|
||||
flags);
|
||||
got_lock = 1;
|
||||
}
|
||||
if (stole_lock)
|
||||
break;
|
||||
|
||||
if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
|
||||
got_lock = 1;
|
||||
break;
|
||||
} else {
|
||||
/* still locked */
|
||||
|
@ -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);
|
||||
} else {
|
||||
stole_lock = 0;
|
||||
spin_lock_irqsave(&port->sc_port.lock, flags);
|
||||
sn_transmit_chars(port, 1);
|
||||
spin_unlock_irqrestore(&port->sc_port.lock, flags);
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
|
||||
/* data number in TX and RX fifo */
|
||||
#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 */
|
||||
#define SPRD_IEN 0x0010
|
||||
|
@ -66,67 +68,62 @@
|
|||
#define SPRD_LCR_DATA_LEN6 0x4
|
||||
#define SPRD_LCR_DATA_LEN7 0x8
|
||||
#define SPRD_LCR_DATA_LEN8 0xc
|
||||
#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
|
||||
#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
|
||||
#define SPRD_LCR_PARITY_EN 0x2
|
||||
#define SPRD_LCR_EVEN_PAR 0x0
|
||||
#define SPRD_LCR_ODD_PAR 0x1
|
||||
|
||||
/* control register 1 */
|
||||
#define SPRD_CTL1 0x001C
|
||||
#define SPRD_CTL1 0x001C
|
||||
#define RX_HW_FLOW_CTL_THLD BIT(6)
|
||||
#define RX_HW_FLOW_CTL_EN BIT(7)
|
||||
#define TX_HW_FLOW_CTL_EN BIT(8)
|
||||
#define RX_TOUT_THLD_DEF 0x3E00
|
||||
#define RX_HFC_THLD_DEF 0x40
|
||||
#define RX_HFC_THLD_DEF 0x40
|
||||
|
||||
/* fifo threshold register */
|
||||
#define SPRD_CTL2 0x0020
|
||||
#define THLD_TX_EMPTY 0x40
|
||||
#define THLD_RX_FULL 0x40
|
||||
#define THLD_TX_EMPTY 0x40
|
||||
#define THLD_TX_EMPTY_SHIFT 8
|
||||
#define THLD_RX_FULL 0x40
|
||||
|
||||
/* config baud rate register */
|
||||
#define SPRD_CLKD0 0x0024
|
||||
#define SPRD_CLKD0_MASK GENMASK(15, 0)
|
||||
#define SPRD_CLKD1 0x0028
|
||||
#define SPRD_CLKD1_MASK GENMASK(20, 16)
|
||||
#define SPRD_CLKD1_SHIFT 16
|
||||
|
||||
/* interrupt mask status register */
|
||||
#define SPRD_IMSR 0x002C
|
||||
#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
|
||||
#define SPRD_IMSR 0x002C
|
||||
#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
|
||||
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
|
||||
#define SPRD_IMSR_BREAK_DETECT BIT(7)
|
||||
#define SPRD_IMSR_TIMEOUT BIT(13)
|
||||
|
||||
struct reg_backup {
|
||||
u32 ien;
|
||||
u32 ctrl0;
|
||||
u32 ctrl1;
|
||||
u32 ctrl2;
|
||||
u32 clkd0;
|
||||
u32 clkd1;
|
||||
u32 dspwait;
|
||||
};
|
||||
#define SPRD_IMSR_BREAK_DETECT BIT(7)
|
||||
#define SPRD_IMSR_TIMEOUT BIT(13)
|
||||
|
||||
struct sprd_uart_port {
|
||||
struct uart_port port;
|
||||
struct reg_backup reg_bak;
|
||||
char name[16];
|
||||
};
|
||||
|
||||
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
else
|
||||
return TIOCSER_TEMT;
|
||||
|
@ -224,14 +221,15 @@ static inline void sprd_rx(struct uart_port *port)
|
|||
struct tty_port *tty = &port->state->port;
|
||||
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);
|
||||
ch = serial_in(port, SPRD_RXD);
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
|
||||
SPRD_LSR_FE | SPRD_LSR_OE))
|
||||
SPRD_LSR_FE | SPRD_LSR_OE))
|
||||
if (handle_lsr_errors(port, &lsr, &flag))
|
||||
continue;
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
|
@ -294,8 +292,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
|
|||
if (ims & SPRD_IMSR_TIMEOUT)
|
||||
serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
|
||||
|
||||
if (ims & (SPRD_IMSR_RX_FIFO_FULL |
|
||||
SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
|
||||
if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT |
|
||||
SPRD_IMSR_TIMEOUT))
|
||||
sprd_rx(port);
|
||||
|
||||
if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
|
||||
|
@ -314,16 +312,17 @@ static int sprd_startup(struct uart_port *port)
|
|||
struct sprd_uart_port *sp;
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* clear tx fifo */
|
||||
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();
|
||||
|
||||
/* clear interrupt */
|
||||
|
@ -334,7 +333,7 @@ static int sprd_startup(struct uart_port *port)
|
|||
sp = container_of(port, struct sprd_uart_port, port);
|
||||
snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
|
||||
ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
|
||||
IRQF_SHARED, sp->name, port);
|
||||
IRQF_SHARED, sp->name, port);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
|
||||
port->irq, ret);
|
||||
|
@ -362,8 +361,8 @@ static void sprd_shutdown(struct uart_port *port)
|
|||
}
|
||||
|
||||
static void sprd_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud, quot;
|
||||
unsigned int lcr = 0, fc;
|
||||
|
@ -444,10 +443,11 @@ static void sprd_set_termios(struct uart_port *port,
|
|||
}
|
||||
|
||||
/* clock divider bit0~bit15 */
|
||||
serial_out(port, SPRD_CLKD0, quot & 0xffff);
|
||||
serial_out(port, SPRD_CLKD0, quot & SPRD_CLKD0_MASK);
|
||||
|
||||
/* 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);
|
||||
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
|
||||
serial_out(port, SPRD_CTL1, fc);
|
||||
|
@ -480,8 +480,7 @@ static void sprd_config_port(struct uart_port *port, int flags)
|
|||
port->type = PORT_SPRD;
|
||||
}
|
||||
|
||||
static int sprd_verify_port(struct uart_port *port,
|
||||
struct serial_struct *ser)
|
||||
static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
{
|
||||
if (ser->type != PORT_SPRD)
|
||||
return -EINVAL;
|
||||
|
@ -521,7 +520,7 @@ static void wait_for_xmitr(struct uart_port *port)
|
|||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while (status & 0xff00);
|
||||
} while (status & SPRD_TX_FIFO_CNT_MASK);
|
||||
}
|
||||
|
||||
static void sprd_console_putchar(struct uart_port *port, int ch)
|
||||
|
@ -531,7 +530,7 @@ static void sprd_console_putchar(struct uart_port *port, int ch)
|
|||
}
|
||||
|
||||
static void sprd_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &sprd_port[co->index]->port;
|
||||
int locked = 1;
|
||||
|
@ -594,23 +593,21 @@ static void sprd_putc(struct uart_port *port, int c)
|
|||
unsigned int timeout = SPRD_TIMEOUT;
|
||||
|
||||
while (timeout-- &&
|
||||
!(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
|
||||
!(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
|
||||
cpu_relax();
|
||||
|
||||
writeb(c, port->membase + SPRD_TXD);
|
||||
}
|
||||
|
||||
static void sprd_early_write(struct console *con, const char *s,
|
||||
unsigned n)
|
||||
static void sprd_early_write(struct console *con, const char *s, unsigned int n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, sprd_putc);
|
||||
}
|
||||
|
||||
static int __init sprd_early_console_setup(
|
||||
struct earlycon_device *device,
|
||||
const char *opt)
|
||||
static int __init sprd_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
@ -692,8 +689,8 @@ static int sprd_probe(struct platform_device *pdev)
|
|||
|
||||
index = sprd_probe_dt_alias(index, &pdev->dev);
|
||||
|
||||
sprd_port[index] = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*sprd_port[index]), GFP_KERNEL);
|
||||
sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
|
||||
GFP_KERNEL);
|
||||
if (!sprd_port[index])
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -712,15 +709,12 @@ static int sprd_probe(struct platform_device *pdev)
|
|||
up->uartclk = clk_get_rate(clk);
|
||||
|
||||
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);
|
||||
if (IS_ERR(up->membase))
|
||||
return PTR_ERR(up->membase);
|
||||
|
||||
up->mapbase = res->start;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "not provide irq resource: %d\n", irq);
|
||||
|
|
|
@ -55,6 +55,11 @@
|
|||
#define ULITE_CONTROL_RST_RX 0x02
|
||||
#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 {
|
||||
const struct uartlite_reg_ops *reg_ops;
|
||||
struct clk *clk;
|
||||
|
@ -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,
|
||||
unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &ulite_ports[co->index];
|
||||
struct uart_port *port = console_port;
|
||||
unsigned long flags;
|
||||
unsigned int ier;
|
||||
int locked = 1;
|
||||
|
@ -506,10 +511,8 @@ static int ulite_console_setup(struct console *co, char *options)
|
|||
int parity = '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? */
|
||||
if (!port->mapbase) {
|
||||
|
@ -541,14 +544,6 @@ static struct console ulite_console = {
|
|||
.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)
|
||||
{
|
||||
/*
|
||||
|
@ -660,6 +655,17 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
|
|||
|
||||
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 */
|
||||
rc = uart_add_one_port(&ulite_uart_driver, port);
|
||||
if (rc) {
|
||||
|
@ -669,6 +675,12 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -776,13 +788,26 @@ static int ulite_probe(struct platform_device *pdev)
|
|||
pdata->clk = NULL;
|
||||
}
|
||||
|
||||
ret = clk_prepare(pdata->clk);
|
||||
ret = clk_prepare_enable(pdata->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to prepare clock\n");
|
||||
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)
|
||||
|
@ -813,25 +838,9 @@ static struct platform_driver ulite_platform_driver = {
|
|||
|
||||
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");
|
||||
ret = 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;
|
||||
return platform_driver_register(&ulite_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit ulite_exit(void)
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
#define CDNS_UART_TTY_NAME "ttyPS"
|
||||
#define CDNS_UART_NAME "xuartps"
|
||||
#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
|
||||
#define CDNS_UART_MINOR 0 /* works best with devtmpfs */
|
||||
#define CDNS_UART_NR_PORTS 2
|
||||
#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
|
||||
#define CDNS_UART_REGISTER_SPACE 0x1000
|
||||
|
||||
|
@ -180,7 +178,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||
* @port: Pointer to the UART port
|
||||
* @uartclk: Reference clock
|
||||
* @pclk: APB clock
|
||||
* @cdns_uart_driver: Pointer to UART driver
|
||||
* @baud: Current baud rate
|
||||
* @id: Port ID
|
||||
* @clk_rate_change_nb: Notifier block for clock changes
|
||||
* @quirks: Flags for RXBS support.
|
||||
*/
|
||||
|
@ -188,7 +188,9 @@ struct cdns_uart {
|
|||
struct uart_port *port;
|
||||
struct clk *uartclk;
|
||||
struct clk *pclk;
|
||||
struct uart_driver *cdns_uart_driver;
|
||||
unsigned int baud;
|
||||
int id;
|
||||
struct notifier_block clk_rate_change_nb;
|
||||
u32 quirks;
|
||||
};
|
||||
|
@ -1003,13 +1005,12 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
val = readl(port->membase + CDNS_UART_MODEMCR);
|
||||
mode_reg = readl(port->membase + CDNS_UART_MR);
|
||||
|
||||
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
|
||||
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR |
|
||||
CDNS_UART_MODEMCR_FCM);
|
||||
mode_reg &= ~CDNS_UART_MR_CHMODE_MASK;
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
val |= CDNS_UART_MODEMCR_RTS;
|
||||
if (mctrl & TIOCM_DTR)
|
||||
val |= CDNS_UART_MODEMCR_DTR;
|
||||
if (mctrl & TIOCM_RTS || mctrl & TIOCM_DTR)
|
||||
val |= CDNS_UART_MODEMCR_FCM;
|
||||
if (mctrl & TIOCM_LOOP)
|
||||
mode_reg |= CDNS_UART_MR_CHMODE_L_LOOP;
|
||||
else
|
||||
|
@ -1217,7 +1218,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
|
|||
*
|
||||
* Return: 0 on success, negative errno otherwise.
|
||||
*/
|
||||
static int __init cdns_uart_console_setup(struct console *co, char *options)
|
||||
static int cdns_uart_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port = console_port;
|
||||
|
||||
|
@ -1237,32 +1238,8 @@ static int __init cdns_uart_console_setup(struct console *co, char *options)
|
|||
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver cdns_uart_uart_driver;
|
||||
|
||||
static struct console cdns_uart_console = {
|
||||
.name = CDNS_UART_TTY_NAME,
|
||||
.write = cdns_uart_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = cdns_uart_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
|
||||
.data = &cdns_uart_uart_driver,
|
||||
};
|
||||
#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
|
||||
|
||||
static struct uart_driver cdns_uart_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = CDNS_UART_NAME,
|
||||
.dev_name = CDNS_UART_TTY_NAME,
|
||||
.major = CDNS_UART_MAJOR,
|
||||
.minor = CDNS_UART_MINOR,
|
||||
.nr = CDNS_UART_NR_PORTS,
|
||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
.cons = &cdns_uart_console,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* cdns_uart_suspend - suspend event
|
||||
|
@ -1273,24 +1250,12 @@ static struct uart_driver cdns_uart_uart_driver = {
|
|||
static int cdns_uart_suspend(struct device *device)
|
||||
{
|
||||
struct uart_port *port = dev_get_drvdata(device);
|
||||
struct tty_struct *tty;
|
||||
struct device *tty_dev;
|
||||
int may_wake = 0;
|
||||
struct cdns_uart *cdns_uart = port->private_data;
|
||||
int may_wake;
|
||||
|
||||
/* Get the tty which could be NULL so don't assume it's valid */
|
||||
tty = tty_port_tty_get(&port->state->port);
|
||||
if (tty) {
|
||||
tty_dev = tty->dev;
|
||||
may_wake = device_may_wakeup(tty_dev);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
may_wake = device_may_wakeup(device);
|
||||
|
||||
/*
|
||||
* Call the API provided in serial_core.c file which handles
|
||||
* the suspend.
|
||||
*/
|
||||
uart_suspend_port(&cdns_uart_uart_driver, port);
|
||||
if (!(console_suspend_enabled && !may_wake)) {
|
||||
if (console_suspend_enabled && may_wake) {
|
||||
unsigned long flags = 0;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
@ -1305,7 +1270,11 @@ static int cdns_uart_suspend(struct device *device)
|
|||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* Call the API provided in serial_core.c file which handles
|
||||
* the suspend.
|
||||
*/
|
||||
return uart_suspend_port(cdns_uart->cdns_uart_driver, port);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1317,23 +1286,14 @@ static int cdns_uart_suspend(struct device *device)
|
|||
static int cdns_uart_resume(struct device *device)
|
||||
{
|
||||
struct uart_port *port = dev_get_drvdata(device);
|
||||
struct cdns_uart *cdns_uart = port->private_data;
|
||||
unsigned long flags = 0;
|
||||
u32 ctrl_reg;
|
||||
struct tty_struct *tty;
|
||||
struct device *tty_dev;
|
||||
int may_wake = 0;
|
||||
int may_wake;
|
||||
|
||||
/* Get the tty which could be NULL so don't assume it's valid */
|
||||
tty = tty_port_tty_get(&port->state->port);
|
||||
if (tty) {
|
||||
tty_dev = tty->dev;
|
||||
may_wake = device_may_wakeup(tty_dev);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
may_wake = device_may_wakeup(device);
|
||||
|
||||
if (console_suspend_enabled && !may_wake) {
|
||||
struct cdns_uart *cdns_uart = port->private_data;
|
||||
|
||||
clk_enable(cdns_uart->pclk);
|
||||
clk_enable(cdns_uart->uartclk);
|
||||
|
||||
|
@ -1367,7 +1327,7 @@ static int cdns_uart_resume(struct device *device)
|
|||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
return uart_resume_port(&cdns_uart_uart_driver, port);
|
||||
return uart_resume_port(cdns_uart->cdns_uart_driver, port);
|
||||
}
|
||||
#endif /* ! CONFIG_PM_SLEEP */
|
||||
static int __maybe_unused cdns_runtime_suspend(struct device *dev)
|
||||
|
@ -1409,6 +1369,90 @@ static const struct of_device_id cdns_uart_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
|
||||
|
||||
/*
|
||||
* Maximum number of instances without alias IDs but if there is alias
|
||||
* which target "< MAX_UART_INSTANCES" range this ID can't be used.
|
||||
*/
|
||||
#define MAX_UART_INSTANCES 32
|
||||
|
||||
/* Stores static aliases list */
|
||||
static DECLARE_BITMAP(alias_bitmap, MAX_UART_INSTANCES);
|
||||
static int alias_bitmap_initialized;
|
||||
|
||||
/* Stores actual bitmap of allocated IDs with alias IDs together */
|
||||
static DECLARE_BITMAP(bitmap, MAX_UART_INSTANCES);
|
||||
/* Protect bitmap operations to have unique IDs */
|
||||
static DEFINE_MUTEX(bitmap_lock);
|
||||
|
||||
static int cdns_get_id(struct platform_device *pdev)
|
||||
{
|
||||
int id, ret;
|
||||
|
||||
mutex_lock(&bitmap_lock);
|
||||
|
||||
/* Alias list is stable that's why get alias bitmap only once */
|
||||
if (!alias_bitmap_initialized) {
|
||||
ret = of_alias_get_alias_list(cdns_uart_of_match, "serial",
|
||||
alias_bitmap, MAX_UART_INSTANCES);
|
||||
if (ret && ret != -EOVERFLOW) {
|
||||
mutex_unlock(&bitmap_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
alias_bitmap_initialized++;
|
||||
}
|
||||
|
||||
/* Make sure that alias ID is not taken by instance without alias */
|
||||
bitmap_or(bitmap, bitmap, alias_bitmap, MAX_UART_INSTANCES);
|
||||
|
||||
dev_dbg(&pdev->dev, "Alias bitmap: %*pb\n",
|
||||
MAX_UART_INSTANCES, bitmap);
|
||||
|
||||
/* Look for a serialN alias */
|
||||
id = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (id < 0) {
|
||||
dev_warn(&pdev->dev,
|
||||
"No serial alias passed. Using the first free id\n");
|
||||
|
||||
/*
|
||||
* Start with id 0 and check if there is no serial0 alias
|
||||
* which points to device which is compatible with this driver.
|
||||
* If alias exists then try next free position.
|
||||
*/
|
||||
id = 0;
|
||||
|
||||
for (;;) {
|
||||
dev_info(&pdev->dev, "Checking id %d\n", id);
|
||||
id = find_next_zero_bit(bitmap, MAX_UART_INSTANCES, id);
|
||||
|
||||
/* No free empty instance */
|
||||
if (id == MAX_UART_INSTANCES) {
|
||||
dev_err(&pdev->dev, "No free ID\n");
|
||||
mutex_unlock(&bitmap_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "The empty id is %d\n", id);
|
||||
/* Check if ID is empty */
|
||||
if (!test_and_set_bit(id, bitmap)) {
|
||||
/* Break the loop if bit is taken */
|
||||
dev_dbg(&pdev->dev,
|
||||
"Selected ID %d allocation passed\n",
|
||||
id);
|
||||
break;
|
||||
}
|
||||
dev_dbg(&pdev->dev,
|
||||
"Selected ID %d allocation failed\n", id);
|
||||
/* if taking bit fails then try next one */
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&bitmap_lock);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_uart_probe - Platform driver probe
|
||||
* @pdev: Pointer to the platform device structure
|
||||
|
@ -1417,11 +1461,16 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
|
|||
*/
|
||||
static int cdns_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc, id, irq;
|
||||
int rc, irq;
|
||||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
struct cdns_uart *cdns_uart_data;
|
||||
const struct of_device_id *match;
|
||||
struct uart_driver *cdns_uart_uart_driver;
|
||||
char *driver_name;
|
||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
struct console *cdns_uart_console;
|
||||
#endif
|
||||
|
||||
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
|
||||
GFP_KERNEL);
|
||||
|
@ -1431,6 +1480,63 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
cdns_uart_uart_driver = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*cdns_uart_uart_driver),
|
||||
GFP_KERNEL);
|
||||
if (!cdns_uart_uart_driver)
|
||||
return -ENOMEM;
|
||||
|
||||
cdns_uart_data->id = cdns_get_id(pdev);
|
||||
if (cdns_uart_data->id < 0)
|
||||
return cdns_uart_data->id;
|
||||
|
||||
/* There is a need to use unique driver name */
|
||||
driver_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%d",
|
||||
CDNS_UART_NAME, cdns_uart_data->id);
|
||||
if (!driver_name) {
|
||||
rc = -ENOMEM;
|
||||
goto err_out_id;
|
||||
}
|
||||
|
||||
cdns_uart_uart_driver->owner = THIS_MODULE;
|
||||
cdns_uart_uart_driver->driver_name = driver_name;
|
||||
cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
|
||||
cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
|
||||
cdns_uart_uart_driver->minor = cdns_uart_data->id;
|
||||
cdns_uart_uart_driver->nr = 1;
|
||||
|
||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
|
||||
GFP_KERNEL);
|
||||
if (!cdns_uart_console)
|
||||
return -ENOMEM;
|
||||
|
||||
strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
|
||||
sizeof(cdns_uart_console->name));
|
||||
cdns_uart_console->index = cdns_uart_data->id;
|
||||
cdns_uart_console->write = cdns_uart_console_write;
|
||||
cdns_uart_console->device = uart_console_device;
|
||||
cdns_uart_console->setup = cdns_uart_console_setup;
|
||||
cdns_uart_console->flags = CON_PRINTBUFFER;
|
||||
cdns_uart_console->data = cdns_uart_uart_driver;
|
||||
cdns_uart_uart_driver->cons = cdns_uart_console;
|
||||
#endif
|
||||
|
||||
rc = uart_register_driver(cdns_uart_uart_driver);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register driver\n");
|
||||
goto err_out_id;
|
||||
}
|
||||
|
||||
cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
|
||||
|
||||
/*
|
||||
* Setting up proper name_base needs to be done after uart
|
||||
* registration because tty_driver structure is not filled.
|
||||
* name_base is 0 by default.
|
||||
*/
|
||||
cdns_uart_uart_driver->tty_driver->name_base = cdns_uart_data->id;
|
||||
|
||||
match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
|
||||
if (match && match->data) {
|
||||
const struct cdns_platform_data *data = match->data;
|
||||
|
@ -1446,7 +1552,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
}
|
||||
if (IS_ERR(cdns_uart_data->pclk)) {
|
||||
dev_err(&pdev->dev, "pclk clock not found.\n");
|
||||
return PTR_ERR(cdns_uart_data->pclk);
|
||||
rc = PTR_ERR(cdns_uart_data->pclk);
|
||||
goto err_out_unregister_driver;
|
||||
}
|
||||
|
||||
cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
|
||||
|
@ -1457,13 +1564,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
}
|
||||
if (IS_ERR(cdns_uart_data->uartclk)) {
|
||||
dev_err(&pdev->dev, "uart_clk clock not found.\n");
|
||||
return PTR_ERR(cdns_uart_data->uartclk);
|
||||
rc = PTR_ERR(cdns_uart_data->uartclk);
|
||||
goto err_out_unregister_driver;
|
||||
}
|
||||
|
||||
rc = clk_prepare_enable(cdns_uart_data->pclk);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
|
||||
return rc;
|
||||
goto err_out_unregister_driver;
|
||||
}
|
||||
rc = clk_prepare_enable(cdns_uart_data->uartclk);
|
||||
if (rc) {
|
||||
|
@ -1490,28 +1598,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
&cdns_uart_data->clk_rate_change_nb))
|
||||
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
|
||||
#endif
|
||||
/* Look for a serialN alias */
|
||||
id = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (id < 0)
|
||||
id = 0;
|
||||
|
||||
if (id >= CDNS_UART_NR_PORTS) {
|
||||
dev_err(&pdev->dev, "Cannot get uart_port structure\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out_notif_unreg;
|
||||
}
|
||||
|
||||
/* At this point, we've got an empty uart_port struct, initialize it */
|
||||
spin_lock_init(&port->lock);
|
||||
port->membase = NULL;
|
||||
port->irq = 0;
|
||||
port->type = PORT_UNKNOWN;
|
||||
port->iotype = UPIO_MEM32;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->ops = &cdns_uart_ops;
|
||||
port->fifosize = CDNS_UART_FIFO_SIZE;
|
||||
port->line = id;
|
||||
port->dev = NULL;
|
||||
|
||||
/*
|
||||
* Register the port.
|
||||
|
@ -1538,11 +1632,11 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
* If register_console() don't assign value, then console_port pointer
|
||||
* is cleanup.
|
||||
*/
|
||||
if (cdns_uart_uart_driver.cons->index == -1)
|
||||
if (!console_port)
|
||||
console_port = port;
|
||||
#endif
|
||||
|
||||
rc = uart_add_one_port(&cdns_uart_uart_driver, port);
|
||||
rc = uart_add_one_port(cdns_uart_uart_driver, port);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev,
|
||||
"uart_add_one_port() failed; err=%i\n", rc);
|
||||
|
@ -1551,7 +1645,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
|
||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
/* This is not port which is used for console that's why clean it up */
|
||||
if (cdns_uart_uart_driver.cons->index == -1)
|
||||
if (console_port == port &&
|
||||
!(cdns_uart_uart_driver->cons->flags & CON_ENABLED))
|
||||
console_port = NULL;
|
||||
#endif
|
||||
|
||||
|
@ -1561,7 +1656,6 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
err_out_notif_unreg:
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
clk_notifier_unregister(cdns_uart_data->uartclk,
|
||||
&cdns_uart_data->clk_rate_change_nb);
|
||||
|
@ -1570,7 +1664,13 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
clk_disable_unprepare(cdns_uart_data->uartclk);
|
||||
err_out_clk_dis_pclk:
|
||||
clk_disable_unprepare(cdns_uart_data->pclk);
|
||||
|
||||
err_out_unregister_driver:
|
||||
uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
|
||||
err_out_id:
|
||||
mutex_lock(&bitmap_lock);
|
||||
if (cdns_uart_data->id < MAX_UART_INSTANCES)
|
||||
clear_bit(cdns_uart_data->id, bitmap);
|
||||
mutex_unlock(&bitmap_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1591,13 +1691,24 @@ static int cdns_uart_remove(struct platform_device *pdev)
|
|||
clk_notifier_unregister(cdns_uart_data->uartclk,
|
||||
&cdns_uart_data->clk_rate_change_nb);
|
||||
#endif
|
||||
rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
|
||||
rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port);
|
||||
port->mapbase = 0;
|
||||
mutex_lock(&bitmap_lock);
|
||||
if (cdns_uart_data->id < MAX_UART_INSTANCES)
|
||||
clear_bit(cdns_uart_data->id, bitmap);
|
||||
mutex_unlock(&bitmap_lock);
|
||||
clk_disable_unprepare(cdns_uart_data->uartclk);
|
||||
clk_disable_unprepare(cdns_uart_data->pclk);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
|
||||
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
|
||||
if (console_port == port)
|
||||
console_port = NULL;
|
||||
#endif
|
||||
|
||||
uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1613,28 +1724,14 @@ static struct platform_driver cdns_uart_platform_driver = {
|
|||
|
||||
static int __init cdns_uart_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
/* Register the cdns_uart driver with the serial core */
|
||||
retval = uart_register_driver(&cdns_uart_uart_driver);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Register the platform driver */
|
||||
retval = platform_driver_register(&cdns_uart_platform_driver);
|
||||
if (retval)
|
||||
uart_unregister_driver(&cdns_uart_uart_driver);
|
||||
|
||||
return retval;
|
||||
return platform_driver_register(&cdns_uart_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit cdns_uart_exit(void)
|
||||
{
|
||||
/* Unregister the platform driver */
|
||||
platform_driver_unregister(&cdns_uart_platform_driver);
|
||||
|
||||
/* Unregister the cdns_uart driver */
|
||||
uart_unregister_driver(&cdns_uart_uart_driver);
|
||||
}
|
||||
|
||||
arch_initcall(cdns_uart_init);
|
||||
|
|
|
@ -118,9 +118,12 @@ void tty_buffer_free_all(struct tty_port *port)
|
|||
struct tty_bufhead *buf = &port->buf;
|
||||
struct tty_buffer *p, *next;
|
||||
struct llist_node *llist;
|
||||
unsigned int freed = 0;
|
||||
int still_used;
|
||||
|
||||
while ((p = buf->head) != NULL) {
|
||||
buf->head = p->next;
|
||||
freed += p->size;
|
||||
if (p->size > 0)
|
||||
kfree(p);
|
||||
}
|
||||
|
@ -132,7 +135,9 @@ void tty_buffer_free_all(struct tty_port *port)
|
|||
buf->head = &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)
|
|||
{
|
||||
unsigned char *p = char_buf_ptr(head, head->read);
|
||||
char *f = NULL;
|
||||
int n;
|
||||
|
||||
if (~head->flags & TTYB_NORMAL)
|
||||
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)
|
|||
mutex_lock(&tty_mutex);
|
||||
/* Search through the tty devices to look for a match */
|
||||
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;
|
||||
stp = str;
|
||||
if (*stp == ',')
|
||||
|
|
|
@ -279,7 +279,6 @@ EXPORT_SYMBOL(tty_port_put);
|
|||
* Return a refcount protected tty instance or NULL if the port is not
|
||||
* associated with a tty (eg due to close or hangup)
|
||||
*/
|
||||
|
||||
struct tty_struct *tty_port_tty_get(struct tty_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -300,7 +299,6 @@ EXPORT_SYMBOL(tty_port_tty_get);
|
|||
* Associate the port and tty pair. Manages any internal refcounts.
|
||||
* Pass NULL to deassociate a port
|
||||
*/
|
||||
|
||||
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -343,7 +341,6 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
|
|||
*
|
||||
* Caller holds tty lock.
|
||||
*/
|
||||
|
||||
void tty_port_hangup(struct tty_port *port)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
@ -399,7 +396,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
|
|||
* to hide some internal details. This will eventually become entirely
|
||||
* internal to the tty port.
|
||||
*/
|
||||
|
||||
int tty_port_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->carrier_raised == NULL)
|
||||
|
@ -416,7 +412,6 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
|
|||
* to hide some internal details. This will eventually become entirely
|
||||
* internal to the tty port.
|
||||
*/
|
||||
|
||||
void tty_port_raise_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->dtr_rts)
|
||||
|
@ -432,7 +427,6 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
|
|||
* to hide some internal details. This will eventually become entirely
|
||||
* internal to the tty port.
|
||||
*/
|
||||
|
||||
void tty_port_lower_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->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
|
||||
* may have changed state (eg., may have been hung up).
|
||||
*/
|
||||
|
||||
int tty_port_block_til_ready(struct tty_port *port,
|
||||
struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
|
|
|
@ -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 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_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);
|
||||
|
||||
|
@ -898,6 +901,13 @@ static inline int of_alias_get_highest_id(const char *stem)
|
|||
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)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -144,6 +144,8 @@ struct uart_port {
|
|||
void (*handle_break)(struct uart_port *);
|
||||
int (*rs485_config)(struct uart_port *,
|
||||
struct serial_rs485 *rs485);
|
||||
int (*iso7816_config)(struct uart_port *,
|
||||
struct serial_iso7816 *iso7816);
|
||||
unsigned int irq; /* irq number */
|
||||
unsigned long irqflags; /* irq flags */
|
||||
unsigned int uartclk; /* base uart clock */
|
||||
|
@ -260,6 +262,7 @@ struct uart_port {
|
|||
struct attribute_group *attr_group; /* port specific attributes */
|
||||
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
|
||||
struct serial_rs485 rs485;
|
||||
struct serial_iso7816 iso7816;
|
||||
void *private_data; /* generic platform data pointer */
|
||||
};
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#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 FIOCLEX 0x5451
|
||||
|
|
|
@ -132,4 +132,21 @@ struct serial_rs485 {
|
|||
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 */
|
||||
|
|
Loading…
Reference in New Issue
Block a user