TTY/Serial patches for 4.13-rc1
Here is the large tty/serial patchset for 4.13-rc1. A lot of tty and serial driver updates are in here, along with some fixups for some __get/put_user usages that were reported. Nothing huge, just lots of development by a number of different developers, full details in the shortlog. All of these have been in linux-next for a while. There will be a merge issue with the arm-soc tree in the include/linux/platform_data/atmel.h file. Stephen has sent out a fixup for it, so it shouldn't be that difficult to merge. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWVpZ9w8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylkTgCfV2HhbxIph/aEL1nJmwW64oCXFrMAoK59ZH65 tBZIosv0d91K1A+mObBT =adPL -----END PGP SIGNATURE----- Merge tag 'tty-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial updates from Greg KH: "Here is the large tty/serial patchset for 4.13-rc1. A lot of tty and serial driver updates are in here, along with some fixups for some __get/put_user usages that were reported. Nothing huge, just lots of development by a number of different developers, full details in the shortlog. All of these have been in linux-next for a while" * tag 'tty-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (71 commits) tty: serial: lpuart: add a more accurate baud rate calculation method tty: serial: lpuart: add earlycon support for imx7ulp tty: serial: lpuart: add imx7ulp support dt-bindings: serial: fsl-lpuart: add i.MX7ULP support tty: serial: lpuart: add little endian 32 bit register support tty: serial: lpuart: refactor lpuart32_{read|write} prototype tty: serial: lpuart: introduce lpuart_soc_data to represent SoC property serial: imx-serial - move DMA buffer configuration to DT serial: imx: Enable RTSD only when needed serial: imx: Remove unused members from imx_port struct serial: 8250: 8250_omap: Fix race b/w dma completion and RX timeout serial: 8250: Fix THRE flag usage for CAP_MINI tty/serial: meson_uart: update to stable bindings dt-bindings: serial: Add bindings for the Amlogic Meson UARTs serial: Delete dead code for CIR serial ports serial: sirf: make of_device_ids const serial/mpsc: switch to dma_alloc_attrs tty: serial: Add Actions Semi Owl UART earlycon dt-bindings: serial: Document Actions Semi Owl UARTs tty/serial: atmel: make the driver DT only ...
This commit is contained in:
commit
9a715cd543
15
Documentation/ABI/stable/sysfs-driver-aspeed-vuart
Normal file
15
Documentation/ABI/stable/sysfs-driver-aspeed-vuart
Normal file
@ -0,0 +1,15 @@
|
||||
What: /sys/bus/platform/drivers/aspeed-vuart/*/lpc_address
|
||||
Date: April 2017
|
||||
Contact: Jeremy Kerr <jk@ozlabs.org>
|
||||
Description: Configures which IO port the host side of the UART
|
||||
will appear on the host <-> BMC LPC bus.
|
||||
Users: OpenBMC. Proposed changes should be mailed to
|
||||
openbmc@lists.ozlabs.org
|
||||
|
||||
What: /sys/bus/platform/drivers/aspeed-vuart*/sirq
|
||||
Date: April 2017
|
||||
Contact: Jeremy Kerr <jk@ozlabs.org>
|
||||
Description: Configures which interrupt number the host side of
|
||||
the UART will appear on the host <-> BMC LPC bus.
|
||||
Users: OpenBMC. Proposed changes should be mailed to
|
||||
openbmc@lists.ozlabs.org
|
@ -954,6 +954,12 @@
|
||||
must already be setup and configured. Options are not
|
||||
yet supported.
|
||||
|
||||
owl,<addr>
|
||||
Start an early, polled-mode console on a serial port
|
||||
of an Actions Semi SoC, such as S500 or S900, at the
|
||||
specified address. The serial port must already be
|
||||
setup and configured. Options are not yet supported.
|
||||
|
||||
smh Use ARM semihosting calls for early console.
|
||||
|
||||
s3c2410,<addr>
|
||||
|
@ -20,6 +20,8 @@ Required properties:
|
||||
- "fsl,16550-FIFO64"
|
||||
- "fsl,ns16550"
|
||||
- "ti,da830-uart"
|
||||
- "aspeed,ast2400-vuart"
|
||||
- "aspeed,ast2500-vuart"
|
||||
- "serial" if the port type is unknown.
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : should contain uart interrupt.
|
||||
@ -45,6 +47,7 @@ Optional properties:
|
||||
property.
|
||||
- tx-threshold: Specify the TX FIFO low water indication for parts with
|
||||
programmable TX FIFO thresholds.
|
||||
- resets : phandle + reset specifier pairs
|
||||
|
||||
Note:
|
||||
* fsl,ns16550:
|
||||
|
@ -0,0 +1,16 @@
|
||||
Actions Semi Owl UART
|
||||
|
||||
Required properties:
|
||||
- compatible : "actions,s500-uart", "actions,owl-uart" for S500
|
||||
"actions,s900-uart", "actions,owl-uart" for S900
|
||||
- reg : Offset and length of the register set for the device.
|
||||
- interrupts : Should contain UART interrupt.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
uart3: serial@b0126000 {
|
||||
compatible = "actions,s500-uart", "actions,owl-uart";
|
||||
reg = <0xb0126000 0x1000>;
|
||||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
@ -0,0 +1,38 @@
|
||||
Amlogic Meson SoC UART Serial Interface
|
||||
=======================================
|
||||
|
||||
The Amlogic Meson SoC UART Serial Interface is present on a large range
|
||||
of SoCs, and can be present either in the "Always-On" power domain or the
|
||||
"Everything-Else" power domain.
|
||||
|
||||
The particularity of the "Always-On" Serial Interface is that the hardware
|
||||
is active since power-on and does not need any clock gating and is usable
|
||||
as very early serial console.
|
||||
|
||||
Required properties:
|
||||
- compatible : compatible: value should be different for each SoC family as :
|
||||
- Meson6 : "amlogic,meson6-uart"
|
||||
- Meson8 : "amlogic,meson8-uart"
|
||||
- Meson8b : "amlogic,meson8b-uart"
|
||||
- GX (GXBB, GXL, GXM) : "amlogic,meson-gx-uart"
|
||||
eventually followed by : "amlogic,meson-ao-uart" if this UART interface
|
||||
is in the "Always-On" power domain.
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : identifier to the device interrupt
|
||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||
entry in clock names.
|
||||
- clocks-names :
|
||||
* "xtal" for external xtal clock identifier
|
||||
* "pclk" for the bus core clock, either the clk81 clock or the gate clock
|
||||
* "baud" for the source of the baudrate generator, can be either the xtal
|
||||
or the pclk.
|
||||
|
||||
e.g.
|
||||
uart_A: serial@84c0 {
|
||||
compatible = "amlogic,meson-gx-uart";
|
||||
reg = <0x0 0x84c0 0x0 0x14>;
|
||||
interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
|
||||
/* Use xtal as baud rate clock source */
|
||||
clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>;
|
||||
clock-names = "xtal", "pclk", "baud";
|
||||
};
|
@ -9,6 +9,7 @@ Optional properties:
|
||||
- fsl,irda-mode : Indicate the uart supports irda mode
|
||||
- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
|
||||
in DCE mode by default.
|
||||
- fsl,dma-size : Indicate the size of the DMA buffer and its periods
|
||||
|
||||
Please check Documentation/devicetree/bindings/serial/serial.txt
|
||||
for the complete list of generic properties.
|
||||
@ -28,4 +29,5 @@ uart1: serial@73fbc000 {
|
||||
interrupts = <31>;
|
||||
uart-has-rtscts;
|
||||
fsl,dte-mode;
|
||||
fsl,dma-size = <1024 4>;
|
||||
};
|
||||
|
@ -6,6 +6,8 @@ Required properties:
|
||||
on Vybrid vf610 SoC with 8-bit register organization
|
||||
- "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated
|
||||
on LS1021A SoC with 32-bit big-endian register organization
|
||||
- "fsl,imx7ulp-lpuart" for lpuart compatible with the one integrated
|
||||
on i.MX7ULP SoC with 32-bit little-endian register organization
|
||||
- reg : Address and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- clocks : phandle + clock specifier pairs, one for each entry in clock-names
|
||||
|
@ -77,6 +77,13 @@ for example, it's possible :
|
||||
|
||||
6- first close all virtual ports before closing the physical port.
|
||||
|
||||
Note that after closing the physical port the modem is still in multiplexing
|
||||
mode. This may prevent a successful re-opening of the port later. To avoid
|
||||
this situation either reset the modem if your hardware allows that or send
|
||||
a disconnect command frame manually before initializing the multiplexing mode
|
||||
for the second time. The byte sequence for the disconnect command frame is:
|
||||
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9.
|
||||
|
||||
Additional Documentation
|
||||
------------------------
|
||||
More practical details on the protocol and how it's supported by industrial
|
||||
|
@ -8446,7 +8446,7 @@ T: git git://git.monstr.eu/linux-2.6-microblaze.git
|
||||
S: Supported
|
||||
F: arch/microblaze/
|
||||
|
||||
MICROCHIP / ATMEL AT91 / AT32 SERIAL DRIVER
|
||||
MICROCHIP / ATMEL AT91 SERIAL DRIVER
|
||||
M: Richard Genoud <richard.genoud@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/tty/serial/atmel_serial.c
|
||||
|
@ -100,6 +100,7 @@
|
||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||
|
||||
#define TIOCSERCONFIG 0x5453
|
||||
#define TIOCSERGWILD 0x5454
|
||||
|
@ -387,19 +387,6 @@ static int activate(struct tty_port *port, struct tty_struct *tty)
|
||||
}
|
||||
|
||||
state->xmit.head = state->xmit.tail = 0;
|
||||
|
||||
/*
|
||||
* Set up the tty->alt_speed kludge
|
||||
*/
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
|
||||
errout:
|
||||
local_irq_restore(flags);
|
||||
return retval;
|
||||
|
@ -91,6 +91,7 @@
|
||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||
|
||||
/* I hope the range from 0x5480 on is free ... */
|
||||
#define TIOCSCTTY 0x5480 /* become controlling tty */
|
||||
|
@ -60,6 +60,7 @@
|
||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||
|
||||
#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||
#define FIOCLEX 0x5451
|
||||
|
@ -100,6 +100,7 @@
|
||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||
|
||||
#define TIOCSERCONFIG 0x5453
|
||||
#define TIOCSERGWILD 0x5454
|
||||
|
@ -93,6 +93,7 @@
|
||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||
|
||||
#define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */
|
||||
#define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */
|
||||
|
@ -27,7 +27,7 @@
|
||||
#define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485)
|
||||
#define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485)
|
||||
|
||||
/* Note that all the ioctls that are not available in Linux have a
|
||||
/* Note that all the ioctls that are not available in Linux have a
|
||||
* double underscore on the front to: a) avoid some programs to
|
||||
* think we support some ioctls under Linux (autoconfiguration stuff)
|
||||
*/
|
||||
@ -88,6 +88,7 @@
|
||||
#define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */
|
||||
#define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */
|
||||
#define TIOCSIG _IOW('t', 136, int) /* Generate signal on Pty slave */
|
||||
#define TIOCGPTPEER _IOR('t', 137, int) /* Safely open the slave */
|
||||
|
||||
/* Little f */
|
||||
#define FIOCLEX _IO('f', 1)
|
||||
|
@ -105,6 +105,7 @@
|
||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||
|
||||
#define TIOCSERCONFIG _IO('T', 83)
|
||||
#define TIOCSERGWILD _IOR('T', 84, int)
|
||||
|
@ -1,6 +1,7 @@
|
||||
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
|
||||
tty_buffer.o tty_port.o tty_mutex.o \
|
||||
tty_ldsem.o tty_baudrate.o tty_jobctrl.o
|
||||
tty_ldsem.o tty_baudrate.o tty_jobctrl.o \
|
||||
n_null.o
|
||||
obj-$(CONFIG_LEGACY_PTYS) += pty.o
|
||||
obj-$(CONFIG_UNIX98_PTYS) += pty.o
|
||||
obj-$(CONFIG_AUDIT) += tty_audit.o
|
||||
|
@ -569,18 +569,6 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
info->xmit.head = info->xmit.tail = 0;
|
||||
|
||||
/*
|
||||
* Set up the tty->alt_speed kludge
|
||||
*/
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
|
||||
/*
|
||||
* and set the speed of the serial port
|
||||
*/
|
||||
@ -1084,14 +1072,9 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
|
||||
check_and_exit:
|
||||
if (tty_port_initialized(port)) {
|
||||
if (change_spd) {
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
/* warn about deprecation unless clearing */
|
||||
if (new_serial.flags & ASYNC_SPD_MASK)
|
||||
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
|
||||
change_speed(tty, state, NULL);
|
||||
}
|
||||
} else
|
||||
|
@ -1975,18 +1975,6 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
|
||||
cflag = tty->termios.c_cflag;
|
||||
iflag = tty->termios.c_iflag;
|
||||
|
||||
/*
|
||||
* Set up the tty->alt_speed kludge
|
||||
*/
|
||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
|
||||
@ -2295,12 +2283,16 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
|
||||
struct serial_struct __user *new_info)
|
||||
{
|
||||
struct serial_struct new_serial;
|
||||
int old_flags;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&info->port.mutex);
|
||||
|
||||
old_flags = info->port.flags;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if (new_serial.close_delay != info->port.close_delay ||
|
||||
new_serial.baud_base != info->baud ||
|
||||
@ -2332,6 +2324,11 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
|
||||
|
||||
check_and_exit:
|
||||
if (tty_port_initialized(&info->port)) {
|
||||
if ((new_serial.flags ^ old_flags) & ASYNC_SPD_MASK) {
|
||||
/* warn about deprecation unless clearing */
|
||||
if (new_serial.flags & ASYNC_SPD_MASK)
|
||||
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
|
||||
}
|
||||
cy_set_line_char(info, tty);
|
||||
ret = 0;
|
||||
} else {
|
||||
|
@ -1242,8 +1242,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
||||
free_irq(irq, hvcsd);
|
||||
return;
|
||||
} else if (hvcsd->port.count < 0) {
|
||||
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
|
||||
" is missmanaged.\n",
|
||||
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d is mismanaged.\n",
|
||||
hvcsd->vdev->unit_address, hvcsd->port.count);
|
||||
}
|
||||
|
||||
|
@ -2015,6 +2015,33 @@ static void gsm_error(struct gsm_mux *gsm,
|
||||
gsm->io_error++;
|
||||
}
|
||||
|
||||
static int gsm_disconnect(struct gsm_mux *gsm)
|
||||
{
|
||||
struct gsm_dlci *dlci = gsm->dlci[0];
|
||||
struct gsm_control *gc;
|
||||
|
||||
if (!dlci)
|
||||
return 0;
|
||||
|
||||
/* In theory disconnecting DLCI 0 is sufficient but for some
|
||||
modems this is apparently not the case. */
|
||||
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
|
||||
if (gc)
|
||||
gsm_control_wait(gsm, gc);
|
||||
|
||||
del_timer_sync(&gsm->t2_timer);
|
||||
/* Now we are sure T2 has stopped */
|
||||
|
||||
gsm_dlci_begin_close(dlci);
|
||||
wait_event_interruptible(gsm->event,
|
||||
dlci->state == DLCI_CLOSED);
|
||||
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_cleanup_mux - generic GSM protocol cleanup
|
||||
* @gsm: our mux
|
||||
@ -2029,7 +2056,6 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
|
||||
int i;
|
||||
struct gsm_dlci *dlci = gsm->dlci[0];
|
||||
struct gsm_msg *txq, *ntxq;
|
||||
struct gsm_control *gc;
|
||||
|
||||
gsm->dead = 1;
|
||||
|
||||
@ -2045,21 +2071,11 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
|
||||
if (i == MAX_MUX)
|
||||
return;
|
||||
|
||||
/* In theory disconnecting DLCI 0 is sufficient but for some
|
||||
modems this is apparently not the case. */
|
||||
if (dlci) {
|
||||
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
|
||||
if (gc)
|
||||
gsm_control_wait(gsm, gc);
|
||||
}
|
||||
del_timer_sync(&gsm->t2_timer);
|
||||
/* Now we are sure T2 has stopped */
|
||||
if (dlci) {
|
||||
if (dlci)
|
||||
dlci->dead = 1;
|
||||
gsm_dlci_begin_close(dlci);
|
||||
wait_event_interruptible(gsm->event,
|
||||
dlci->state == DLCI_CLOSED);
|
||||
}
|
||||
|
||||
/* Free up any link layer users */
|
||||
mutex_lock(&gsm->mutex);
|
||||
for (i = 0; i < NUM_DLCI; i++)
|
||||
@ -2519,12 +2535,12 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
|
||||
*/
|
||||
|
||||
if (need_close || need_restart) {
|
||||
gsm_dlci_begin_close(gsm->dlci[0]);
|
||||
/* This will timeout if the link is down due to N2 expiring */
|
||||
wait_event_interruptible(gsm->event,
|
||||
gsm->dlci[0]->state == DLCI_CLOSED);
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
int ret;
|
||||
|
||||
ret = gsm_disconnect(gsm);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (need_restart)
|
||||
gsm_cleanup_mux(gsm);
|
||||
|
80
drivers/tty/n_null.c
Normal file
80
drivers/tty/n_null.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* n_null.c - Null line discipline used in the failure path
|
||||
*
|
||||
* Copyright (C) Intel 2017
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
static int n_null_open(struct tty_struct *tty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void n_null_close(struct tty_struct *tty)
|
||||
{
|
||||
}
|
||||
|
||||
static ssize_t n_null_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user * buf, size_t nr)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static ssize_t n_null_write(struct tty_struct *tty, struct file *file,
|
||||
const unsigned char *buf, size_t nr)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void n_null_receivebuf(struct tty_struct *tty,
|
||||
const unsigned char *cp, char *fp,
|
||||
int cnt)
|
||||
{
|
||||
}
|
||||
|
||||
static struct tty_ldisc_ops null_ldisc = {
|
||||
.owner = THIS_MODULE,
|
||||
.magic = TTY_LDISC_MAGIC,
|
||||
.name = "n_null",
|
||||
.open = n_null_open,
|
||||
.close = n_null_close,
|
||||
.read = n_null_read,
|
||||
.write = n_null_write,
|
||||
.receive_buf = n_null_receivebuf
|
||||
};
|
||||
|
||||
static int __init n_null_init(void)
|
||||
{
|
||||
BUG_ON(tty_register_ldisc(N_NULL, &null_ldisc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit n_null_exit(void)
|
||||
{
|
||||
tty_unregister_ldisc(N_NULL);
|
||||
}
|
||||
|
||||
module_init(n_null_init);
|
||||
module_exit(n_null_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alan Cox");
|
||||
MODULE_ALIAS_LDISC(N_NULL);
|
||||
MODULE_DESCRIPTION("Null ldisc driver");
|
@ -24,6 +24,9 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#undef TTY_DEBUG_HANGUP
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
@ -66,8 +69,13 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
if (tty->driver == ptm_driver) {
|
||||
mutex_lock(&devpts_mutex);
|
||||
if (tty->link->driver_data)
|
||||
devpts_pty_kill(tty->link->driver_data);
|
||||
if (tty->link->driver_data) {
|
||||
struct path *path = tty->link->driver_data;
|
||||
|
||||
devpts_pty_kill(path->dentry);
|
||||
path_put(path);
|
||||
kfree(path);
|
||||
}
|
||||
mutex_unlock(&devpts_mutex);
|
||||
}
|
||||
#endif
|
||||
@ -440,6 +448,48 @@ err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* pty_open_peer - open the peer of a pty
|
||||
* @tty: the peer of the pty being opened
|
||||
*
|
||||
* Open the cached dentry in tty->link, providing a safe way for userspace
|
||||
* to get the slave end of a pty (where they have the master fd and cannot
|
||||
* access or trust the mount namespace /dev/pts was mounted inside).
|
||||
*/
|
||||
static struct file *pty_open_peer(struct tty_struct *tty, int flags)
|
||||
{
|
||||
if (tty->driver->subtype != PTY_TYPE_MASTER)
|
||||
return ERR_PTR(-EIO);
|
||||
return dentry_open(tty->link->driver_data, flags, current_cred());
|
||||
}
|
||||
|
||||
static int pty_get_peer(struct tty_struct *tty, int flags)
|
||||
{
|
||||
int fd = -1;
|
||||
struct file *filp = NULL;
|
||||
int retval = -EINVAL;
|
||||
|
||||
fd = get_unused_fd_flags(0);
|
||||
if (fd < 0) {
|
||||
retval = fd;
|
||||
goto err;
|
||||
}
|
||||
|
||||
filp = pty_open_peer(tty, flags);
|
||||
if (IS_ERR(filp)) {
|
||||
retval = PTR_ERR(filp);
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
fd_install(fd, filp);
|
||||
return fd;
|
||||
|
||||
err_put:
|
||||
put_unused_fd(fd);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void pty_cleanup(struct tty_struct *tty)
|
||||
{
|
||||
tty_port_put(tty->port);
|
||||
@ -481,6 +531,16 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static long pty_bsd_compat_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
/*
|
||||
* PTY ioctls don't require any special translation between 32-bit and
|
||||
* 64-bit userspace, they are already compatible.
|
||||
*/
|
||||
return pty_bsd_ioctl(tty, cmd, arg);
|
||||
}
|
||||
|
||||
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
|
||||
/*
|
||||
* not really modular, but the easiest way to keep compat with existing
|
||||
@ -502,6 +562,7 @@ static const struct tty_operations master_pty_ops_bsd = {
|
||||
.chars_in_buffer = pty_chars_in_buffer,
|
||||
.unthrottle = pty_unthrottle,
|
||||
.ioctl = pty_bsd_ioctl,
|
||||
.compat_ioctl = pty_bsd_compat_ioctl,
|
||||
.cleanup = pty_cleanup,
|
||||
.resize = pty_resize,
|
||||
.remove = pty_remove
|
||||
@ -602,6 +663,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
|
||||
return pty_get_pktmode(tty, (int __user *)arg);
|
||||
case TIOCGPTN: /* Get PT Number */
|
||||
return put_user(tty->index, (unsigned int __user *)arg);
|
||||
case TIOCGPTPEER: /* Open the other end */
|
||||
return pty_get_peer(tty, (int) arg);
|
||||
case TIOCSIG: /* Send signal to other side of pty */
|
||||
return pty_signal(tty, (int) arg);
|
||||
}
|
||||
@ -609,6 +672,16 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static long pty_unix98_compat_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
/*
|
||||
* PTY ioctls don't require any special translation between 32-bit and
|
||||
* 64-bit userspace, they are already compatible.
|
||||
*/
|
||||
return pty_unix98_ioctl(tty, cmd, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* ptm_unix98_lookup - find a pty master
|
||||
* @driver: ptm driver
|
||||
@ -681,6 +754,7 @@ static const struct tty_operations ptm_unix98_ops = {
|
||||
.chars_in_buffer = pty_chars_in_buffer,
|
||||
.unthrottle = pty_unthrottle,
|
||||
.ioctl = pty_unix98_ioctl,
|
||||
.compat_ioctl = pty_unix98_compat_ioctl,
|
||||
.resize = pty_resize,
|
||||
.cleanup = pty_cleanup
|
||||
};
|
||||
@ -718,6 +792,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct pts_fs_info *fsi;
|
||||
struct tty_struct *tty;
|
||||
struct path *pts_path;
|
||||
struct dentry *dentry;
|
||||
int retval;
|
||||
int index;
|
||||
@ -771,16 +846,26 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
||||
retval = PTR_ERR(dentry);
|
||||
goto err_release;
|
||||
}
|
||||
tty->link->driver_data = dentry;
|
||||
/* We need to cache a fake path for TIOCGPTPEER. */
|
||||
pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
|
||||
if (!pts_path)
|
||||
goto err_release;
|
||||
pts_path->mnt = filp->f_path.mnt;
|
||||
pts_path->dentry = dentry;
|
||||
path_get(pts_path);
|
||||
tty->link->driver_data = pts_path;
|
||||
|
||||
retval = ptm_driver->ops->open(tty, filp);
|
||||
if (retval)
|
||||
goto err_release;
|
||||
goto err_path_put;
|
||||
|
||||
tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
|
||||
|
||||
tty_unlock(tty);
|
||||
return 0;
|
||||
err_path_put:
|
||||
path_put(pts_path);
|
||||
kfree(pts_path);
|
||||
err_release:
|
||||
tty_unlock(tty);
|
||||
// This will also put-ref the fsi
|
||||
|
@ -947,18 +947,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
|
||||
/*
|
||||
* Set up the tty->alt_speed kludge
|
||||
*/
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
|
||||
configure_r_port(tty, info, NULL);
|
||||
if (C_BAUD(tty)) {
|
||||
sSetDTR(cp);
|
||||
@ -1219,23 +1207,20 @@ static int set_config(struct tty_struct *tty, struct r_port *info,
|
||||
return -EPERM;
|
||||
}
|
||||
info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
|
||||
configure_r_port(tty, info, NULL);
|
||||
mutex_unlock(&info->port.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((new_serial.flags ^ info->flags) & ROCKET_SPD_MASK) {
|
||||
/* warn about deprecation, unless clearing */
|
||||
if (new_serial.flags & ROCKET_SPD_MASK)
|
||||
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
|
||||
}
|
||||
|
||||
info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
|
||||
info->port.close_delay = new_serial.close_delay;
|
||||
info->port.closing_wait = new_serial.closing_wait;
|
||||
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
mutex_unlock(&info->port.mutex);
|
||||
|
||||
configure_r_port(tty, info, NULL);
|
||||
|
@ -148,7 +148,7 @@ static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigne
|
||||
|
||||
/* tty_set_termios() return not checked as it is always 0 */
|
||||
tty_set_termios(tty, &ktermios);
|
||||
return speed;
|
||||
return ktermios.c_ospeed;
|
||||
}
|
||||
|
||||
static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable)
|
||||
|
@ -81,6 +81,9 @@ struct serial8250_config {
|
||||
#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
|
||||
#define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */
|
||||
#define UART_CAP_IRDA (1 << 16) /* UART supports IrDA line discipline */
|
||||
#define UART_CAP_MINI (1 << 17) /* Mini UART on BCM283X family lacks:
|
||||
* STOP PARITY EPAR SPAR WLEN5 WLEN6
|
||||
*/
|
||||
|
||||
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
|
||||
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
|
||||
|
323
drivers/tty/serial/8250/8250_aspeed_vuart.c
Normal file
323
drivers/tty/serial/8250/8250_aspeed_vuart.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Serial Port driver for Aspeed VUART device
|
||||
*
|
||||
* Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp.
|
||||
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
#define ASPEED_VUART_GCRA 0x20
|
||||
#define ASPEED_VUART_GCRA_VUART_EN BIT(0)
|
||||
#define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
|
||||
#define ASPEED_VUART_GCRB 0x24
|
||||
#define ASPEED_VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4)
|
||||
#define ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT 4
|
||||
#define ASPEED_VUART_ADDRL 0x28
|
||||
#define ASPEED_VUART_ADDRH 0x2c
|
||||
|
||||
struct aspeed_vuart {
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
struct clk *clk;
|
||||
int line;
|
||||
};
|
||||
|
||||
/*
|
||||
* The VUART is basically two UART 'front ends' connected by their FIFO
|
||||
* (no actual serial line in between). One is on the BMC side (management
|
||||
* controller) and one is on the host CPU side.
|
||||
*
|
||||
* It allows the BMC to provide to the host a "UART" that pipes into
|
||||
* the BMC itself and can then be turned by the BMC into a network console
|
||||
* of some sort for example.
|
||||
*
|
||||
* This driver is for the BMC side. The sysfs files allow the BMC
|
||||
* userspace which owns the system configuration policy, to specify
|
||||
* at what IO port and interrupt number the host side will appear
|
||||
* to the host on the Host <-> BMC LPC bus. It could be different on a
|
||||
* different system (though most of them use 3f8/4).
|
||||
*/
|
||||
|
||||
static ssize_t lpc_address_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||
u16 addr;
|
||||
|
||||
addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) |
|
||||
(readb(vuart->regs + ASPEED_VUART_ADDRL));
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
|
||||
}
|
||||
|
||||
static ssize_t lpc_address_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 0, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
writeb(val >> 8, vuart->regs + ASPEED_VUART_ADDRH);
|
||||
writeb(val >> 0, vuart->regs + ASPEED_VUART_ADDRL);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(lpc_address);
|
||||
|
||||
static ssize_t sirq_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||
u8 reg;
|
||||
|
||||
reg = readb(vuart->regs + ASPEED_VUART_GCRB);
|
||||
reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
|
||||
reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg);
|
||||
}
|
||||
|
||||
static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||
unsigned long val;
|
||||
int err;
|
||||
u8 reg;
|
||||
|
||||
err = kstrtoul(buf, 0, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
|
||||
val &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
|
||||
|
||||
reg = readb(vuart->regs + ASPEED_VUART_GCRB);
|
||||
reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
|
||||
reg |= val;
|
||||
writeb(reg, vuart->regs + ASPEED_VUART_GCRB);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(sirq);
|
||||
|
||||
static struct attribute *aspeed_vuart_attrs[] = {
|
||||
&dev_attr_sirq.attr,
|
||||
&dev_attr_lpc_address.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group aspeed_vuart_attr_group = {
|
||||
.attrs = aspeed_vuart_attrs,
|
||||
};
|
||||
|
||||
static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
|
||||
{
|
||||
u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
|
||||
|
||||
if (enabled)
|
||||
reg |= ASPEED_VUART_GCRA_VUART_EN;
|
||||
else
|
||||
reg &= ~ASPEED_VUART_GCRA_VUART_EN;
|
||||
|
||||
writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
|
||||
}
|
||||
|
||||
static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
|
||||
bool discard)
|
||||
{
|
||||
u8 reg;
|
||||
|
||||
reg = readb(vuart->regs + ASPEED_VUART_GCRA);
|
||||
|
||||
/* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */
|
||||
if (!discard)
|
||||
reg |= ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
|
||||
else
|
||||
reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
|
||||
|
||||
writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
|
||||
}
|
||||
|
||||
static int aspeed_vuart_startup(struct uart_port *uart_port)
|
||||
{
|
||||
struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
|
||||
struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
|
||||
int rc;
|
||||
|
||||
rc = serial8250_do_startup(uart_port);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
aspeed_vuart_set_host_tx_discard(vuart, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aspeed_vuart_shutdown(struct uart_port *uart_port)
|
||||
{
|
||||
struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
|
||||
struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
|
||||
|
||||
aspeed_vuart_set_host_tx_discard(vuart, true);
|
||||
|
||||
serial8250_do_shutdown(uart_port);
|
||||
}
|
||||
|
||||
static int aspeed_vuart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port port;
|
||||
struct aspeed_vuart *vuart;
|
||||
struct device_node *np;
|
||||
struct resource *res;
|
||||
u32 clk, prop;
|
||||
int rc;
|
||||
|
||||
np = pdev->dev.of_node;
|
||||
|
||||
vuart = devm_kzalloc(&pdev->dev, sizeof(*vuart), GFP_KERNEL);
|
||||
if (!vuart)
|
||||
return -ENOMEM;
|
||||
|
||||
vuart->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
vuart->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(vuart->regs))
|
||||
return PTR_ERR(vuart->regs);
|
||||
|
||||
memset(&port, 0, sizeof(port));
|
||||
port.port.private_data = vuart;
|
||||
port.port.membase = vuart->regs;
|
||||
port.port.mapbase = res->start;
|
||||
port.port.mapsize = resource_size(res);
|
||||
port.port.startup = aspeed_vuart_startup;
|
||||
port.port.shutdown = aspeed_vuart_shutdown;
|
||||
port.port.dev = &pdev->dev;
|
||||
|
||||
rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (of_property_read_u32(np, "clock-frequency", &clk)) {
|
||||
vuart->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(vuart->clk)) {
|
||||
dev_warn(&pdev->dev,
|
||||
"clk or clock-frequency not defined\n");
|
||||
return PTR_ERR(vuart->clk);
|
||||
}
|
||||
|
||||
rc = clk_prepare_enable(vuart->clk);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
clk = clk_get_rate(vuart->clk);
|
||||
}
|
||||
|
||||
/* If current-speed was set, then try not to change it. */
|
||||
if (of_property_read_u32(np, "current-speed", &prop) == 0)
|
||||
port.port.custom_divisor = clk / (16 * prop);
|
||||
|
||||
/* Check for shifted address mapping */
|
||||
if (of_property_read_u32(np, "reg-offset", &prop) == 0)
|
||||
port.port.mapbase += prop;
|
||||
|
||||
/* Check for registers offset within the devices address range */
|
||||
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
|
||||
port.port.regshift = prop;
|
||||
|
||||
/* Check for fifo size */
|
||||
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
|
||||
port.port.fifosize = prop;
|
||||
|
||||
/* Check for a fixed line number */
|
||||
rc = of_alias_get_id(np, "serial");
|
||||
if (rc >= 0)
|
||||
port.port.line = rc;
|
||||
|
||||
port.port.irq = irq_of_parse_and_map(np, 0);
|
||||
port.port.irqflags = IRQF_SHARED;
|
||||
port.port.iotype = UPIO_MEM;
|
||||
port.port.type = PORT_16550A;
|
||||
port.port.uartclk = clk;
|
||||
port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
|
||||
| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
|
||||
|
||||
if (of_property_read_bool(np, "no-loopback-test"))
|
||||
port.port.flags |= UPF_SKIP_TEST;
|
||||
|
||||
if (port.port.fifosize)
|
||||
port.capabilities = UART_CAP_FIFO;
|
||||
|
||||
if (of_property_read_bool(np, "auto-flow-control"))
|
||||
port.capabilities |= UART_CAP_AFE;
|
||||
|
||||
rc = serial8250_register_8250_port(&port);
|
||||
if (rc < 0)
|
||||
goto err_clk_disable;
|
||||
|
||||
vuart->line = rc;
|
||||
|
||||
aspeed_vuart_set_enabled(vuart, true);
|
||||
aspeed_vuart_set_host_tx_discard(vuart, true);
|
||||
platform_set_drvdata(pdev, vuart);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk_disable:
|
||||
clk_disable_unprepare(vuart->clk);
|
||||
irq_dispose_mapping(port.port.irq);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int aspeed_vuart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
|
||||
|
||||
aspeed_vuart_set_enabled(vuart, false);
|
||||
serial8250_unregister_port(vuart->line);
|
||||
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
|
||||
clk_disable_unprepare(vuart->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_vuart_table[] = {
|
||||
{ .compatible = "aspeed,ast2400-vuart" },
|
||||
{ .compatible = "aspeed,ast2500-vuart" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver aspeed_vuart_driver = {
|
||||
.driver = {
|
||||
.name = "aspeed-vuart",
|
||||
.of_match_table = aspeed_vuart_table,
|
||||
},
|
||||
.probe = aspeed_vuart_probe,
|
||||
.remove = aspeed_vuart_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(aspeed_vuart_driver);
|
||||
|
||||
MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Driver for Aspeed VUART device");
|
@ -39,7 +39,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
|
||||
/* initialize data */
|
||||
spin_lock_init(&data->uart.port.lock);
|
||||
data->uart.capabilities = UART_CAP_FIFO;
|
||||
data->uart.capabilities = UART_CAP_FIFO | UART_CAP_MINI;
|
||||
data->uart.port.dev = &pdev->dev;
|
||||
data->uart.port.regshift = 2;
|
||||
data->uart.port.type = PORT_16550;
|
||||
|
@ -1043,24 +1043,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
if (up->dl_write)
|
||||
uart->dl_write = up->dl_write;
|
||||
|
||||
if (uart->port.type != PORT_8250_CIR) {
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
&uart->capabilities);
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
&uart->capabilities);
|
||||
|
||||
ret = uart_add_one_port(&serial8250_reg,
|
||||
&uart->port);
|
||||
if (ret == 0)
|
||||
ret = uart->port.line;
|
||||
} else {
|
||||
dev_info(uart->port.dev,
|
||||
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
|
||||
uart->port.iobase,
|
||||
(unsigned long long)uart->port.mapbase,
|
||||
uart->port.irq);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
ret = uart_add_one_port(&serial8250_reg, &uart->port);
|
||||
if (ret == 0)
|
||||
ret = uart->port.line;
|
||||
}
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
|
@ -109,7 +109,6 @@ pci_fastcom335_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
||||
u8 __iomem *p;
|
||||
int err;
|
||||
|
||||
port->port.flags |= UPF_EXAR_EFR;
|
||||
port->port.uartclk = baud * 16;
|
||||
|
||||
err = default_setup(priv, pcidev, idx, offset, port);
|
||||
@ -171,19 +170,26 @@ pci_xr17c154_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
||||
return default_setup(priv, pcidev, idx, offset, port);
|
||||
}
|
||||
|
||||
static void setup_gpio(u8 __iomem *p)
|
||||
static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
|
||||
{
|
||||
/*
|
||||
* The Commtech adapters required the MPIOs to be driven low. The Exar
|
||||
* devices will export them as GPIOs, so we pre-configure them safely
|
||||
* as inputs.
|
||||
*/
|
||||
u8 dir = pcidev->vendor == PCI_VENDOR_ID_EXAR ? 0xff : 0x00;
|
||||
|
||||
writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
|
||||
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
|
||||
writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
|
||||
writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
|
||||
writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
|
||||
writeb(dir, p + UART_EXAR_MPIOSEL_7_0);
|
||||
writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
|
||||
writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
|
||||
writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
|
||||
writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
|
||||
writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
|
||||
writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
|
||||
writeb(dir, p + UART_EXAR_MPIOSEL_15_8);
|
||||
writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
|
||||
}
|
||||
|
||||
@ -236,7 +242,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
||||
|
||||
if (idx == 0) {
|
||||
/* Setup Multipurpose Input/Output pins. */
|
||||
setup_gpio(p);
|
||||
setup_gpio(pcidev, p);
|
||||
|
||||
port->port.private_data = xr17v35x_register_gpio(pcidev);
|
||||
}
|
||||
|
@ -19,11 +19,13 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
struct of_serial_info {
|
||||
struct clk *clk;
|
||||
struct reset_control *rst;
|
||||
int type;
|
||||
int line;
|
||||
};
|
||||
@ -132,6 +134,13 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||
}
|
||||
}
|
||||
|
||||
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
|
||||
if (IS_ERR(info->rst))
|
||||
goto out;
|
||||
ret = reset_control_deassert(info->rst);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
port->type = type;
|
||||
port->uartclk = clk;
|
||||
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
|
||||
@ -229,6 +238,7 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
|
||||
|
||||
serial8250_unregister_port(info->line);
|
||||
|
||||
reset_control_assert(info->rst);
|
||||
if (info->clk)
|
||||
clk_disable_unprepare(info->clk);
|
||||
kfree(info);
|
||||
|
@ -613,6 +613,10 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
up->lsr_saved_flags = 0;
|
||||
up->msr_saved_flags = 0;
|
||||
|
||||
/* Disable DMA for console UART */
|
||||
if (uart_console(port))
|
||||
up->dma = NULL;
|
||||
|
||||
if (up->dma) {
|
||||
ret = serial8250_request_dma(up);
|
||||
if (ret) {
|
||||
@ -782,8 +786,27 @@ unlock:
|
||||
|
||||
static void __dma_rx_complete(void *param)
|
||||
{
|
||||
__dma_rx_do_complete(param);
|
||||
omap_8250_rx_dma(param);
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct dma_tx_state state;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&p->port.lock, flags);
|
||||
|
||||
/*
|
||||
* If the tx status is not DMA_COMPLETE, then this is a delayed
|
||||
* completion callback. A previous RX timeout flush would have
|
||||
* already pushed the data, so exit.
|
||||
*/
|
||||
if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) !=
|
||||
DMA_COMPLETE) {
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
return;
|
||||
}
|
||||
__dma_rx_do_complete(p);
|
||||
omap_8250_rx_dma(p);
|
||||
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
||||
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
|
@ -1764,6 +1764,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
if ((up->capabilities & UART_CAP_HFIFO) &&
|
||||
(serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
|
||||
break;
|
||||
/* The BCM2835 MINI UART THRE bit is really a not-full bit. */
|
||||
if ((up->capabilities & UART_CAP_MINI) &&
|
||||
!(serial_in(up, UART_LSR) & UART_LSR_THRE))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
@ -2228,7 +2232,7 @@ int serial8250_do_startup(struct uart_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
if (port->irq) {
|
||||
if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) {
|
||||
unsigned char iir1;
|
||||
/*
|
||||
* Test for UARTs that do not reassert THRE when the
|
||||
@ -2585,6 +2589,12 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot, frac = 0;
|
||||
|
||||
if (up->capabilities & UART_CAP_MINI) {
|
||||
termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR);
|
||||
if ((termios->c_cflag & CSIZE) == CS5 ||
|
||||
(termios->c_cflag & CSIZE) == CS6)
|
||||
termios->c_cflag = (termios->c_cflag & ~CSIZE) | CS7;
|
||||
}
|
||||
cval = serial8250_compute_lcr(up, termios->c_cflag);
|
||||
|
||||
baud = serial8250_get_baud_rate(port, termios, old);
|
||||
|
@ -224,6 +224,16 @@ config SERIAL_8250_ACCENT
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called 8250_accent.
|
||||
|
||||
config SERIAL_8250_ASPEED_VUART
|
||||
tristate "Aspeed Virtual UART"
|
||||
depends on SERIAL_8250
|
||||
depends on OF
|
||||
help
|
||||
If you want to use the virtual UART (VUART) device on Aspeed
|
||||
BMC platforms, enable this option. This enables the 16550A-
|
||||
compatible device on the local LPC bus, giving a UART device
|
||||
with no physical RS232 connections.
|
||||
|
||||
config SERIAL_8250_BOCA
|
||||
tristate "Support Boca cards"
|
||||
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
|
||||
|
@ -14,6 +14,7 @@ obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o
|
||||
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
|
||||
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
|
||||
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
|
||||
obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o
|
||||
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
|
||||
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
|
||||
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
|
||||
|
@ -114,32 +114,32 @@ config SERIAL_SB1250_DUART_CONSOLE
|
||||
If unsure, say Y.
|
||||
|
||||
config SERIAL_ATMEL
|
||||
bool "AT91 / AT32 on-chip serial port support"
|
||||
bool "AT91 on-chip serial port support"
|
||||
depends on HAS_DMA
|
||||
depends on ARCH_AT91 || AVR32 || COMPILE_TEST
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
help
|
||||
This enables the driver for the on-chip UARTs of the Atmel
|
||||
AT91 and AT32 processors.
|
||||
AT91 processors.
|
||||
|
||||
config SERIAL_ATMEL_CONSOLE
|
||||
bool "Support for console on AT91 / AT32 serial port"
|
||||
bool "Support for console on AT91 serial port"
|
||||
depends on SERIAL_ATMEL=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
Say Y here if you wish to use an on-chip UART on a Atmel
|
||||
AT91 or AT32 processor as the system console (the system
|
||||
AT91 processor as the system console (the system
|
||||
console is the device which receives all kernel messages and
|
||||
warnings and which allows logins in single user mode).
|
||||
|
||||
config SERIAL_ATMEL_PDC
|
||||
bool "Support DMA transfers on AT91 / AT32 serial port"
|
||||
bool "Support DMA transfers on AT91 serial port"
|
||||
depends on SERIAL_ATMEL
|
||||
default y
|
||||
help
|
||||
Say Y here if you wish to use the PDC to do DMA transfers to
|
||||
and from the Atmel AT91 / AT32 serial port. In order to
|
||||
and from the Atmel AT91 serial port. In order to
|
||||
actually use DMA transfers, make sure that the use_dma_tx
|
||||
and use_dma_rx members in the atmel_uart_data struct is set
|
||||
appropriately for each port.
|
||||
@ -152,7 +152,7 @@ config SERIAL_ATMEL_TTYAT
|
||||
bool "Install as device ttyATn instead of ttySn"
|
||||
depends on SERIAL_ATMEL=y
|
||||
help
|
||||
Say Y here if you wish to have the internal AT91 / AT32 UARTs
|
||||
Say Y here if you wish to have the internal AT91 UARTs
|
||||
appear as /dev/ttyATn (major 204, minor starting at 154)
|
||||
instead of the normal /dev/ttySn (major 4, minor starting at
|
||||
64). This is necessary if you also want other UARTs, such as
|
||||
@ -1688,6 +1688,25 @@ config SERIAL_MVEBU_CONSOLE
|
||||
and warnings and which allows logins in single user mode)
|
||||
Otherwise, say 'N'.
|
||||
|
||||
config SERIAL_OWL
|
||||
bool "Actions Semi Owl serial port support"
|
||||
depends on ARCH_ACTIONS || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver is for Actions Semiconductor S500/S900 SoC's UART.
|
||||
Say 'Y' here if you wish to use the on-board serial port.
|
||||
Otherwise, say 'N'.
|
||||
|
||||
config SERIAL_OWL_CONSOLE
|
||||
bool "Console on Actions Semi Owl serial port"
|
||||
depends on SERIAL_OWL=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
default y
|
||||
help
|
||||
Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART
|
||||
as the system console. Only earlycon is implemented currently.
|
||||
|
||||
endmenu
|
||||
|
||||
config SERIAL_MCTRL_GPIO
|
||||
|
@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
|
||||
obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
|
||||
obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o
|
||||
obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o
|
||||
obj-$(CONFIG_SERIAL_OWL) += owl-uart.o
|
||||
|
||||
# GPIOLIB helpers for modem control lines
|
||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||
|
@ -697,6 +697,7 @@ static struct console amba_console = {
|
||||
#define AMBA_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
static DEFINE_MUTEX(amba_reg_lock);
|
||||
static struct uart_driver amba_reg = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "ttyAM",
|
||||
@ -749,6 +750,19 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
|
||||
amba_ports[i] = uap;
|
||||
|
||||
amba_set_drvdata(dev, uap);
|
||||
|
||||
mutex_lock(&amba_reg_lock);
|
||||
if (!amba_reg.state) {
|
||||
ret = uart_register_driver(&amba_reg);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&amba_reg_lock);
|
||||
dev_err(uap->port.dev,
|
||||
"Failed to register AMBA-PL010 driver\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&amba_reg_lock);
|
||||
|
||||
ret = uart_add_one_port(&amba_reg, &uap->port);
|
||||
if (ret)
|
||||
amba_ports[i] = NULL;
|
||||
@ -760,12 +774,18 @@ static int pl010_remove(struct amba_device *dev)
|
||||
{
|
||||
struct uart_amba_port *uap = amba_get_drvdata(dev);
|
||||
int i;
|
||||
bool busy = false;
|
||||
|
||||
uart_remove_one_port(&amba_reg, &uap->port);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
|
||||
if (amba_ports[i] == uap)
|
||||
amba_ports[i] = NULL;
|
||||
else if (amba_ports[i])
|
||||
busy = true;
|
||||
|
||||
if (!busy)
|
||||
uart_unregister_driver(&amba_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -816,23 +836,14 @@ static struct amba_driver pl010_driver = {
|
||||
|
||||
static int __init pl010_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "Serial: AMBA driver\n");
|
||||
|
||||
ret = uart_register_driver(&amba_reg);
|
||||
if (ret == 0) {
|
||||
ret = amba_driver_register(&pl010_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&amba_reg);
|
||||
}
|
||||
return ret;
|
||||
return amba_driver_register(&pl010_driver);
|
||||
}
|
||||
|
||||
static void __exit pl010_exit(void)
|
||||
{
|
||||
amba_driver_unregister(&pl010_driver);
|
||||
uart_unregister_driver(&amba_reg);
|
||||
}
|
||||
|
||||
module_init(pl010_init);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Driver for Atmel AT91 / AT32 Serial ports
|
||||
* Driver for Atmel AT91 Serial ports
|
||||
* Copyright (C) 2003 Rick Bronson
|
||||
*
|
||||
* Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
|
||||
@ -46,6 +46,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/ioctls.h>
|
||||
@ -118,7 +119,6 @@ struct atmel_uart_char {
|
||||
|
||||
/*
|
||||
* at91: 6 USARTs and one DBGU port (SAM9260)
|
||||
* avr32: 4
|
||||
* samx7: 3 USARTs and 5 UARTs
|
||||
*/
|
||||
#define ATMEL_MAX_UART 8
|
||||
@ -228,21 +228,6 @@ static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value)
|
||||
__raw_writel(value, port->membase + reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AVR32
|
||||
|
||||
/* AVR32 cannot handle 8 or 16bit I/O accesses but only 32bit I/O accesses */
|
||||
static inline u8 atmel_uart_read_char(struct uart_port *port)
|
||||
{
|
||||
return __raw_readl(port->membase + ATMEL_US_RHR);
|
||||
}
|
||||
|
||||
static inline void atmel_uart_write_char(struct uart_port *port, u8 value)
|
||||
{
|
||||
__raw_writel(value, port->membase + ATMEL_US_THR);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline u8 atmel_uart_read_char(struct uart_port *port)
|
||||
{
|
||||
return __raw_readb(port->membase + ATMEL_US_RHR);
|
||||
@ -253,8 +238,6 @@ static inline void atmel_uart_write_char(struct uart_port *port, u8 value)
|
||||
__raw_writeb(value, port->membase + ATMEL_US_THR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_ATMEL_PDC
|
||||
static bool atmel_use_pdc_rx(struct uart_port *port)
|
||||
{
|
||||
@ -959,7 +942,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
|
||||
sg_set_page(&atmel_port->sg_tx,
|
||||
virt_to_page(port->state->xmit.buf),
|
||||
UART_XMIT_SIZE,
|
||||
(unsigned long)port->state->xmit.buf & ~PAGE_MASK);
|
||||
offset_in_page(port->state->xmit.buf));
|
||||
nent = dma_map_sg(port->dev,
|
||||
&atmel_port->sg_tx,
|
||||
1,
|
||||
@ -1141,7 +1124,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
||||
sg_set_page(&atmel_port->sg_rx,
|
||||
virt_to_page(ring->buf),
|
||||
sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
|
||||
(unsigned long)ring->buf & ~PAGE_MASK);
|
||||
offset_in_page(ring->buf));
|
||||
nent = dma_map_sg(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
@ -1655,72 +1638,56 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (np) {
|
||||
/* DMA/PDC usage specification */
|
||||
if (of_property_read_bool(np, "atmel,use-dma-rx")) {
|
||||
if (of_property_read_bool(np, "dmas")) {
|
||||
atmel_port->use_dma_rx = true;
|
||||
atmel_port->use_pdc_rx = false;
|
||||
} else {
|
||||
atmel_port->use_dma_rx = false;
|
||||
atmel_port->use_pdc_rx = true;
|
||||
}
|
||||
/* DMA/PDC usage specification */
|
||||
if (of_property_read_bool(np, "atmel,use-dma-rx")) {
|
||||
if (of_property_read_bool(np, "dmas")) {
|
||||
atmel_port->use_dma_rx = true;
|
||||
atmel_port->use_pdc_rx = false;
|
||||
} else {
|
||||
atmel_port->use_dma_rx = false;
|
||||
atmel_port->use_pdc_rx = false;
|
||||
atmel_port->use_pdc_rx = true;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "atmel,use-dma-tx")) {
|
||||
if (of_property_read_bool(np, "dmas")) {
|
||||
atmel_port->use_dma_tx = true;
|
||||
atmel_port->use_pdc_tx = false;
|
||||
} else {
|
||||
atmel_port->use_dma_tx = false;
|
||||
atmel_port->use_pdc_tx = true;
|
||||
}
|
||||
} else {
|
||||
atmel_port->use_dma_tx = false;
|
||||
atmel_port->use_pdc_tx = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
atmel_port->use_pdc_rx = pdata->use_dma_rx;
|
||||
atmel_port->use_pdc_tx = pdata->use_dma_tx;
|
||||
atmel_port->use_dma_rx = false;
|
||||
atmel_port->use_dma_tx = false;
|
||||
atmel_port->use_pdc_rx = false;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "atmel,use-dma-tx")) {
|
||||
if (of_property_read_bool(np, "dmas")) {
|
||||
atmel_port->use_dma_tx = true;
|
||||
atmel_port->use_pdc_tx = false;
|
||||
} else {
|
||||
atmel_port->use_dma_tx = false;
|
||||
atmel_port->use_pdc_tx = true;
|
||||
}
|
||||
} else {
|
||||
atmel_port->use_dma_tx = false;
|
||||
atmel_port->use_pdc_tx = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void atmel_init_rs485(struct uart_port *port,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (np) {
|
||||
struct serial_rs485 *rs485conf = &port->rs485;
|
||||
u32 rs485_delay[2];
|
||||
/* rs485 properties */
|
||||
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
||||
rs485_delay, 2) == 0) {
|
||||
rs485conf->delay_rts_before_send = rs485_delay[0];
|
||||
rs485conf->delay_rts_after_send = rs485_delay[1];
|
||||
rs485conf->flags = 0;
|
||||
}
|
||||
struct serial_rs485 *rs485conf = &port->rs485;
|
||||
u32 rs485_delay[2];
|
||||
|
||||
if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||
|
||||
if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
|
||||
NULL))
|
||||
rs485conf->flags |= SER_RS485_ENABLED;
|
||||
} else {
|
||||
port->rs485 = pdata->rs485;
|
||||
/* rs485 properties */
|
||||
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
||||
rs485_delay, 2) == 0) {
|
||||
rs485conf->delay_rts_before_send = rs485_delay[0];
|
||||
rs485conf->delay_rts_after_send = rs485_delay[1];
|
||||
rs485conf->flags = 0;
|
||||
}
|
||||
|
||||
if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||
|
||||
if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
|
||||
rs485conf->flags |= SER_RS485_ENABLED;
|
||||
}
|
||||
|
||||
static void atmel_set_ops(struct uart_port *port)
|
||||
@ -2402,7 +2369,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
||||
{
|
||||
int ret;
|
||||
struct uart_port *port = &atmel_port->uart;
|
||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
atmel_init_property(atmel_port, pdev);
|
||||
atmel_set_ops(port);
|
||||
@ -2410,24 +2376,17 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
||||
atmel_init_rs485(port, pdev);
|
||||
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
|
||||
port->ops = &atmel_pops;
|
||||
port->fifosize = 1;
|
||||
port->dev = &pdev->dev;
|
||||
port->mapbase = pdev->resource[0].start;
|
||||
port->irq = pdev->resource[1].start;
|
||||
port->rs485_config = atmel_config_rs485;
|
||||
port->membase = NULL;
|
||||
|
||||
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
|
||||
|
||||
if (pdata && pdata->regs) {
|
||||
/* Already mapped by setup code */
|
||||
port->membase = pdata->regs;
|
||||
} else {
|
||||
port->flags |= UPF_IOREMAP;
|
||||
port->membase = NULL;
|
||||
}
|
||||
|
||||
/* for console, the clock could already be configured */
|
||||
if (!atmel_port->clk) {
|
||||
atmel_port->clk = clk_get(&pdev->dev, "usart");
|
||||
@ -2460,8 +2419,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct platform_device *atmel_default_console_device; /* the serial console device */
|
||||
|
||||
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
|
||||
static void atmel_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
@ -2594,47 +2551,6 @@ static struct console atmel_console = {
|
||||
|
||||
#define ATMEL_CONSOLE_DEVICE (&atmel_console)
|
||||
|
||||
/*
|
||||
* Early console initialization (before VM subsystem initialized).
|
||||
*/
|
||||
static int __init atmel_console_init(void)
|
||||
{
|
||||
int ret;
|
||||
if (atmel_default_console_device) {
|
||||
struct atmel_uart_data *pdata =
|
||||
dev_get_platdata(&atmel_default_console_device->dev);
|
||||
int id = pdata->num;
|
||||
struct atmel_uart_port *atmel_port = &atmel_ports[id];
|
||||
|
||||
atmel_port->backup_imr = 0;
|
||||
atmel_port->uart.line = id;
|
||||
|
||||
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
|
||||
ret = atmel_init_port(atmel_port, atmel_default_console_device);
|
||||
if (ret)
|
||||
return ret;
|
||||
register_console(&atmel_console);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
console_initcall(atmel_console_init);
|
||||
|
||||
/*
|
||||
* Late console initialization.
|
||||
*/
|
||||
static int __init atmel_late_console_init(void)
|
||||
{
|
||||
if (atmel_default_console_device
|
||||
&& !(atmel_console.flags & CON_ENABLED))
|
||||
register_console(&atmel_console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
core_initcall(atmel_late_console_init);
|
||||
|
||||
static inline bool atmel_is_console_port(struct uart_port *port)
|
||||
{
|
||||
return port->cons && port->cons->index == port->line;
|
||||
@ -2804,19 +2720,13 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
void *data;
|
||||
int ret = -ENODEV;
|
||||
bool rs485_enabled;
|
||||
|
||||
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
|
||||
|
||||
if (np)
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
else
|
||||
if (pdata)
|
||||
ret = pdata->num;
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0)
|
||||
/* port id not found in platform data nor device-tree aliases:
|
||||
* auto-enumerate it */
|
||||
|
@ -140,6 +140,8 @@
|
||||
#define UARTBAUD_SBNS 0x00002000
|
||||
#define UARTBAUD_SBR 0x00000000
|
||||
#define UARTBAUD_SBR_MASK 0x1fff
|
||||
#define UARTBAUD_OSR_MASK 0x1f
|
||||
#define UARTBAUD_OSR_SHIFT 24
|
||||
|
||||
#define UARTSTAT_LBKDIF 0x80000000
|
||||
#define UARTSTAT_RXEDGIF 0x40000000
|
||||
@ -231,12 +233,14 @@
|
||||
#define DEV_NAME "ttyLP"
|
||||
#define UART_NR 6
|
||||
|
||||
/* IMX lpuart has four extra unused regs located at the beginning */
|
||||
#define IMX_REG_OFF 0x10
|
||||
|
||||
struct lpuart_port {
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
unsigned int txfifo_size;
|
||||
unsigned int rxfifo_size;
|
||||
bool lpuart32;
|
||||
|
||||
bool lpuart_dma_tx_use;
|
||||
bool lpuart_dma_rx_use;
|
||||
@ -258,13 +262,28 @@ struct lpuart_port {
|
||||
wait_queue_head_t dma_wait;
|
||||
};
|
||||
|
||||
struct lpuart_soc_data {
|
||||
char iotype;
|
||||
u8 reg_off;
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data vf_data = {
|
||||
.iotype = UPIO_MEM,
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data ls_data = {
|
||||
.iotype = UPIO_MEM32BE,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx_data = {
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
};
|
||||
|
||||
static const struct of_device_id lpuart_dt_ids[] = {
|
||||
{
|
||||
.compatible = "fsl,vf610-lpuart",
|
||||
},
|
||||
{
|
||||
.compatible = "fsl,ls1021a-lpuart",
|
||||
},
|
||||
{ .compatible = "fsl,vf610-lpuart", .data = &vf_data, },
|
||||
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls_data, },
|
||||
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
||||
@ -272,14 +291,29 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
||||
/* Forward declare this for the dma callbacks*/
|
||||
static void lpuart_dma_tx_complete(void *arg);
|
||||
|
||||
static u32 lpuart32_read(void __iomem *addr)
|
||||
static inline u32 lpuart32_read(struct uart_port *port, u32 off)
|
||||
{
|
||||
return ioread32be(addr);
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM32:
|
||||
return readl(port->membase + off);
|
||||
case UPIO_MEM32BE:
|
||||
return ioread32be(port->membase + off);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpuart32_write(u32 val, void __iomem *addr)
|
||||
static inline void lpuart32_write(struct uart_port *port, u32 val,
|
||||
u32 off)
|
||||
{
|
||||
iowrite32be(val, addr);
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM32:
|
||||
writel(val, port->membase + off);
|
||||
break;
|
||||
case UPIO_MEM32BE:
|
||||
iowrite32be(val, port->membase + off);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpuart_stop_tx(struct uart_port *port)
|
||||
@ -295,9 +329,9 @@ static void lpuart32_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
||||
temp = lpuart32_read(port, UARTCTRL);
|
||||
temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
|
||||
lpuart32_write(temp, port->membase + UARTCTRL);
|
||||
lpuart32_write(port, temp, UARTCTRL);
|
||||
}
|
||||
|
||||
static void lpuart_stop_rx(struct uart_port *port)
|
||||
@ -312,8 +346,8 @@ static void lpuart32_stop_rx(struct uart_port *port)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
||||
lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL);
|
||||
temp = lpuart32_read(port, UARTCTRL);
|
||||
lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL);
|
||||
}
|
||||
|
||||
static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||
@ -512,14 +546,14 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
unsigned long txcnt;
|
||||
|
||||
txcnt = lpuart32_read(sport->port.membase + UARTWATER);
|
||||
txcnt = lpuart32_read(&sport->port, UARTWATER);
|
||||
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
||||
txcnt &= UARTWATER_COUNT_MASK;
|
||||
while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
|
||||
lpuart32_write(xmit->buf[xmit->tail], sport->port.membase + UARTDATA);
|
||||
lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx++;
|
||||
txcnt = lpuart32_read(sport->port.membase + UARTWATER);
|
||||
txcnt = lpuart32_read(&sport->port, UARTWATER);
|
||||
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
||||
txcnt &= UARTWATER_COUNT_MASK;
|
||||
}
|
||||
@ -555,10 +589,10 @@ static void lpuart32_start_tx(struct uart_port *port)
|
||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
unsigned long temp;
|
||||
|
||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
||||
lpuart32_write(temp | UARTCTRL_TIE, port->membase + UARTCTRL);
|
||||
temp = lpuart32_read(port, UARTCTRL);
|
||||
lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
|
||||
|
||||
if (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE)
|
||||
if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
|
||||
lpuart32_transmit_buffer(sport);
|
||||
}
|
||||
|
||||
@ -581,7 +615,7 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
|
||||
|
||||
static unsigned int lpuart32_tx_empty(struct uart_port *port)
|
||||
{
|
||||
return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ?
|
||||
return (lpuart32_read(port, UARTSTAT) & UARTSTAT_TC) ?
|
||||
TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
@ -593,22 +627,22 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id)
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (sport->port.x_char) {
|
||||
if (sport->lpuart32)
|
||||
lpuart32_write(sport->port.x_char, sport->port.membase + UARTDATA);
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||
lpuart32_write(&sport->port, sport->port.x_char, UARTDATA);
|
||||
else
|
||||
writeb(sport->port.x_char, sport->port.membase + UARTDR);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
|
||||
if (sport->lpuart32)
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||
lpuart32_stop_tx(&sport->port);
|
||||
else
|
||||
lpuart_stop_tx(&sport->port);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sport->lpuart32)
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||
lpuart32_transmit_buffer(sport);
|
||||
else
|
||||
lpuart_transmit_buffer(sport);
|
||||
@ -694,15 +728,15 @@ static irqreturn_t lpuart32_rxint(int irq, void *dev_id)
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
while (!(lpuart32_read(sport->port.membase + UARTFIFO) & UARTFIFO_RXEMPT)) {
|
||||
while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) {
|
||||
flg = TTY_NORMAL;
|
||||
sport->port.icount.rx++;
|
||||
/*
|
||||
* to clear the FE, OR, NF, FE, PE flags,
|
||||
* read STAT then read DATA reg
|
||||
*/
|
||||
sr = lpuart32_read(sport->port.membase + UARTSTAT);
|
||||
rx = lpuart32_read(sport->port.membase + UARTDATA);
|
||||
sr = lpuart32_read(&sport->port, UARTSTAT);
|
||||
rx = lpuart32_read(&sport->port, UARTDATA);
|
||||
rx &= 0x3ff;
|
||||
|
||||
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
|
||||
@ -769,18 +803,18 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
|
||||
struct lpuart_port *sport = dev_id;
|
||||
unsigned long sts, rxcount;
|
||||
|
||||
sts = lpuart32_read(sport->port.membase + UARTSTAT);
|
||||
rxcount = lpuart32_read(sport->port.membase + UARTWATER);
|
||||
sts = lpuart32_read(&sport->port, UARTSTAT);
|
||||
rxcount = lpuart32_read(&sport->port, UARTWATER);
|
||||
rxcount = rxcount >> UARTWATER_RXCNT_OFF;
|
||||
|
||||
if (sts & UARTSTAT_RDRF || rxcount > 0)
|
||||
lpuart32_rxint(irq, dev_id);
|
||||
|
||||
if ((sts & UARTSTAT_TDRE) &&
|
||||
!(lpuart32_read(sport->port.membase + UARTBAUD) & UARTBAUD_TDMAE))
|
||||
!(lpuart32_read(&sport->port, UARTBAUD) & UARTBAUD_TDMAE))
|
||||
lpuart_txint(irq, dev_id);
|
||||
|
||||
lpuart32_write(sts, sport->port.membase + UARTSTAT);
|
||||
lpuart32_write(&sport->port, sts, UARTSTAT);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -1041,7 +1075,7 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
|
||||
unsigned int temp = 0;
|
||||
unsigned long reg;
|
||||
|
||||
reg = lpuart32_read(port->membase + UARTMODIR);
|
||||
reg = lpuart32_read(port, UARTMODIR);
|
||||
if (reg & UARTMODIR_TXCTSE)
|
||||
temp |= TIOCM_CTS;
|
||||
|
||||
@ -1076,7 +1110,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
temp = lpuart32_read(port->membase + UARTMODIR) &
|
||||
temp = lpuart32_read(port, UARTMODIR) &
|
||||
~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
@ -1085,7 +1119,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
if (mctrl & TIOCM_CTS)
|
||||
temp |= UARTMODIR_TXCTSE;
|
||||
|
||||
lpuart32_write(temp, port->membase + UARTMODIR);
|
||||
lpuart32_write(port, temp, UARTMODIR);
|
||||
}
|
||||
|
||||
static void lpuart_break_ctl(struct uart_port *port, int break_state)
|
||||
@ -1104,12 +1138,12 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
temp = lpuart32_read(port->membase + UARTCTRL) & ~UARTCTRL_SBK;
|
||||
temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
|
||||
|
||||
if (break_state != 0)
|
||||
temp |= UARTCTRL_SBK;
|
||||
|
||||
lpuart32_write(temp, port->membase + UARTCTRL);
|
||||
lpuart32_write(port, temp, UARTCTRL);
|
||||
}
|
||||
|
||||
static void lpuart_setup_watermark(struct lpuart_port *sport)
|
||||
@ -1149,24 +1183,24 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
|
||||
unsigned long val, ctrl;
|
||||
unsigned long ctrl_saved;
|
||||
|
||||
ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
||||
ctrl_saved = ctrl;
|
||||
ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
|
||||
UARTCTRL_RIE | UARTCTRL_RE);
|
||||
lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
||||
|
||||
/* enable FIFO mode */
|
||||
val = lpuart32_read(sport->port.membase + UARTFIFO);
|
||||
val = lpuart32_read(&sport->port, UARTFIFO);
|
||||
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
|
||||
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
|
||||
lpuart32_write(val, sport->port.membase + UARTFIFO);
|
||||
lpuart32_write(&sport->port, val, UARTFIFO);
|
||||
|
||||
/* set the watermark */
|
||||
val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
|
||||
lpuart32_write(val, sport->port.membase + UARTWATER);
|
||||
lpuart32_write(&sport->port, val, UARTWATER);
|
||||
|
||||
/* Restore cr2 */
|
||||
lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, ctrl_saved, UARTCTRL);
|
||||
}
|
||||
|
||||
static void rx_dma_timer_init(struct lpuart_port *sport)
|
||||
@ -1242,7 +1276,7 @@ static int lpuart32_startup(struct uart_port *port)
|
||||
unsigned long temp;
|
||||
|
||||
/* determine FIFO size */
|
||||
temp = lpuart32_read(sport->port.membase + UARTFIFO);
|
||||
temp = lpuart32_read(&sport->port, UARTFIFO);
|
||||
|
||||
sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) &
|
||||
UARTFIFO_FIFOSIZE_MASK) - 1);
|
||||
@ -1259,10 +1293,10 @@ static int lpuart32_startup(struct uart_port *port)
|
||||
|
||||
lpuart32_setup_watermark(sport);
|
||||
|
||||
temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE);
|
||||
temp |= UARTCTRL_ILIE;
|
||||
lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
return 0;
|
||||
@ -1311,10 +1345,10 @@ static void lpuart32_shutdown(struct uart_port *port)
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* disable Rx/Tx and interrupts */
|
||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
||||
temp = lpuart32_read(port, UARTCTRL);
|
||||
temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
|
||||
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
||||
lpuart32_write(temp, port->membase + UARTCTRL);
|
||||
lpuart32_write(port, temp, UARTCTRL);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
@ -1478,6 +1512,75 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate)
|
||||
{
|
||||
u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
|
||||
u32 clk = sport->port.uartclk;
|
||||
|
||||
/*
|
||||
* The idea is to use the best OSR (over-sampling rate) possible.
|
||||
* Note, OSR is typically hard-set to 16 in other LPUART instantiations.
|
||||
* Loop to find the best OSR value possible, one that generates minimum
|
||||
* baud_diff iterate through the rest of the supported values of OSR.
|
||||
*
|
||||
* Calculation Formula:
|
||||
* Baud Rate = baud clock / ((OSR+1) × SBR)
|
||||
*/
|
||||
baud_diff = baudrate;
|
||||
osr = 0;
|
||||
sbr = 0;
|
||||
|
||||
for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
|
||||
/* calculate the temporary sbr value */
|
||||
tmp_sbr = (clk / (baudrate * tmp_osr));
|
||||
if (tmp_sbr == 0)
|
||||
tmp_sbr = 1;
|
||||
|
||||
/*
|
||||
* calculate the baud rate difference based on the temporary
|
||||
* osr and sbr values
|
||||
*/
|
||||
tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate;
|
||||
|
||||
/* select best values between sbr and sbr+1 */
|
||||
tmp = clk / (tmp_osr * (tmp_sbr + 1));
|
||||
if (tmp_diff > (baudrate - tmp)) {
|
||||
tmp_diff = baudrate - tmp;
|
||||
tmp_sbr++;
|
||||
}
|
||||
|
||||
if (tmp_diff <= baud_diff) {
|
||||
baud_diff = tmp_diff;
|
||||
osr = tmp_osr;
|
||||
sbr = tmp_sbr;
|
||||
|
||||
if (!baud_diff)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle buadrate outside acceptable rate */
|
||||
if (baud_diff > ((baudrate / 100) * 3))
|
||||
dev_warn(sport->port.dev,
|
||||
"unacceptable baud rate difference of more than 3%%\n");
|
||||
|
||||
tmp = lpuart32_read(&sport->port, UARTBAUD);
|
||||
|
||||
if ((osr > 3) && (osr < 8))
|
||||
tmp |= UARTBAUD_BOTHEDGE;
|
||||
|
||||
tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
|
||||
tmp |= (((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT);
|
||||
|
||||
tmp &= ~UARTBAUD_SBR_MASK;
|
||||
tmp |= sbr & UARTBAUD_SBR_MASK;
|
||||
|
||||
tmp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
|
||||
|
||||
lpuart32_write(&sport->port, tmp, UARTBAUD);
|
||||
}
|
||||
|
||||
static void
|
||||
lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
@ -1487,11 +1590,10 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
unsigned long ctrl, old_ctrl, bd, modem;
|
||||
unsigned int baud;
|
||||
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
|
||||
unsigned int sbr;
|
||||
|
||||
ctrl = old_ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
bd = lpuart32_read(sport->port.membase + UARTBAUD);
|
||||
modem = lpuart32_read(sport->port.membase + UARTMODIR);
|
||||
ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
||||
bd = lpuart32_read(&sport->port, UARTBAUD);
|
||||
modem = lpuart32_read(&sport->port, UARTMODIR);
|
||||
/*
|
||||
* only support CS8 and CS7, and for CS7 must enable PE.
|
||||
* supported mode:
|
||||
@ -1577,21 +1679,16 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
/* wait transmit engin complete */
|
||||
while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
|
||||
while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC))
|
||||
barrier();
|
||||
|
||||
/* disable transmit and receive */
|
||||
lpuart32_write(old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
|
||||
sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
|
||||
UARTCTRL);
|
||||
|
||||
sbr = sport->port.uartclk / (16 * baud);
|
||||
bd &= ~UARTBAUD_SBR_MASK;
|
||||
bd |= sbr & UARTBAUD_SBR_MASK;
|
||||
bd |= UARTBAUD_BOTHEDGE;
|
||||
bd &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
|
||||
lpuart32_write(bd, sport->port.membase + UARTBAUD);
|
||||
lpuart32_write(modem, sport->port.membase + UARTMODIR);
|
||||
lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
|
||||
lpuart32_serial_setbrg(sport, baud);
|
||||
lpuart32_write(&sport->port, modem, UARTMODIR);
|
||||
lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
||||
/* restore control register */
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
@ -1694,10 +1791,10 @@ static void lpuart_console_putchar(struct uart_port *port, int ch)
|
||||
|
||||
static void lpuart32_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
while (!(lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE))
|
||||
while (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE))
|
||||
barrier();
|
||||
|
||||
lpuart32_write(ch, port->membase + UARTDATA);
|
||||
lpuart32_write(port, ch, UARTDATA);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1745,18 +1842,18 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
/* first save CR2 and then disable interrupts */
|
||||
cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
cr = old_cr = lpuart32_read(&sport->port, UARTCTRL);
|
||||
cr |= (UARTCTRL_TE | UARTCTRL_RE);
|
||||
cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
||||
lpuart32_write(cr, sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, cr, UARTCTRL);
|
||||
|
||||
uart_console_write(&sport->port, s, count, lpuart32_console_putchar);
|
||||
|
||||
/* wait for transmitter finish complete and restore CR2 */
|
||||
while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
|
||||
while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC))
|
||||
barrier();
|
||||
|
||||
lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, old_cr, UARTCTRL);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
@ -1822,14 +1919,14 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
||||
unsigned long cr, bd;
|
||||
unsigned int sbr, uartclk, baud_raw;
|
||||
|
||||
cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
cr = lpuart32_read(&sport->port, UARTCTRL);
|
||||
cr &= UARTCTRL_TE | UARTCTRL_RE;
|
||||
if (!cr)
|
||||
return;
|
||||
|
||||
/* ok, the port was enabled */
|
||||
|
||||
cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
cr = lpuart32_read(&sport->port, UARTCTRL);
|
||||
|
||||
*parity = 'n';
|
||||
if (cr & UARTCTRL_PE) {
|
||||
@ -1844,7 +1941,7 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
||||
else
|
||||
*bits = 8;
|
||||
|
||||
bd = lpuart32_read(sport->port.membase + UARTBAUD);
|
||||
bd = lpuart32_read(&sport->port, UARTBAUD);
|
||||
bd &= UARTBAUD_SBR_MASK;
|
||||
sbr = bd;
|
||||
uartclk = clk_get_rate(sport->clk);
|
||||
@ -1881,12 +1978,12 @@ static int __init lpuart_console_setup(struct console *co, char *options)
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
else
|
||||
if (sport->lpuart32)
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||
lpuart32_console_get_options(sport, &baud, &parity, &bits);
|
||||
else
|
||||
lpuart_console_get_options(sport, &baud, &parity, &bits);
|
||||
|
||||
if (sport->lpuart32)
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||
lpuart32_setup_watermark(sport);
|
||||
else
|
||||
lpuart_setup_watermark(sport);
|
||||
@ -1945,12 +2042,26 @@ static int __init lpuart32_early_console_setup(struct earlycon_device *device,
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->port.iotype = UPIO_MEM32BE;
|
||||
device->con->write = lpuart32_early_write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init lpuart32_imx_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->port.iotype = UPIO_MEM32;
|
||||
device->port.membase += IMX_REG_OFF;
|
||||
device->con->write = lpuart32_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
|
||||
|
||||
@ -1971,6 +2082,9 @@ static struct uart_driver lpuart_reg = {
|
||||
|
||||
static int lpuart_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id = of_match_device(lpuart_dt_ids,
|
||||
&pdev->dev);
|
||||
const struct lpuart_soc_data *sdata = of_id->data;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct lpuart_port *sport;
|
||||
struct resource *res;
|
||||
@ -1988,25 +2102,23 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
sport->port.line = ret;
|
||||
sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(sport->port.membase))
|
||||
return PTR_ERR(sport->port.membase);
|
||||
|
||||
sport->port.membase += sdata->reg_off;
|
||||
sport->port.mapbase = res->start;
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.type = PORT_LPUART;
|
||||
sport->port.iotype = UPIO_MEM;
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot obtain irq\n");
|
||||
return ret;
|
||||
}
|
||||
sport->port.irq = ret;
|
||||
|
||||
if (sport->lpuart32)
|
||||
sport->port.iotype = sdata->iotype;
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||
sport->port.ops = &lpuart32_pops;
|
||||
else
|
||||
sport->port.ops = &lpuart_pops;
|
||||
@ -2033,7 +2145,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, &sport->port);
|
||||
|
||||
if (sport->lpuart32)
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||
lpuart_reg.cons = LPUART32_CONSOLE;
|
||||
else
|
||||
lpuart_reg.cons = LPUART_CONSOLE;
|
||||
@ -2086,11 +2198,11 @@ static int lpuart_suspend(struct device *dev)
|
||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
unsigned long temp;
|
||||
|
||||
if (sport->lpuart32) {
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
|
||||
/* disable Rx/Tx and interrupts */
|
||||
temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
|
||||
lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
} else {
|
||||
/* disable Rx/Tx and interrupts */
|
||||
temp = readb(sport->port.membase + UARTCR2);
|
||||
@ -2137,12 +2249,12 @@ static int lpuart_resume(struct device *dev)
|
||||
if (sport->port.suspended && !sport->port.irq_wake)
|
||||
clk_prepare_enable(sport->clk);
|
||||
|
||||
if (sport->lpuart32) {
|
||||
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
|
||||
lpuart32_setup_watermark(sport);
|
||||
temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
|
||||
UARTCTRL_TE | UARTCTRL_ILIE);
|
||||
lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
} else {
|
||||
lpuart_setup_watermark(sport);
|
||||
temp = readb(sport->port.membase + UARTCR2);
|
||||
|
@ -186,6 +186,11 @@
|
||||
|
||||
#define UART_NR 8
|
||||
|
||||
/* RX DMA buffer periods */
|
||||
#define RX_DMA_PERIODS 4
|
||||
#define RX_BUF_SIZE (PAGE_SIZE)
|
||||
|
||||
|
||||
/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */
|
||||
enum imx_uart_type {
|
||||
IMX1_UART,
|
||||
@ -207,9 +212,6 @@ struct imx_port {
|
||||
unsigned int have_rtscts:1;
|
||||
unsigned int have_rtsgpio:1;
|
||||
unsigned int dte_mode:1;
|
||||
unsigned int irda_inv_rx:1;
|
||||
unsigned int irda_inv_tx:1;
|
||||
unsigned short trcv_delay; /* transceiver delay */
|
||||
struct clk *clk_ipg;
|
||||
struct clk *clk_per;
|
||||
const struct imx_uart_data *devdata;
|
||||
@ -224,6 +226,7 @@ struct imx_port {
|
||||
struct dma_chan *dma_chan_rx, *dma_chan_tx;
|
||||
struct scatterlist rx_sgl, tx_sgl[2];
|
||||
void *rx_buf;
|
||||
unsigned int rx_buf_size;
|
||||
struct circ_buf rx_ring;
|
||||
unsigned int rx_periods;
|
||||
dma_cookie_t rx_cookie;
|
||||
@ -964,8 +967,6 @@ static void imx_timeout(unsigned long data)
|
||||
}
|
||||
}
|
||||
|
||||
#define RX_BUF_SIZE (PAGE_SIZE)
|
||||
|
||||
/*
|
||||
* There are two kinds of RX DMA interrupts(such as in the MX6Q):
|
||||
* [1] the RX DMA buffer is full.
|
||||
@ -1048,9 +1049,6 @@ static void dma_rx_callback(void *data)
|
||||
}
|
||||
}
|
||||
|
||||
/* RX DMA buffer periods */
|
||||
#define RX_DMA_PERIODS 4
|
||||
|
||||
static int start_rx_dma(struct imx_port *sport)
|
||||
{
|
||||
struct scatterlist *sgl = &sport->rx_sgl;
|
||||
@ -1061,9 +1059,8 @@ static int start_rx_dma(struct imx_port *sport)
|
||||
|
||||
sport->rx_ring.head = 0;
|
||||
sport->rx_ring.tail = 0;
|
||||
sport->rx_periods = RX_DMA_PERIODS;
|
||||
|
||||
sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
|
||||
sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size);
|
||||
ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
|
||||
if (ret == 0) {
|
||||
dev_err(dev, "DMA mapping error for RX.\n");
|
||||
@ -1174,7 +1171,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
|
||||
goto err;
|
||||
}
|
||||
|
||||
sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL);
|
||||
if (!sport->rx_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
@ -1302,7 +1299,9 @@ static int imx_startup(struct uart_port *port)
|
||||
imx_enable_dma(sport);
|
||||
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
|
||||
temp |= UCR1_RRDYEN | UCR1_UARTEN;
|
||||
if (sport->have_rtscts)
|
||||
temp |= UCR1_RTSDEN;
|
||||
|
||||
writel(temp, sport->port.membase + UCR1);
|
||||
|
||||
@ -1340,29 +1339,13 @@ static int imx_startup(struct uart_port *port)
|
||||
imx_enable_ms(&sport->port);
|
||||
|
||||
/*
|
||||
* If the serial port is opened for reading start RX DMA immediately
|
||||
* instead of waiting for RX FIFO interrupts. In our iMX53 the average
|
||||
* delay for the first reception dropped from approximately 35000
|
||||
* microseconds to 1000 microseconds.
|
||||
* Start RX DMA immediately instead of waiting for RX FIFO interrupts.
|
||||
* In our iMX53 the average delay for the first reception dropped from
|
||||
* approximately 35000 microseconds to 1000 microseconds.
|
||||
*/
|
||||
if (sport->dma_is_enabled) {
|
||||
struct tty_struct *tty = sport->port.state->port.tty;
|
||||
struct tty_file_private *file_priv;
|
||||
int readcnt = 0;
|
||||
|
||||
spin_lock(&tty->files_lock);
|
||||
|
||||
if (!list_empty(&tty->tty_files))
|
||||
list_for_each_entry(file_priv, &tty->tty_files, list)
|
||||
if (!(file_priv->file->f_flags & O_WRONLY))
|
||||
readcnt++;
|
||||
|
||||
spin_unlock(&tty->files_lock);
|
||||
|
||||
if (readcnt > 0) {
|
||||
imx_disable_rx_int(sport);
|
||||
start_rx_dma(sport);
|
||||
}
|
||||
imx_disable_rx_int(sport);
|
||||
start_rx_dma(sport);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
@ -2053,6 +2036,7 @@ static int serial_imx_probe_dt(struct imx_port *sport,
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
u32 dma_buf_size[2];
|
||||
|
||||
sport->devdata = of_device_get_match_data(&pdev->dev);
|
||||
if (!sport->devdata)
|
||||
@ -2076,6 +2060,14 @@ static int serial_imx_probe_dt(struct imx_port *sport,
|
||||
if (of_get_property(np, "rts-gpios", NULL))
|
||||
sport->have_rtsgpio = 1;
|
||||
|
||||
if (!of_property_read_u32_array(np, "fsl,dma-size", dma_buf_size, 2)) {
|
||||
sport->rx_buf_size = dma_buf_size[0] * dma_buf_size[1];
|
||||
sport->rx_periods = dma_buf_size[1];
|
||||
} else {
|
||||
sport->rx_buf_size = RX_BUF_SIZE;
|
||||
sport->rx_periods = RX_DMA_PERIODS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@ -286,7 +286,7 @@ static int meson_uart_startup(struct uart_port *port)
|
||||
writel(val, port->membase + AML_UART_MISC);
|
||||
|
||||
ret = request_irq(port->irq, meson_uart_interrupt, 0,
|
||||
meson_uart_type(port), port);
|
||||
port->name, port);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -298,8 +298,6 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
|
||||
while (!meson_uart_tx_empty(port))
|
||||
cpu_relax();
|
||||
|
||||
val = readl(port->membase + AML_UART_REG5);
|
||||
val &= ~AML_UART_BAUD_MASK;
|
||||
if (port->uartclk == 24000000) {
|
||||
val = ((port->uartclk / 3) / baud) - 1;
|
||||
val |= AML_UART_BAUD_XTAL;
|
||||
@ -355,7 +353,7 @@ static void meson_uart_set_termios(struct uart_port *port,
|
||||
if (cflags & CSTOPB)
|
||||
val |= AML_UART_STOP_BIN_2SB;
|
||||
else
|
||||
val &= ~AML_UART_STOP_BIN_1SB;
|
||||
val |= AML_UART_STOP_BIN_1SB;
|
||||
|
||||
if (cflags & CRTSCTS)
|
||||
val &= ~AML_UART_TWO_WIRE_EN;
|
||||
@ -395,51 +393,25 @@ static int meson_uart_verify_port(struct uart_port *port,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int meson_uart_res_size(struct uart_port *port)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(port->dev, "cannot obtain I/O memory region");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return resource_size(res);
|
||||
}
|
||||
|
||||
static void meson_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
int size = meson_uart_res_size(port);
|
||||
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
devm_release_mem_region(port->dev, port->mapbase, size);
|
||||
devm_iounmap(port->dev, port->membase);
|
||||
port->membase = NULL;
|
||||
}
|
||||
devm_iounmap(port->dev, port->membase);
|
||||
port->membase = NULL;
|
||||
devm_release_mem_region(port->dev, port->mapbase, port->mapsize);
|
||||
}
|
||||
|
||||
static int meson_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
int size = meson_uart_res_size(port);
|
||||
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
if (!devm_request_mem_region(port->dev, port->mapbase, size,
|
||||
if (!devm_request_mem_region(port->dev, port->mapbase, port->mapsize,
|
||||
dev_name(port->dev))) {
|
||||
dev_err(port->dev, "Memory region busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
port->membase = devm_ioremap_nocache(port->dev,
|
||||
port->mapbase,
|
||||
size);
|
||||
if (port->membase == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
port->membase = devm_ioremap_nocache(port->dev, port->mapbase,
|
||||
port->mapsize);
|
||||
if (!port->membase)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -470,6 +442,14 @@ static struct uart_ops meson_uart_ops = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_MESON_CONSOLE
|
||||
static void meson_uart_enable_tx_engine(struct uart_port *port)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(port->membase + AML_UART_CONTROL);
|
||||
val |= AML_UART_TX_EN;
|
||||
writel(val, port->membase + AML_UART_CONTROL);
|
||||
}
|
||||
|
||||
static void meson_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
@ -499,7 +479,6 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
||||
}
|
||||
|
||||
val = readl(port->membase + AML_UART_CONTROL);
|
||||
val |= AML_UART_TX_EN;
|
||||
tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
|
||||
writel(tmp, port->membase + AML_UART_CONTROL);
|
||||
|
||||
@ -538,6 +517,8 @@ static int meson_serial_console_setup(struct console *co, char *options)
|
||||
if (!port || !port->membase)
|
||||
return -ENODEV;
|
||||
|
||||
meson_uart_enable_tx_engine(port);
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
@ -576,11 +557,16 @@ meson_serial_early_console_setup(struct earlycon_device *device, const char *opt
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
meson_uart_enable_tx_engine(&device->port);
|
||||
device->con->write = meson_serial_early_console_write;
|
||||
return 0;
|
||||
}
|
||||
/* Legacy bindings, should be removed when no more used */
|
||||
OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart",
|
||||
meson_serial_early_console_setup);
|
||||
/* Stable bindings */
|
||||
OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart",
|
||||
meson_serial_early_console_setup);
|
||||
|
||||
#define MESON_SERIAL_CONSOLE (&meson_serial_console)
|
||||
#else
|
||||
@ -595,11 +581,76 @@ static struct uart_driver meson_uart_driver = {
|
||||
.cons = MESON_SERIAL_CONSOLE,
|
||||
};
|
||||
|
||||
static inline struct clk *meson_uart_probe_clock(struct device *dev,
|
||||
const char *id)
|
||||
{
|
||||
struct clk *clk = NULL;
|
||||
int ret;
|
||||
|
||||
clk = devm_clk_get(dev, id);
|
||||
if (IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "couldn't enable clk\n");
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
devm_add_action_or_reset(dev,
|
||||
(void(*)(void *))clk_disable_unprepare,
|
||||
clk);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gets clocks in the legacy non-stable DT bindings.
|
||||
* This code will be remove once all the platforms switch to the
|
||||
* new DT bindings.
|
||||
*/
|
||||
static int meson_uart_probe_clocks_legacy(struct platform_device *pdev,
|
||||
struct uart_port *port)
|
||||
{
|
||||
struct clk *clk = NULL;
|
||||
|
||||
clk = meson_uart_probe_clock(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
port->uartclk = clk_get_rate(clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_uart_probe_clocks(struct platform_device *pdev,
|
||||
struct uart_port *port)
|
||||
{
|
||||
struct clk *clk_xtal = NULL;
|
||||
struct clk *clk_pclk = NULL;
|
||||
struct clk *clk_baud = NULL;
|
||||
|
||||
clk_pclk = meson_uart_probe_clock(&pdev->dev, "pclk");
|
||||
if (IS_ERR(clk_pclk))
|
||||
return PTR_ERR(clk_pclk);
|
||||
|
||||
clk_xtal = meson_uart_probe_clock(&pdev->dev, "xtal");
|
||||
if (IS_ERR(clk_xtal))
|
||||
return PTR_ERR(clk_xtal);
|
||||
|
||||
clk_baud = meson_uart_probe_clock(&pdev->dev, "baud");
|
||||
if (IS_ERR(clk_baud))
|
||||
return PTR_ERR(clk_baud);
|
||||
|
||||
port->uartclk = clk_get_rate(clk_baud);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res_mem, *res_irq;
|
||||
struct uart_port *port;
|
||||
struct clk *clk;
|
||||
int ret = 0;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
@ -625,15 +676,20 @@ static int meson_uart_probe(struct platform_device *pdev)
|
||||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
/* Use legacy way until all platforms switch to new bindings */
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "amlogic,meson-uart"))
|
||||
ret = meson_uart_probe_clocks_legacy(pdev, port);
|
||||
else
|
||||
ret = meson_uart_probe_clocks(pdev, port);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port->uartclk = clk_get_rate(clk);
|
||||
port->iotype = UPIO_MEM;
|
||||
port->mapbase = res_mem->start;
|
||||
port->mapsize = resource_size(res_mem);
|
||||
port->irq = res_irq->start;
|
||||
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
|
||||
port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY;
|
||||
port->dev = &pdev->dev;
|
||||
port->line = pdev->id;
|
||||
port->type = PORT_MESON;
|
||||
@ -668,9 +724,14 @@ static int meson_uart_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct of_device_id meson_uart_dt_match[] = {
|
||||
/* Legacy bindings, should be removed when no more used */
|
||||
{ .compatible = "amlogic,meson-uart" },
|
||||
/* Stable bindings */
|
||||
{ .compatible = "amlogic,meson6-uart" },
|
||||
{ .compatible = "amlogic,meson8-uart" },
|
||||
{ .compatible = "amlogic,meson8b-uart" },
|
||||
{ .compatible = "amlogic,meson-gx-uart" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
|
||||
|
@ -754,9 +754,10 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
|
||||
if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
|
||||
printk(KERN_ERR "MPSC: Inadequate DMA support\n");
|
||||
rc = -ENXIO;
|
||||
} else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
|
||||
} else if ((pi->dma_region = dma_alloc_attrs(pi->port.dev,
|
||||
MPSC_DMA_ALLOC_SIZE,
|
||||
&pi->dma_region_p, GFP_KERNEL))
|
||||
&pi->dma_region_p, GFP_KERNEL,
|
||||
DMA_ATTR_NON_CONSISTENT))
|
||||
== NULL) {
|
||||
printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
|
||||
rc = -ENOMEM;
|
||||
@ -771,8 +772,9 @@ static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
|
||||
pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
|
||||
|
||||
if (pi->dma_region) {
|
||||
dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
|
||||
pi->dma_region, pi->dma_region_p);
|
||||
dma_free_attrs(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
|
||||
pi->dma_region, pi->dma_region_p,
|
||||
DMA_ATTR_NON_CONSISTENT);
|
||||
pi->dma_region = NULL;
|
||||
pi->dma_region_p = (dma_addr_t)NULL;
|
||||
}
|
||||
|
135
drivers/tty/serial/owl-uart.c
Normal file
135
drivers/tty/serial/owl-uart.c
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Actions Semi Owl family serial console
|
||||
*
|
||||
* Copyright 2013 Actions Semi Inc.
|
||||
* Author: Actions Semi, Inc.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Andreas Färber
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#define OWL_UART_CTL 0x000
|
||||
#define OWL_UART_TXDAT 0x008
|
||||
#define OWL_UART_STAT 0x00c
|
||||
|
||||
#define OWL_UART_CTL_TRFS_TX BIT(14)
|
||||
#define OWL_UART_CTL_EN BIT(15)
|
||||
#define OWL_UART_CTL_RXIE BIT(18)
|
||||
#define OWL_UART_CTL_TXIE BIT(19)
|
||||
|
||||
#define OWL_UART_STAT_RIP BIT(0)
|
||||
#define OWL_UART_STAT_TIP BIT(1)
|
||||
#define OWL_UART_STAT_TFFU BIT(6)
|
||||
#define OWL_UART_STAT_TRFL_MASK (0x1f << 11)
|
||||
#define OWL_UART_STAT_UTBB BIT(17)
|
||||
|
||||
static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off)
|
||||
{
|
||||
writel(val, port->membase + off);
|
||||
}
|
||||
|
||||
static inline u32 owl_uart_read(struct uart_port *port, unsigned int off)
|
||||
{
|
||||
return readl(port->membase + off);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_OWL_CONSOLE
|
||||
|
||||
static void owl_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
||||
while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)
|
||||
cpu_relax();
|
||||
|
||||
owl_uart_write(port, ch, OWL_UART_TXDAT);
|
||||
}
|
||||
|
||||
static void owl_uart_port_write(struct uart_port *port, const char *s,
|
||||
u_int count)
|
||||
{
|
||||
u32 old_ctl, val;
|
||||
unsigned long flags;
|
||||
int locked;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (port->sysrq)
|
||||
locked = 0;
|
||||
else if (oops_in_progress)
|
||||
locked = spin_trylock(&port->lock);
|
||||
else {
|
||||
spin_lock(&port->lock);
|
||||
locked = 1;
|
||||
}
|
||||
|
||||
old_ctl = owl_uart_read(port, OWL_UART_CTL);
|
||||
val = old_ctl | OWL_UART_CTL_TRFS_TX;
|
||||
/* disable IRQ */
|
||||
val &= ~(OWL_UART_CTL_RXIE | OWL_UART_CTL_TXIE);
|
||||
owl_uart_write(port, val, OWL_UART_CTL);
|
||||
|
||||
uart_console_write(port, s, count, owl_console_putchar);
|
||||
|
||||
/* wait until all contents have been sent out */
|
||||
while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TRFL_MASK)
|
||||
cpu_relax();
|
||||
|
||||
/* clear IRQ pending */
|
||||
val = owl_uart_read(port, OWL_UART_STAT);
|
||||
val |= OWL_UART_STAT_TIP | OWL_UART_STAT_RIP;
|
||||
owl_uart_write(port, val, OWL_UART_STAT);
|
||||
|
||||
owl_uart_write(port, old_ctl, OWL_UART_CTL);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void owl_uart_early_console_write(struct console *co,
|
||||
const char *s,
|
||||
u_int count)
|
||||
{
|
||||
struct earlycon_device *dev = co->data;
|
||||
|
||||
owl_uart_port_write(&dev->port, s, count);
|
||||
}
|
||||
|
||||
static int __init
|
||||
owl_uart_early_console_setup(struct earlycon_device *device, const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = owl_uart_early_console_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
OF_EARLYCON_DECLARE(owl, "actions,owl-uart",
|
||||
owl_uart_early_console_setup);
|
||||
|
||||
#endif /* CONFIG_SERIAL_OWL_CONSOLE */
|
@ -878,8 +878,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
|
||||
sg_dma_len(sg) = priv->trigger_level;
|
||||
|
||||
sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
|
||||
sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
|
||||
~PAGE_MASK);
|
||||
sg_dma_len(sg), offset_in_page(priv->rx_buf_virt));
|
||||
|
||||
sg_dma_address(sg) = priv->rx_buf_dma;
|
||||
|
||||
|
@ -884,14 +884,19 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
if (PTR_ERR(clk) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
ret = PTR_ERR(clk);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto err_out;
|
||||
}
|
||||
uartclk = 0;
|
||||
} else {
|
||||
clk_prepare_enable(clk);
|
||||
uartclk = clk_get_rate(clk);
|
||||
}
|
||||
|
||||
if (!uartclk) {
|
||||
dev_notice(&pdev->dev, "Using default clock frequency\n");
|
||||
uartclk = s->chip->freq_std;
|
||||
} else
|
||||
uartclk = clk_get_rate(clk);
|
||||
}
|
||||
|
||||
/* Check input frequency */
|
||||
if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
|
||||
|
@ -954,11 +954,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
||||
old_custom_divisor != uport->custom_divisor) {
|
||||
/*
|
||||
* If they're setting up a custom divisor or speed,
|
||||
* instead of clearing it, then bitch about it. No
|
||||
* need to rate-limit; it's CAP_SYS_ADMIN only.
|
||||
* instead of clearing it, then bitch about it.
|
||||
*/
|
||||
if (uport->flags & UPF_SPD_MASK) {
|
||||
dev_notice(uport->dev,
|
||||
dev_notice_ratelimited(uport->dev,
|
||||
"%s sets custom speed on %s. This is deprecated.\n",
|
||||
current->comm,
|
||||
tty_name(port->tty));
|
||||
|
@ -1450,8 +1450,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_compat failed\n");
|
||||
dev_warn(port->dev, "dma_request_slave_channel failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1558,7 +1557,16 @@ static void sci_free_dma(struct uart_port *port)
|
||||
if (s->chan_rx)
|
||||
sci_rx_dma_release(s, false);
|
||||
}
|
||||
#else
|
||||
|
||||
static void sci_flush_buffer(struct uart_port *port)
|
||||
{
|
||||
/*
|
||||
* In uart_flush_buffer(), the xmit circular buffer has just been
|
||||
* cleared, so we have to reset tx_dma_len accordingly.
|
||||
*/
|
||||
to_sci_port(port)->tx_dma_len = 0;
|
||||
}
|
||||
#else /* !CONFIG_SERIAL_SH_SCI_DMA */
|
||||
static inline void sci_request_dma(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
@ -1566,7 +1574,9 @@ static inline void sci_request_dma(struct uart_port *port)
|
||||
static inline void sci_free_dma(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#define sci_flush_buffer NULL
|
||||
#endif /* !CONFIG_SERIAL_SH_SCI_DMA */
|
||||
|
||||
static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
||||
{
|
||||
@ -2581,6 +2591,7 @@ static const struct uart_ops sci_uart_ops = {
|
||||
.break_ctl = sci_break_ctl,
|
||||
.startup = sci_startup,
|
||||
.shutdown = sci_shutdown,
|
||||
.flush_buffer = sci_flush_buffer,
|
||||
.set_termios = sci_set_termios,
|
||||
.pm = sci_pm,
|
||||
.type = sci_type,
|
||||
@ -2950,6 +2961,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
|
||||
|
||||
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
|
||||
|
||||
static DEFINE_MUTEX(sci_uart_registration_lock);
|
||||
static struct uart_driver sci_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "sci",
|
||||
@ -3078,6 +3090,16 @@ static int sci_probe_single(struct platform_device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&sci_uart_registration_lock);
|
||||
if (!sci_uart_driver.state) {
|
||||
ret = uart_register_driver(&sci_uart_driver);
|
||||
if (ret) {
|
||||
mutex_unlock(&sci_uart_registration_lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sci_uart_registration_lock);
|
||||
|
||||
ret = sci_init_single(dev, sciport, index, p, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -3201,24 +3223,17 @@ static struct platform_driver sci_driver = {
|
||||
|
||||
static int __init sci_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_info("%s\n", banner);
|
||||
|
||||
ret = uart_register_driver(&sci_uart_driver);
|
||||
if (likely(ret == 0)) {
|
||||
ret = platform_driver_register(&sci_driver);
|
||||
if (unlikely(ret))
|
||||
uart_unregister_driver(&sci_uart_driver);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return platform_driver_register(&sci_driver);
|
||||
}
|
||||
|
||||
static void __exit sci_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&sci_driver);
|
||||
uart_unregister_driver(&sci_uart_driver);
|
||||
|
||||
if (sci_uart_driver.state)
|
||||
uart_unregister_driver(&sci_uart_driver);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
|
||||
|
@ -1253,7 +1253,7 @@ next_hrt:
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
static struct of_device_id sirfsoc_uart_ids[] = {
|
||||
static const struct of_device_id sirfsoc_uart_ids[] = {
|
||||
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
|
||||
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
|
||||
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
|
||||
|
@ -186,6 +186,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
||||
* @pclk: APB clock
|
||||
* @baud: Current baud rate
|
||||
* @clk_rate_change_nb: Notifier block for clock changes
|
||||
* @quirks: Flags for RXBS support.
|
||||
*/
|
||||
struct cdns_uart {
|
||||
struct uart_port *port;
|
||||
@ -1587,20 +1588,21 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev,
|
||||
"uart_add_one_port() failed; err=%i\n", rc);
|
||||
goto err_out_notif_unreg;
|
||||
goto err_out_pm_disable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_pm_disable:
|
||||
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);
|
||||
#endif
|
||||
err_out_clk_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
clk_disable_unprepare(cdns_uart_data->uartclk);
|
||||
err_out_clk_dis_pclk:
|
||||
clk_disable_unprepare(cdns_uart_data->pclk);
|
||||
|
@ -491,6 +491,29 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
tty_ldisc_debug(tty, "%p: closed\n", ld);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_failto - helper for ldisc failback
|
||||
* @tty: tty to open the ldisc on
|
||||
* @ld: ldisc we are trying to fail back to
|
||||
*
|
||||
* Helper to try and recover a tty when switching back to the old
|
||||
* ldisc fails and we need something attached.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_failto(struct tty_struct *tty, int ld)
|
||||
{
|
||||
struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
|
||||
int r;
|
||||
|
||||
if (IS_ERR(disc))
|
||||
return PTR_ERR(disc);
|
||||
tty->ldisc = disc;
|
||||
tty_set_termios_ldisc(tty, ld);
|
||||
if ((r = tty_ldisc_open(tty, disc)) < 0)
|
||||
tty_ldisc_put(disc);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_restore - helper for tty ldisc change
|
||||
* @tty: tty to recover
|
||||
@ -502,9 +525,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
|
||||
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
{
|
||||
struct tty_ldisc *new_ldisc;
|
||||
int r;
|
||||
|
||||
/* There is an outstanding reference here so this is safe */
|
||||
old = tty_ldisc_get(tty, old->ops->num);
|
||||
WARN_ON(IS_ERR(old));
|
||||
@ -512,17 +532,13 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
tty_set_termios_ldisc(tty, old->ops->num);
|
||||
if (tty_ldisc_open(tty, old) < 0) {
|
||||
tty_ldisc_put(old);
|
||||
/* This driver is always present */
|
||||
new_ldisc = tty_ldisc_get(tty, N_TTY);
|
||||
if (IS_ERR(new_ldisc))
|
||||
panic("n_tty: get");
|
||||
tty->ldisc = new_ldisc;
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
r = tty_ldisc_open(tty, new_ldisc);
|
||||
if (r < 0)
|
||||
panic("Couldn't open N_TTY ldisc for "
|
||||
"%s --- error %d.",
|
||||
tty_name(tty), r);
|
||||
/* The traditional behaviour is to fall back to N_TTY, we
|
||||
want to avoid falling back to N_NULL unless we have no
|
||||
choice to avoid the risk of breaking anything */
|
||||
if (tty_ldisc_failto(tty, N_TTY) < 0 &&
|
||||
tty_ldisc_failto(tty, N_NULL) < 0)
|
||||
panic("Couldn't open N_NULL ldisc for %s.",
|
||||
tty_name(tty));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,15 +322,13 @@ int con_set_trans_old(unsigned char __user * arg)
|
||||
{
|
||||
int i;
|
||||
unsigned short inbuf[E_TABSZ];
|
||||
unsigned char ubuf[E_TABSZ];
|
||||
|
||||
if (!access_ok(VERIFY_READ, arg, E_TABSZ))
|
||||
if (copy_from_user(ubuf, arg, E_TABSZ))
|
||||
return -EFAULT;
|
||||
|
||||
for (i = 0; i < E_TABSZ ; i++) {
|
||||
unsigned char uc;
|
||||
__get_user(uc, arg+i);
|
||||
inbuf[i] = UNI_DIRECT_BASE | uc;
|
||||
}
|
||||
for (i = 0; i < E_TABSZ ; i++)
|
||||
inbuf[i] = UNI_DIRECT_BASE | ubuf[i];
|
||||
|
||||
console_lock();
|
||||
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
|
||||
@ -345,9 +343,6 @@ int con_get_trans_old(unsigned char __user * arg)
|
||||
unsigned short *p = translations[USER_MAP];
|
||||
unsigned char outbuf[E_TABSZ];
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
|
||||
return -EFAULT;
|
||||
|
||||
console_lock();
|
||||
for (i = 0; i < E_TABSZ ; i++)
|
||||
{
|
||||
@ -356,22 +351,16 @@ int con_get_trans_old(unsigned char __user * arg)
|
||||
}
|
||||
console_unlock();
|
||||
|
||||
for (i = 0; i < E_TABSZ ; i++)
|
||||
__put_user(outbuf[i], arg+i);
|
||||
return 0;
|
||||
return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
int con_set_trans_new(ushort __user * arg)
|
||||
{
|
||||
int i;
|
||||
unsigned short inbuf[E_TABSZ];
|
||||
|
||||
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
|
||||
if (copy_from_user(inbuf, arg, sizeof(inbuf)))
|
||||
return -EFAULT;
|
||||
|
||||
for (i = 0; i < E_TABSZ ; i++)
|
||||
__get_user(inbuf[i], arg+i);
|
||||
|
||||
console_lock();
|
||||
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
|
||||
update_user_maps();
|
||||
@ -381,19 +370,13 @@ int con_set_trans_new(ushort __user * arg)
|
||||
|
||||
int con_get_trans_new(ushort __user * arg)
|
||||
{
|
||||
int i;
|
||||
unsigned short outbuf[E_TABSZ];
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
|
||||
return -EFAULT;
|
||||
|
||||
console_lock();
|
||||
memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
|
||||
console_unlock();
|
||||
|
||||
for (i = 0; i < E_TABSZ ; i++)
|
||||
__put_user(outbuf[i], arg+i);
|
||||
return 0;
|
||||
return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -557,14 +540,9 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
if (!ct)
|
||||
return 0;
|
||||
|
||||
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
||||
if (!unilist)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = ct, plist = unilist; i; i--, plist++, list++) {
|
||||
__get_user(plist->unicode, &list->unicode);
|
||||
__get_user(plist->fontpos, &list->fontpos);
|
||||
}
|
||||
unilist = memdup_user(list, ct * sizeof(struct unipair));
|
||||
if (IS_ERR(unilist))
|
||||
return PTR_ERR(unilist);
|
||||
|
||||
console_lock();
|
||||
|
||||
@ -757,11 +735,11 @@ EXPORT_SYMBOL(con_copy_unimap);
|
||||
*/
|
||||
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
|
||||
{
|
||||
int i, j, k;
|
||||
int i, j, k, ret = 0;
|
||||
ushort ect;
|
||||
u16 **p1, *p2;
|
||||
struct uni_pagedir *p;
|
||||
struct unipair *unilist, *plist;
|
||||
struct unipair *unilist;
|
||||
|
||||
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
||||
if (!unilist)
|
||||
@ -792,13 +770,11 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
||||
}
|
||||
}
|
||||
console_unlock();
|
||||
for (i = min(ect, ct), plist = unilist; i; i--, list++, plist++) {
|
||||
__put_user(plist->unicode, &list->unicode);
|
||||
__put_user(plist->fontpos, &list->fontpos);
|
||||
}
|
||||
__put_user(ect, uct);
|
||||
if (copy_to_user(list, unilist, min(ect, ct) * sizeof(struct unipair)))
|
||||
ret = -EFAULT;
|
||||
put_user(ect, uct);
|
||||
kfree(unilist);
|
||||
return ((ect <= ct) ? 0 : -ENOMEM);
|
||||
return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1203,8 +1203,7 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
|
||||
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
|
||||
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
|
||||
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
|
||||
(defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
|
||||
defined(CONFIG_AVR32)
|
||||
(defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
|
||||
|
||||
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
|
||||
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
|
||||
|
@ -425,7 +425,7 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
|
||||
else if (_underline)
|
||||
a = (a & 0xf0) | vc->vc_ulcolor;
|
||||
else if (_intensity == 0)
|
||||
a = (a & 0xf0) | vc->vc_ulcolor;
|
||||
a = (a & 0xf0) | vc->vc_halfcolor;
|
||||
if (_reverse)
|
||||
a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
|
||||
if (_blink)
|
||||
@ -2709,13 +2709,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
|
||||
* related to the kernel should not use this.
|
||||
*/
|
||||
data = vt_get_shift_state();
|
||||
ret = __put_user(data, p);
|
||||
ret = put_user(data, p);
|
||||
break;
|
||||
case TIOCL_GETMOUSEREPORTING:
|
||||
console_lock(); /* May be overkill */
|
||||
data = mouse_reporting();
|
||||
console_unlock();
|
||||
ret = __put_user(data, p);
|
||||
ret = put_user(data, p);
|
||||
break;
|
||||
case TIOCL_SETVESABLANK:
|
||||
console_lock();
|
||||
@ -2724,7 +2724,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
|
||||
break;
|
||||
case TIOCL_GETKMSGREDIRECT:
|
||||
data = vt_get_kmsg_redirect();
|
||||
ret = __put_user(data, p);
|
||||
ret = put_user(data, p);
|
||||
break;
|
||||
case TIOCL_SETKMSGREDIRECT:
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
|
@ -266,10 +266,6 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
|
||||
|
||||
if (copy_from_user(&tmp, user_ud, sizeof tmp))
|
||||
return -EFAULT;
|
||||
if (tmp.entries)
|
||||
if (!access_ok(VERIFY_WRITE, tmp.entries,
|
||||
tmp.entry_ct*sizeof(struct unipair)))
|
||||
return -EFAULT;
|
||||
switch (cmd) {
|
||||
case PIO_UNIMAP:
|
||||
if (!perm)
|
||||
@ -1170,10 +1166,6 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
|
||||
if (copy_from_user(&tmp, user_ud, sizeof tmp))
|
||||
return -EFAULT;
|
||||
tmp_entries = compat_ptr(tmp.entries);
|
||||
if (tmp_entries)
|
||||
if (!access_ok(VERIFY_WRITE, tmp_entries,
|
||||
tmp.entry_ct*sizeof(struct unipair)))
|
||||
return -EFAULT;
|
||||
switch (cmd) {
|
||||
case PIO_UNIMAP:
|
||||
if (!perm)
|
||||
|
@ -1244,42 +1244,13 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
|
||||
int div_okay = 1;
|
||||
int baud;
|
||||
|
||||
/*
|
||||
* The logic involved in setting the baudrate can be cleanly split into
|
||||
* 3 steps.
|
||||
* 1. Standard baud rates are set in tty->termios->c_cflag
|
||||
* 2. If these are not enough, you can set any speed using alt_speed as
|
||||
* follows:
|
||||
* - set tty->termios->c_cflag speed to B38400
|
||||
* - set your real speed in tty->alt_speed; it gets ignored when
|
||||
* alt_speed==0, (or)
|
||||
* - call TIOCSSERIAL ioctl with (struct serial_struct) set as
|
||||
* follows:
|
||||
* flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP],
|
||||
* this just sets alt_speed to (HI: 57600, VHI: 115200,
|
||||
* SHI: 230400, WARP: 460800)
|
||||
* ** Steps 1, 2 are done courtesy of tty_get_baud_rate
|
||||
* 3. You can also set baud rate by setting custom divisor as follows
|
||||
* - set tty->termios->c_cflag speed to B38400
|
||||
* - call TIOCSSERIAL ioctl with (struct serial_struct) set as
|
||||
* follows:
|
||||
* o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
|
||||
* o custom_divisor set to baud_base / your_new_baudrate
|
||||
* ** Step 3 is done courtesy of code borrowed from serial.c
|
||||
* I should really spend some time and separate + move this common
|
||||
* code to serial.c, it is replicated in nearly every serial driver
|
||||
* you see.
|
||||
*/
|
||||
|
||||
/* 1. Get the baud rate from the tty settings, this observes
|
||||
alt_speed hack */
|
||||
|
||||
baud = tty_get_baud_rate(tty);
|
||||
dev_dbg(dev, "%s - tty_get_baud_rate reports speed %d\n", __func__, baud);
|
||||
|
||||
/* 2. Observe async-compatible custom_divisor hack, update baudrate
|
||||
if needed */
|
||||
|
||||
/*
|
||||
* Observe deprecated async-compatible custom_divisor hack, update
|
||||
* baudrate if needed.
|
||||
*/
|
||||
if (baud == 38400 &&
|
||||
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
|
||||
(priv->custom_divisor)) {
|
||||
@ -1288,8 +1259,6 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
|
||||
__func__, priv->custom_divisor, baud);
|
||||
}
|
||||
|
||||
/* 3. Convert baudrate to device-specific divisor */
|
||||
|
||||
if (!baud)
|
||||
baud = 9600;
|
||||
switch (priv->chip_type) {
|
||||
@ -1505,8 +1474,7 @@ static int set_serial_info(struct tty_struct *tty,
|
||||
/* Do error checking and permission checking */
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
|
||||
(priv->flags & ~ASYNC_USR_MASK))) {
|
||||
if ((new_serial.flags ^ priv->flags) & ~ASYNC_USR_MASK) {
|
||||
mutex_unlock(&priv->cfg_lock);
|
||||
return -EPERM;
|
||||
}
|
||||
@ -1530,23 +1498,14 @@ static int set_serial_info(struct tty_struct *tty,
|
||||
check_and_exit:
|
||||
write_latency_timer(port);
|
||||
|
||||
if ((old_priv.flags & ASYNC_SPD_MASK) !=
|
||||
(priv->flags & ASYNC_SPD_MASK)) {
|
||||
if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
tty->alt_speed = 115200;
|
||||
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
tty->alt_speed = 230400;
|
||||
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
tty->alt_speed = 460800;
|
||||
else
|
||||
tty->alt_speed = 0;
|
||||
}
|
||||
if (((old_priv.flags & ASYNC_SPD_MASK) !=
|
||||
(priv->flags & ASYNC_SPD_MASK)) ||
|
||||
(((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
|
||||
(old_priv.custom_divisor != priv->custom_divisor))) {
|
||||
if ((priv->flags ^ old_priv.flags) & ASYNC_SPD_MASK ||
|
||||
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
||||
priv->custom_divisor != old_priv.custom_divisor)) {
|
||||
|
||||
/* warn about deprecation unless clearing */
|
||||
if (priv->flags & ASYNC_SPD_MASK)
|
||||
dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n");
|
||||
|
||||
change_speed(tty, port);
|
||||
mutex_unlock(&priv->cfg_lock);
|
||||
}
|
||||
|
@ -866,8 +866,6 @@ COMPATIBLE_IOCTL(TIOCGDEV)
|
||||
COMPATIBLE_IOCTL(TIOCCBRK)
|
||||
COMPATIBLE_IOCTL(TIOCGSID)
|
||||
COMPATIBLE_IOCTL(TIOCGICOUNT)
|
||||
COMPATIBLE_IOCTL(TIOCGPKT)
|
||||
COMPATIBLE_IOCTL(TIOCGPTLCK)
|
||||
COMPATIBLE_IOCTL(TIOCGEXCL)
|
||||
/* Little t */
|
||||
COMPATIBLE_IOCTL(TIOCGETD)
|
||||
@ -883,16 +881,12 @@ COMPATIBLE_IOCTL(TIOCMGET)
|
||||
COMPATIBLE_IOCTL(TIOCMBIC)
|
||||
COMPATIBLE_IOCTL(TIOCMBIS)
|
||||
COMPATIBLE_IOCTL(TIOCMSET)
|
||||
COMPATIBLE_IOCTL(TIOCPKT)
|
||||
COMPATIBLE_IOCTL(TIOCNOTTY)
|
||||
COMPATIBLE_IOCTL(TIOCSTI)
|
||||
COMPATIBLE_IOCTL(TIOCOUTQ)
|
||||
COMPATIBLE_IOCTL(TIOCSPGRP)
|
||||
COMPATIBLE_IOCTL(TIOCGPGRP)
|
||||
COMPATIBLE_IOCTL(TIOCGPTN)
|
||||
COMPATIBLE_IOCTL(TIOCSPTLCK)
|
||||
COMPATIBLE_IOCTL(TIOCSERGETLSR)
|
||||
COMPATIBLE_IOCTL(TIOCSIG)
|
||||
#ifdef TIOCSRS485
|
||||
COMPATIBLE_IOCTL(TIOCSRS485)
|
||||
#endif
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/serial.h>
|
||||
|
||||
/* Compact Flash */
|
||||
struct at91_cf_data {
|
||||
@ -42,15 +41,6 @@ struct atmel_nand_data {
|
||||
bool need_reset_workaround;
|
||||
};
|
||||
|
||||
/* Serial */
|
||||
struct atmel_uart_data {
|
||||
int num; /* port num */
|
||||
short use_dma_tx; /* use transmit DMA? */
|
||||
short use_dma_rx; /* use receive DMA? */
|
||||
void __iomem *regs; /* virt. base address, if any */
|
||||
struct serial_rs485 rs485; /* rs485 settings */
|
||||
};
|
||||
|
||||
/* FIXME: this needs a better location, but gets stuff building again */
|
||||
extern int at91_suspend_entering_slow_clock(void);
|
||||
|
||||
|
@ -195,6 +195,7 @@ struct uart_port {
|
||||
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
|
||||
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
|
||||
|
||||
#define UPF_NO_THRE_TEST ((__force upf_t) (1 << 19))
|
||||
/* Port has hardware-assisted h/w flow control */
|
||||
#define UPF_AUTO_CTS ((__force upf_t) (1 << 20))
|
||||
#define UPF_AUTO_RTS ((__force upf_t) (1 << 21))
|
||||
|
@ -316,7 +316,6 @@ struct tty_struct {
|
||||
|
||||
struct tty_struct *link;
|
||||
struct fasync_struct *fasync;
|
||||
int alt_speed; /* For magic substitution of 38400 bps */
|
||||
wait_queue_head_t write_wait;
|
||||
wait_queue_head_t read_wait;
|
||||
struct work_struct hangup_work;
|
||||
|
@ -77,6 +77,7 @@
|
||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||
|
||||
#define FIONCLEX 0x5450
|
||||
#define FIOCLEX 0x5451
|
||||
|
@ -122,6 +122,9 @@ struct serial_rs485 {
|
||||
#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for
|
||||
RTS pin after sent*/
|
||||
#define SER_RS485_RX_DURING_TX (1 << 4)
|
||||
#define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus
|
||||
termination
|
||||
(if supported) */
|
||||
__u32 delay_rts_before_send; /* Delay before send (milliseconds) */
|
||||
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
|
||||
__u32 padding[5]; /* Memory is cheap, new structs
|
||||
|
@ -83,7 +83,7 @@
|
||||
/* Parisc type numbers. */
|
||||
#define PORT_MUX 48
|
||||
|
||||
/* Atmel AT91 / AT32 SoC */
|
||||
/* Atmel AT91 SoC */
|
||||
#define PORT_ATMEL 49
|
||||
|
||||
/* Macintosh Zilog type numbers */
|
||||
|
@ -36,5 +36,6 @@
|
||||
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
|
||||
#define N_NCI 25 /* NFC NCI UART */
|
||||
#define N_SPEAKUP 26 /* Speakup communication with synths */
|
||||
#define N_NULL 27 /* Null ldisc used for error handling */
|
||||
|
||||
#endif /* _UAPI_LINUX_TTY_H */
|
||||
|
@ -97,33 +97,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
|
||||
self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
|
||||
}
|
||||
tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL);
|
||||
#if 0
|
||||
/*
|
||||
* Set up parity check flag
|
||||
*/
|
||||
|
||||
if (I_INPCK(self->tty))
|
||||
driver->read_status_mask |= LSR_FE | LSR_PE;
|
||||
if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty))
|
||||
driver->read_status_mask |= LSR_BI;
|
||||
|
||||
/*
|
||||
* Characters to ignore
|
||||
*/
|
||||
driver->ignore_status_mask = 0;
|
||||
if (I_IGNPAR(driver->tty))
|
||||
driver->ignore_status_mask |= LSR_PE | LSR_FE;
|
||||
|
||||
if (I_IGNBRK(self->tty)) {
|
||||
self->ignore_status_mask |= LSR_BI;
|
||||
/*
|
||||
* If we're ignore parity and break indicators, ignore
|
||||
* overruns too. (For real raw support).
|
||||
*/
|
||||
if (I_IGNPAR(self->tty))
|
||||
self->ignore_status_mask |= LSR_OE;
|
||||
}
|
||||
#endif
|
||||
self->settings.data_format = cval;
|
||||
|
||||
ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
|
||||
@ -271,67 +245,6 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
|
||||
static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
|
||||
struct serial_struct __user *new_info)
|
||||
{
|
||||
#if 0
|
||||
struct serial_struct new_serial;
|
||||
struct ircomm_tty_cb old_state, *state;
|
||||
|
||||
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
|
||||
return -EFAULT;
|
||||
|
||||
|
||||
state = self
|
||||
old_state = *self;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if ((new_serial.baud_base != state->settings.data_rate) ||
|
||||
(new_serial.close_delay != state->close_delay) ||
|
||||
((new_serial.flags & ~ASYNC_USR_MASK) !=
|
||||
(self->flags & ~ASYNC_USR_MASK)))
|
||||
return -EPERM;
|
||||
state->flags = ((state->flags & ~ASYNC_USR_MASK) |
|
||||
(new_serial.flags & ASYNC_USR_MASK));
|
||||
self->flags = ((self->flags & ~ASYNC_USR_MASK) |
|
||||
(new_serial.flags & ASYNC_USR_MASK));
|
||||
/* self->custom_divisor = new_serial.custom_divisor; */
|
||||
goto check_and_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, past this point, all the error checking has been done.
|
||||
* At this point, we start making changes.....
|
||||
*/
|
||||
|
||||
if (self->settings.data_rate != new_serial.baud_base) {
|
||||
self->settings.data_rate = new_serial.baud_base;
|
||||
ircomm_param_request(self, IRCOMM_DATA_RATE, TRUE);
|
||||
}
|
||||
|
||||
self->close_delay = new_serial.close_delay * HZ/100;
|
||||
self->closing_wait = new_serial.closing_wait * HZ/100;
|
||||
/* self->custom_divisor = new_serial.custom_divisor; */
|
||||
|
||||
self->flags = ((self->flags & ~ASYNC_FLAGS) |
|
||||
(new_serial.flags & ASYNC_FLAGS));
|
||||
self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
|
||||
if (tty_port_initialized(self)) {
|
||||
if (((old_state.flags & ASYNC_SPD_MASK) !=
|
||||
(self->flags & ASYNC_SPD_MASK)) ||
|
||||
(old_driver.custom_divisor != driver->custom_divisor)) {
|
||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
driver->tty->alt_speed = 57600;
|
||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
||||
driver->tty->alt_speed = 115200;
|
||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
||||
driver->tty->alt_speed = 230400;
|
||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
||||
driver->tty->alt_speed = 460800;
|
||||
ircomm_tty_change_speed(driver);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -367,24 +280,6 @@ int ircomm_tty_ioctl(struct tty_struct *tty,
|
||||
|
||||
case TIOCGICOUNT:
|
||||
pr_debug("%s(), TIOCGICOUNT not impl!\n", __func__);
|
||||
#if 0
|
||||
save_flags(flags); cli();
|
||||
cnow = driver->icount;
|
||||
restore_flags(flags);
|
||||
p_cuser = (struct serial_icounter_struct __user *) arg;
|
||||
if (put_user(cnow.cts, &p_cuser->cts) ||
|
||||
put_user(cnow.dsr, &p_cuser->dsr) ||
|
||||
put_user(cnow.rng, &p_cuser->rng) ||
|
||||
put_user(cnow.dcd, &p_cuser->dcd) ||
|
||||
put_user(cnow.rx, &p_cuser->rx) ||
|
||||
put_user(cnow.tx, &p_cuser->tx) ||
|
||||
put_user(cnow.frame, &p_cuser->frame) ||
|
||||
put_user(cnow.overrun, &p_cuser->overrun) ||
|
||||
put_user(cnow.parity, &p_cuser->parity) ||
|
||||
put_user(cnow.brk, &p_cuser->brk) ||
|
||||
put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
|
||||
return -EFAULT;
|
||||
#endif
|
||||
return 0;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD; /* ioctls which we must ignore */
|
||||
|
Loading…
Reference in New Issue
Block a user