TTY/Serial driver changes for 5.18-rc1
Here are the big set of tty and serial driver changes for 5.18-rc1. Nothing major, some more good cleanups from Jiri and 2 new serial drivers. Highlights include: - termbits cleanups - export symbol cleanups and other core cleanups from Jiri Slaby - new sunplus and mvebu uart drivers (amazing that people are still creating new uarts...) - samsung serial driver cleanups - ldisc 29 is now "reserved" for experimental/development line disciplines - lots of other tiny fixes and cleanups to serial drivers and bindings All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYkGznQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymnFwCgwGD/syV+BH2krgY6cRixZz72vPsAn2RSnicd 2YUwSNCHoL+B7hvQMtDG =A3X9 -----END PGP SIGNATURE----- Merge tag 'tty-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver updates from Greg KH: "Here are the big set of tty and serial driver changes for 5.18-rc1. Nothing major, some more good cleanups from Jiri and 2 new serial drivers. Highlights include: - termbits cleanups - export symbol cleanups and other core cleanups from Jiri Slaby - new sunplus and mvebu uart drivers (amazing that people are still creating new uarts...) - samsung serial driver cleanups - ldisc 29 is now "reserved" for experimental/development line disciplines - lots of other tiny fixes and cleanups to serial drivers and bindings All of these have been in linux-next for a while with no reported issues" * tag 'tty-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (104 commits) vt_ioctl: fix potential spectre v1 in VT_DISALLOCATE serial: 8250: fix XOFF/XON sending when DMA is used tty: serial: samsung: Add ARTPEC-8 support dt-bindings: serial: samsung: Add ARTPEC-8 UART serial: sc16is7xx: Clear RS485 bits in the shutdown tty: serial: samsung: simplify getting OF match data tty: serial: samsung: constify variables and pointers tty: serial: samsung: constify s3c24xx_serial_drv_data members tty: serial: samsung: constify UART name tty: serial: samsung: constify s3c24xx_serial_drv_data tty: serial: samsung: reduce number of casts tty: serial: samsung: embed s3c2410_uartcfg in parent structure tty: serial: samsung: embed s3c24xx_uart_info in parent structure serial: 8250_tegra: mark acpi_device_id as unused with !ACPI tty: serial: bcm63xx: use more precise Kconfig symbol serial: SERIAL_SUNPLUS should depend on ARCH_SUNPLUS tty: serial: jsm: fix two assignments in if conditions tty: serial: jsm: remove redundant assignments to variable linestatus serial: 8250_mtk: make two read-only arrays static const serial: samsung_tty: do not unlock port->lock for uart_write_wakeup() ...
This commit is contained in:
commit
7203062171
|
@ -0,0 +1,59 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/marvell,armada-3700-uart-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Marvell Armada 3720 UART clocks
|
||||
|
||||
maintainers:
|
||||
- Pali Rohár <pali@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: marvell,armada-3700-uart-clock
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: UART Clock Control Register
|
||||
- description: UART 2 Baud Rate Divisor Register
|
||||
|
||||
clocks:
|
||||
description: |
|
||||
List of parent clocks suitable for UART from following set:
|
||||
"TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal"
|
||||
UART clock can use one from this set and when more are provided
|
||||
then kernel would choose and configure the most suitable one.
|
||||
It is suggest to specify at least one TBG clock to achieve
|
||||
baudrates above 230400 and also to specify clock which bootloader
|
||||
used for UART (most probably xtal) for smooth boot log on UART.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: TBG-A-P
|
||||
- const: TBG-B-P
|
||||
- const: TBG-A-S
|
||||
- const: TBG-B-S
|
||||
- const: xtal
|
||||
minItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
uartclk: clock-controller@12010 {
|
||||
compatible = "marvell,armada-3700-uart-clock";
|
||||
reg = <0x12010 0x4>, <0x12210 0x4>;
|
||||
clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, <&tbg 3>, <&xtalclk>;
|
||||
clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S", "TBG-B-S", "xtal";
|
||||
#clock-cells = <1>;
|
||||
};
|
|
@ -20,15 +20,15 @@ properties:
|
|||
- fsl,ls1021a-lpuart
|
||||
- fsl,ls1028a-lpuart
|
||||
- fsl,imx7ulp-lpuart
|
||||
- fsl,imx8qm-lpuart
|
||||
- fsl,imx8qxp-lpuart
|
||||
- fsl,imxrt1050-lpuart
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx8qxp-lpuart
|
||||
- fsl,imx8ulp-lpuart
|
||||
- const: fsl,imx8ulp-lpuart
|
||||
- const: fsl,imx7ulp-lpuart
|
||||
- items:
|
||||
- const: fsl,imx8qm-lpuart
|
||||
- enum:
|
||||
- fsl,imx8qm-lpuart
|
||||
- fsl,imx8dxl-lpuart
|
||||
- const: fsl,imx8qxp-lpuart
|
||||
|
||||
reg:
|
||||
|
|
|
@ -20,6 +20,7 @@ Required properties:
|
|||
* "mediatek,mt8135-uart" for MT8135 compatible UARTS
|
||||
* "mediatek,mt8173-uart" for MT8173 compatible UARTS
|
||||
* "mediatek,mt8183-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS
|
||||
* "mediatek,mt8186-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS
|
||||
* "mediatek,mt8192-uart", "mediatek,mt6577-uart" for MT8192 compatible UARTS
|
||||
* "mediatek,mt8195-uart", "mediatek,mt6577-uart" for MT8195 compatible UARTS
|
||||
* "mediatek,mt8516-uart" for MT8516 compatible UARTS
|
||||
|
|
|
@ -14,7 +14,10 @@ Required properties:
|
|||
is provided (possible only with the "marvell,armada-3700-uart"
|
||||
compatible string for backward compatibility), it will only work
|
||||
if the baudrate was initialized by the bootloader and no baudrate
|
||||
change will then be possible.
|
||||
change will then be possible. When provided it should be UART1-clk
|
||||
for standard variant of UART and UART2-clk for extended variant
|
||||
of UART. TBG clock (with UART TBG divisors d1=d2=1) or xtal clock
|
||||
should not be used and are supported only for backward compatibility.
|
||||
- interrupts:
|
||||
- Must contain three elements for the standard variant of the IP
|
||||
(marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx",
|
||||
|
@ -34,7 +37,7 @@ Example:
|
|||
uart0: serial@12000 {
|
||||
compatible = "marvell,armada-3700-uart";
|
||||
reg = <0x12000 0x18>;
|
||||
clocks = <&xtalclk>;
|
||||
clocks = <&uartclk 0>;
|
||||
interrupts =
|
||||
<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
@ -45,7 +48,7 @@ Example:
|
|||
uart1: serial@12200 {
|
||||
compatible = "marvell,armada-3700-uart-ext";
|
||||
reg = <0x12200 0x30>;
|
||||
clocks = <&xtalclk>;
|
||||
clocks = <&uartclk 1>;
|
||||
interrupts =
|
||||
<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
|
||||
|
|
|
@ -17,6 +17,7 @@ properties:
|
|||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r9a07g043-sci # RZ/G2UL
|
||||
- renesas,r9a07g044-sci # RZ/G2{L,LC}
|
||||
- renesas,r9a07g054-sci # RZ/V2L
|
||||
- const: renesas,sci # generic SCI compatible UART
|
||||
|
@ -67,6 +68,7 @@ if:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,r9a07g043-sci
|
||||
- renesas,r9a07g044-sci
|
||||
- renesas,r9a07g054-sci
|
||||
then:
|
||||
|
|
|
@ -73,12 +73,12 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r9a07g044 # RZ/G2{L,LC}
|
||||
- renesas,scif-r9a07g054 # RZ/V2L
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r9a07g043 # RZ/G2UL
|
||||
- renesas,scif-r9a07g054 # RZ/V2L
|
||||
- const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback for RZ/V2L
|
||||
- const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -167,7 +167,6 @@ if:
|
|||
- renesas,rcar-gen3-scif
|
||||
- renesas,rcar-gen4-scif
|
||||
- renesas,scif-r9a07g044
|
||||
- renesas,scif-r9a07g054
|
||||
then:
|
||||
required:
|
||||
- resets
|
||||
|
|
|
@ -20,12 +20,14 @@ properties:
|
|||
items:
|
||||
- enum:
|
||||
- apple,s5l-uart
|
||||
- axis,artpec8-uart
|
||||
- samsung,s3c2410-uart
|
||||
- samsung,s3c2412-uart
|
||||
- samsung,s3c2440-uart
|
||||
- samsung,s3c6400-uart
|
||||
- samsung,s5pv210-uart
|
||||
- samsung,exynos4210-uart
|
||||
- samsung,exynos5433-uart
|
||||
- samsung,exynos850-uart
|
||||
|
||||
reg:
|
||||
|
@ -110,7 +112,9 @@ allOf:
|
|||
contains:
|
||||
enum:
|
||||
- apple,s5l-uart
|
||||
- axis,artpec8-uart
|
||||
- samsung,exynos4210-uart
|
||||
- samsung,exynos5433-uart
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) Sunplus Co., Ltd. 2021
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/serial/sunplus,sp7021-uart.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Sunplus SoC SP7021 UART Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Hammer Hsieh <hammerh0314@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sunplus,sp7021-uart
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- resets
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
aliases {
|
||||
serial0 = &uart0;
|
||||
};
|
||||
|
||||
uart0: serial@9c000900 {
|
||||
compatible = "sunplus,sp7021-uart";
|
||||
reg = <0x9c000900 0x80>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clkc 0x28>;
|
||||
resets = <&rstc 0x18>;
|
||||
};
|
||||
...
|
13
MAINTAINERS
13
MAINTAINERS
|
@ -11665,6 +11665,13 @@ F: Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml
|
|||
F: drivers/phy/marvell/phy-mvebu-a3700-comphy.c
|
||||
F: drivers/phy/marvell/phy-mvebu-a3700-utmi.c
|
||||
|
||||
MARVELL ARMADA 3700 SERIAL DRIVER
|
||||
M: Pali Rohár <pali@kernel.org>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/clock/marvell,armada-3700-uart-clock.yaml
|
||||
F: Documentation/devicetree/bindings/serial/mvebu-uart.txt
|
||||
F: drivers/tty/serial/mvebu-uart.c
|
||||
|
||||
MARVELL ARMADA DRM SUPPORT
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
S: Maintained
|
||||
|
@ -18853,6 +18860,12 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
|
||||
F: drivers/spi/spi-sunplus-sp7021.c
|
||||
|
||||
SUNPLUS UART DRIVER
|
||||
M: Hammer Hsieh <hammerh0314@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
|
||||
F: drivers/tty/serial/sunplus-uart.c
|
||||
|
||||
SUPERH
|
||||
M: Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
M: Rich Felker <dalias@libc.org>
|
||||
|
|
|
@ -132,10 +132,20 @@
|
|||
reg = <0x11500 0x40>;
|
||||
};
|
||||
|
||||
uartclk: clock-controller@12010 {
|
||||
compatible = "marvell,armada-3700-uart-clock";
|
||||
reg = <0x12010 0x4>, <0x12210 0x4>;
|
||||
clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>,
|
||||
<&tbg 3>, <&xtalclk>;
|
||||
clock-names = "TBG-A-P", "TBG-B-P", "TBG-A-S",
|
||||
"TBG-B-S", "xtal";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
uart0: serial@12000 {
|
||||
compatible = "marvell,armada-3700-uart";
|
||||
reg = <0x12000 0x18>;
|
||||
clocks = <&xtalclk>;
|
||||
clocks = <&uartclk 0>;
|
||||
interrupts =
|
||||
<GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>,
|
||||
|
@ -147,7 +157,7 @@
|
|||
uart1: serial@12200 {
|
||||
compatible = "marvell,armada-3700-uart-ext";
|
||||
reg = <0x12200 0x30>;
|
||||
clocks = <&xtalclk>;
|
||||
clocks = <&uartclk 1>;
|
||||
interrupts =
|
||||
<GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>;
|
||||
|
|
|
@ -1,209 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _ASM_IA64_TERMBITS_H
|
||||
#define _ASM_IA64_TERMBITS_H
|
||||
|
||||
/*
|
||||
* Based on <asm-i386/termbits.h>.
|
||||
*
|
||||
* Modified 1999
|
||||
* David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
|
||||
*
|
||||
* 99/01/28 Added new baudrates
|
||||
*/
|
||||
|
||||
#include <linux/posix_types.h>
|
||||
|
||||
typedef unsigned char cc_t;
|
||||
typedef unsigned int speed_t;
|
||||
typedef unsigned int tcflag_t;
|
||||
|
||||
#define NCCS 19
|
||||
struct termios {
|
||||
tcflag_t c_iflag; /* input mode flags */
|
||||
tcflag_t c_oflag; /* output mode flags */
|
||||
tcflag_t c_cflag; /* control mode flags */
|
||||
tcflag_t c_lflag; /* local mode flags */
|
||||
cc_t c_line; /* line discipline */
|
||||
cc_t c_cc[NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
struct termios2 {
|
||||
tcflag_t c_iflag; /* input mode flags */
|
||||
tcflag_t c_oflag; /* output mode flags */
|
||||
tcflag_t c_cflag; /* control mode flags */
|
||||
tcflag_t c_lflag; /* local mode flags */
|
||||
cc_t c_line; /* line discipline */
|
||||
cc_t c_cc[NCCS]; /* control characters */
|
||||
speed_t c_ispeed; /* input speed */
|
||||
speed_t c_ospeed; /* output speed */
|
||||
};
|
||||
|
||||
struct ktermios {
|
||||
tcflag_t c_iflag; /* input mode flags */
|
||||
tcflag_t c_oflag; /* output mode flags */
|
||||
tcflag_t c_cflag; /* control mode flags */
|
||||
tcflag_t c_lflag; /* local mode flags */
|
||||
cc_t c_line; /* line discipline */
|
||||
cc_t c_cc[NCCS]; /* control characters */
|
||||
speed_t c_ispeed; /* input speed */
|
||||
speed_t c_ospeed; /* output speed */
|
||||
};
|
||||
|
||||
/* c_cc characters */
|
||||
#define VINTR 0
|
||||
#define VQUIT 1
|
||||
#define VERASE 2
|
||||
#define VKILL 3
|
||||
#define VEOF 4
|
||||
#define VTIME 5
|
||||
#define VMIN 6
|
||||
#define VSWTC 7
|
||||
#define VSTART 8
|
||||
#define VSTOP 9
|
||||
#define VSUSP 10
|
||||
#define VEOL 11
|
||||
#define VREPRINT 12
|
||||
#define VDISCARD 13
|
||||
#define VWERASE 14
|
||||
#define VLNEXT 15
|
||||
#define VEOL2 16
|
||||
|
||||
/* c_iflag bits */
|
||||
#define IGNBRK 0000001
|
||||
#define BRKINT 0000002
|
||||
#define IGNPAR 0000004
|
||||
#define PARMRK 0000010
|
||||
#define INPCK 0000020
|
||||
#define ISTRIP 0000040
|
||||
#define INLCR 0000100
|
||||
#define IGNCR 0000200
|
||||
#define ICRNL 0000400
|
||||
#define IUCLC 0001000
|
||||
#define IXON 0002000
|
||||
#define IXANY 0004000
|
||||
#define IXOFF 0010000
|
||||
#define IMAXBEL 0020000
|
||||
#define IUTF8 0040000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define OPOST 0000001
|
||||
#define OLCUC 0000002
|
||||
#define ONLCR 0000004
|
||||
#define OCRNL 0000010
|
||||
#define ONOCR 0000020
|
||||
#define ONLRET 0000040
|
||||
#define OFILL 0000100
|
||||
#define OFDEL 0000200
|
||||
#define NLDLY 0000400
|
||||
#define NL0 0000000
|
||||
#define NL1 0000400
|
||||
#define CRDLY 0003000
|
||||
#define CR0 0000000
|
||||
#define CR1 0001000
|
||||
#define CR2 0002000
|
||||
#define CR3 0003000
|
||||
#define TABDLY 0014000
|
||||
#define TAB0 0000000
|
||||
#define TAB1 0004000
|
||||
#define TAB2 0010000
|
||||
#define TAB3 0014000
|
||||
#define XTABS 0014000
|
||||
#define BSDLY 0020000
|
||||
#define BS0 0000000
|
||||
#define BS1 0020000
|
||||
#define VTDLY 0040000
|
||||
#define VT0 0000000
|
||||
#define VT1 0040000
|
||||
#define FFDLY 0100000
|
||||
#define FF0 0000000
|
||||
#define FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#define CBAUD 0010017
|
||||
#define B0 0000000 /* hang up */
|
||||
#define B50 0000001
|
||||
#define B75 0000002
|
||||
#define B110 0000003
|
||||
#define B134 0000004
|
||||
#define B150 0000005
|
||||
#define B200 0000006
|
||||
#define B300 0000007
|
||||
#define B600 0000010
|
||||
#define B1200 0000011
|
||||
#define B1800 0000012
|
||||
#define B2400 0000013
|
||||
#define B4800 0000014
|
||||
#define B9600 0000015
|
||||
#define B19200 0000016
|
||||
#define B38400 0000017
|
||||
#define EXTA B19200
|
||||
#define EXTB B38400
|
||||
#define CSIZE 0000060
|
||||
#define CS5 0000000
|
||||
#define CS6 0000020
|
||||
#define CS7 0000040
|
||||
#define CS8 0000060
|
||||
#define CSTOPB 0000100
|
||||
#define CREAD 0000200
|
||||
#define PARENB 0000400
|
||||
#define PARODD 0001000
|
||||
#define HUPCL 0002000
|
||||
#define CLOCAL 0004000
|
||||
#define CBAUDEX 0010000
|
||||
#define BOTHER 0010000
|
||||
#define B57600 0010001
|
||||
#define B115200 0010002
|
||||
#define B230400 0010003
|
||||
#define B460800 0010004
|
||||
#define B500000 0010005
|
||||
#define B576000 0010006
|
||||
#define B921600 0010007
|
||||
#define B1000000 0010010
|
||||
#define B1152000 0010011
|
||||
#define B1500000 0010012
|
||||
#define B2000000 0010013
|
||||
#define B2500000 0010014
|
||||
#define B3000000 0010015
|
||||
#define B3500000 0010016
|
||||
#define B4000000 0010017
|
||||
#define CIBAUD 002003600000 /* input baud rate */
|
||||
#define CMSPAR 010000000000 /* mark or space (stick) parity */
|
||||
#define CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
|
||||
|
||||
/* c_lflag bits */
|
||||
#define ISIG 0000001
|
||||
#define ICANON 0000002
|
||||
#define XCASE 0000004
|
||||
#define ECHO 0000010
|
||||
#define ECHOE 0000020
|
||||
#define ECHOK 0000040
|
||||
#define ECHONL 0000100
|
||||
#define NOFLSH 0000200
|
||||
#define TOSTOP 0000400
|
||||
#define ECHOCTL 0001000
|
||||
#define ECHOPRT 0002000
|
||||
#define ECHOKE 0004000
|
||||
#define FLUSHO 0010000
|
||||
#define PENDIN 0040000
|
||||
#define IEXTEN 0100000
|
||||
#define EXTPROC 0200000
|
||||
|
||||
/* tcflow() and TCXONC use these */
|
||||
#define TCOOFF 0
|
||||
#define TCOON 1
|
||||
#define TCIOFF 2
|
||||
#define TCION 3
|
||||
|
||||
/* tcflush() and TCFLSH use these */
|
||||
#define TCIFLUSH 0
|
||||
#define TCOFLUSH 1
|
||||
#define TCIOFLUSH 2
|
||||
|
||||
/* tcsetattr uses these */
|
||||
#define TCSANOW 0
|
||||
#define TCSADRAIN 1
|
||||
#define TCSAFLUSH 2
|
||||
|
||||
#endif /* _ASM_IA64_TERMBITS_H */
|
|
@ -1,221 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* include/asm-xtensa/termbits.h
|
||||
*
|
||||
* Copied from SH.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2001 - 2005 Tensilica Inc.
|
||||
*/
|
||||
|
||||
#ifndef _XTENSA_TERMBITS_H
|
||||
#define _XTENSA_TERMBITS_H
|
||||
|
||||
|
||||
#include <linux/posix_types.h>
|
||||
|
||||
typedef unsigned char cc_t;
|
||||
typedef unsigned int speed_t;
|
||||
typedef unsigned int tcflag_t;
|
||||
|
||||
#define NCCS 19
|
||||
struct termios {
|
||||
tcflag_t c_iflag; /* input mode flags */
|
||||
tcflag_t c_oflag; /* output mode flags */
|
||||
tcflag_t c_cflag; /* control mode flags */
|
||||
tcflag_t c_lflag; /* local mode flags */
|
||||
cc_t c_line; /* line discipline */
|
||||
cc_t c_cc[NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
struct termios2 {
|
||||
tcflag_t c_iflag; /* input mode flags */
|
||||
tcflag_t c_oflag; /* output mode flags */
|
||||
tcflag_t c_cflag; /* control mode flags */
|
||||
tcflag_t c_lflag; /* local mode flags */
|
||||
cc_t c_line; /* line discipline */
|
||||
cc_t c_cc[NCCS]; /* control characters */
|
||||
speed_t c_ispeed; /* input speed */
|
||||
speed_t c_ospeed; /* output speed */
|
||||
};
|
||||
|
||||
struct ktermios {
|
||||
tcflag_t c_iflag; /* input mode flags */
|
||||
tcflag_t c_oflag; /* output mode flags */
|
||||
tcflag_t c_cflag; /* control mode flags */
|
||||
tcflag_t c_lflag; /* local mode flags */
|
||||
cc_t c_line; /* line discipline */
|
||||
cc_t c_cc[NCCS]; /* control characters */
|
||||
speed_t c_ispeed; /* input speed */
|
||||
speed_t c_ospeed; /* output speed */
|
||||
};
|
||||
|
||||
/* c_cc characters */
|
||||
|
||||
#define VINTR 0
|
||||
#define VQUIT 1
|
||||
#define VERASE 2
|
||||
#define VKILL 3
|
||||
#define VEOF 4
|
||||
#define VTIME 5
|
||||
#define VMIN 6
|
||||
#define VSWTC 7
|
||||
#define VSTART 8
|
||||
#define VSTOP 9
|
||||
#define VSUSP 10
|
||||
#define VEOL 11
|
||||
#define VREPRINT 12
|
||||
#define VDISCARD 13
|
||||
#define VWERASE 14
|
||||
#define VLNEXT 15
|
||||
#define VEOL2 16
|
||||
|
||||
/* c_iflag bits */
|
||||
|
||||
#define IGNBRK 0000001
|
||||
#define BRKINT 0000002
|
||||
#define IGNPAR 0000004
|
||||
#define PARMRK 0000010
|
||||
#define INPCK 0000020
|
||||
#define ISTRIP 0000040
|
||||
#define INLCR 0000100
|
||||
#define IGNCR 0000200
|
||||
#define ICRNL 0000400
|
||||
#define IUCLC 0001000
|
||||
#define IXON 0002000
|
||||
#define IXANY 0004000
|
||||
#define IXOFF 0010000
|
||||
#define IMAXBEL 0020000
|
||||
#define IUTF8 0040000
|
||||
|
||||
/* c_oflag bits */
|
||||
|
||||
#define OPOST 0000001
|
||||
#define OLCUC 0000002
|
||||
#define ONLCR 0000004
|
||||
#define OCRNL 0000010
|
||||
#define ONOCR 0000020
|
||||
#define ONLRET 0000040
|
||||
#define OFILL 0000100
|
||||
#define OFDEL 0000200
|
||||
#define NLDLY 0000400
|
||||
#define NL0 0000000
|
||||
#define NL1 0000400
|
||||
#define CRDLY 0003000
|
||||
#define CR0 0000000
|
||||
#define CR1 0001000
|
||||
#define CR2 0002000
|
||||
#define CR3 0003000
|
||||
#define TABDLY 0014000
|
||||
#define TAB0 0000000
|
||||
#define TAB1 0004000
|
||||
#define TAB2 0010000
|
||||
#define TAB3 0014000
|
||||
#define XTABS 0014000
|
||||
#define BSDLY 0020000
|
||||
#define BS0 0000000
|
||||
#define BS1 0020000
|
||||
#define VTDLY 0040000
|
||||
#define VT0 0000000
|
||||
#define VT1 0040000
|
||||
#define FFDLY 0100000
|
||||
#define FF0 0000000
|
||||
#define FF1 0100000
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
|
||||
#define CBAUD 0010017
|
||||
#define B0 0000000 /* hang up */
|
||||
#define B50 0000001
|
||||
#define B75 0000002
|
||||
#define B110 0000003
|
||||
#define B134 0000004
|
||||
#define B150 0000005
|
||||
#define B200 0000006
|
||||
#define B300 0000007
|
||||
#define B600 0000010
|
||||
#define B1200 0000011
|
||||
#define B1800 0000012
|
||||
#define B2400 0000013
|
||||
#define B4800 0000014
|
||||
#define B9600 0000015
|
||||
#define B19200 0000016
|
||||
#define B38400 0000017
|
||||
#define EXTA B19200
|
||||
#define EXTB B38400
|
||||
#define CSIZE 0000060
|
||||
#define CS5 0000000
|
||||
#define CS6 0000020
|
||||
#define CS7 0000040
|
||||
#define CS8 0000060
|
||||
#define CSTOPB 0000100
|
||||
#define CREAD 0000200
|
||||
#define PARENB 0000400
|
||||
#define PARODD 0001000
|
||||
#define HUPCL 0002000
|
||||
#define CLOCAL 0004000
|
||||
#define CBAUDEX 0010000
|
||||
#define BOTHER 0010000
|
||||
#define B57600 0010001
|
||||
#define B115200 0010002
|
||||
#define B230400 0010003
|
||||
#define B460800 0010004
|
||||
#define B500000 0010005
|
||||
#define B576000 0010006
|
||||
#define B921600 0010007
|
||||
#define B1000000 0010010
|
||||
#define B1152000 0010011
|
||||
#define B1500000 0010012
|
||||
#define B2000000 0010013
|
||||
#define B2500000 0010014
|
||||
#define B3000000 0010015
|
||||
#define B3500000 0010016
|
||||
#define B4000000 0010017
|
||||
#define CIBAUD 002003600000 /* input baud rate */
|
||||
#define CMSPAR 010000000000 /* mark or space (stick) parity */
|
||||
#define CRTSCTS 020000000000 /* flow control */
|
||||
|
||||
#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
|
||||
|
||||
/* c_lflag bits */
|
||||
|
||||
#define ISIG 0000001
|
||||
#define ICANON 0000002
|
||||
#define XCASE 0000004
|
||||
#define ECHO 0000010
|
||||
#define ECHOE 0000020
|
||||
#define ECHOK 0000040
|
||||
#define ECHONL 0000100
|
||||
#define NOFLSH 0000200
|
||||
#define TOSTOP 0000400
|
||||
#define ECHOCTL 0001000
|
||||
#define ECHOPRT 0002000
|
||||
#define ECHOKE 0004000
|
||||
#define FLUSHO 0010000
|
||||
#define PENDIN 0040000
|
||||
#define IEXTEN 0100000
|
||||
#define EXTPROC 0200000
|
||||
|
||||
/* tcflow() and TCXONC use these */
|
||||
|
||||
#define TCOOFF 0
|
||||
#define TCOON 1
|
||||
#define TCIOFF 2
|
||||
#define TCION 3
|
||||
|
||||
/* tcflush() and TCFLSH use these */
|
||||
|
||||
#define TCIFLUSH 0
|
||||
#define TCOFLUSH 1
|
||||
#define TCIOFLUSH 2
|
||||
|
||||
/* tcsetattr uses these */
|
||||
|
||||
#define TCSANOW 0
|
||||
#define TCSADRAIN 1
|
||||
#define TCSAFLUSH 2
|
||||
|
||||
#endif /* _XTENSA_TERMBITS_H */
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/tty.h>
|
||||
|
@ -250,21 +251,7 @@ static void sdio_uart_change_speed(struct sdio_uart_port *port,
|
|||
unsigned char cval, fcr = 0;
|
||||
unsigned int baud, quot;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
cval = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
cval = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
cval = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
cval = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
cval |= UART_LCR_STOP;
|
||||
|
|
|
@ -538,10 +538,8 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
|
|||
*/
|
||||
free_irq(IRQ_AMIGA_VERTB, info);
|
||||
|
||||
if (info->xmit.buf) {
|
||||
free_page((unsigned long) info->xmit.buf);
|
||||
info->xmit.buf = NULL;
|
||||
}
|
||||
free_page((unsigned long)info->xmit.buf);
|
||||
info->xmit.buf = NULL;
|
||||
|
||||
info->IER = 0;
|
||||
amiga_custom.intena = IF_RBF | IF_TBE;
|
||||
|
|
|
@ -434,7 +434,7 @@ static int goldfish_tty_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE
|
||||
static void gf_early_console_putchar(struct uart_port *port, int ch)
|
||||
static void gf_early_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
__raw_writel(ch, port->membase);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#define DCC_STATUS_RX (1 << 30)
|
||||
#define DCC_STATUS_TX (1 << 29)
|
||||
|
||||
static void dcc_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void dcc_uart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (__dcc_getstatus() & DCC_STATUS_TX)
|
||||
cpu_relax();
|
||||
|
|
|
@ -1417,7 +1417,9 @@ out_error:
|
|||
*/
|
||||
static int __init hvc_iucv_config(char *val)
|
||||
{
|
||||
return kstrtoul(val, 10, &hvc_iucv_devices);
|
||||
if (kstrtoul(val, 10, &hvc_iucv_devices))
|
||||
pr_warn("hvc_iucv= invalid parameter value '%s'\n", val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -275,9 +275,6 @@ struct mxser_port {
|
|||
u8 read_status_mask;
|
||||
u8 ignore_status_mask;
|
||||
u8 xmit_fifo_size;
|
||||
unsigned int xmit_head;
|
||||
unsigned int xmit_tail;
|
||||
unsigned int xmit_cnt;
|
||||
|
||||
spinlock_t slock;
|
||||
};
|
||||
|
@ -591,21 +588,7 @@ static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_term
|
|||
}
|
||||
|
||||
/* byte size and parity */
|
||||
switch (cflag & CSIZE) {
|
||||
default:
|
||||
case CS5:
|
||||
cval = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
cval = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
cval = UART_LCR_WLEN7;
|
||||
break;
|
||||
case CS8:
|
||||
cval = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
cval = UART_LCR_WLEN(tty_get_char_size(tty->termios.c_cflag));
|
||||
|
||||
if (cflag & CSTOPB)
|
||||
cval |= UART_LCR_STOP;
|
||||
|
@ -742,22 +725,21 @@ static void mxser_disable_and_clear_FIFO(struct mxser_port *info)
|
|||
static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct mxser_port *info = container_of(port, struct mxser_port, port);
|
||||
unsigned long page;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
page = __get_free_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
ret = tty_port_alloc_xmit_buf(port);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
|
||||
if (!info->type) {
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
free_page(page);
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto err_free_xmit;
|
||||
}
|
||||
info->port.xmit_buf = (unsigned char *) page;
|
||||
|
||||
/*
|
||||
* Clear the FIFO buffers and disable them
|
||||
|
@ -775,8 +757,10 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
|||
if (capable(CAP_SYS_ADMIN)) {
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
return 0;
|
||||
} else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = -ENODEV;
|
||||
goto err_free_xmit;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -812,7 +796,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
|||
(void) inb(info->ioaddr + UART_MSR);
|
||||
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
||||
kfifo_reset(&port->xmit_fifo);
|
||||
|
||||
/*
|
||||
* and set the speed of the serial port
|
||||
|
@ -821,6 +805,9 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
|||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
return 0;
|
||||
err_free_xmit:
|
||||
tty_port_free_xmit_buf(port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -855,14 +842,6 @@ static void mxser_shutdown_port(struct tty_port *port)
|
|||
*/
|
||||
wake_up_interruptible(&info->port.delta_msr_wait);
|
||||
|
||||
/*
|
||||
* Free the xmit buffer, if necessary
|
||||
*/
|
||||
if (info->port.xmit_buf) {
|
||||
free_page((unsigned long) info->port.xmit_buf);
|
||||
info->port.xmit_buf = NULL;
|
||||
}
|
||||
|
||||
info->IER = 0;
|
||||
outb(0x00, info->ioaddr + UART_IER);
|
||||
|
||||
|
@ -877,6 +856,11 @@ static void mxser_shutdown_port(struct tty_port *port)
|
|||
mxser_must_no_sw_flow_control(info->ioaddr);
|
||||
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
/* make sure ISR is not running while we free the buffer */
|
||||
synchronize_irq(info->board->irq);
|
||||
|
||||
tty_port_free_xmit_buf(port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -900,9 +884,8 @@ static void mxser_flush_buffer(struct tty_struct *tty)
|
|||
struct mxser_port *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
||||
kfifo_reset(&info->port.xmit_fifo);
|
||||
|
||||
outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
|
||||
info->ioaddr + UART_FCR);
|
||||
|
@ -919,50 +902,34 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
{
|
||||
int c, total = 0;
|
||||
struct mxser_port *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
int written;
|
||||
bool is_empty;
|
||||
|
||||
while (1) {
|
||||
c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
|
||||
SERIAL_XMIT_SIZE - info->xmit_head));
|
||||
if (c <= 0)
|
||||
break;
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
written = kfifo_in(&info->port.xmit_fifo, buf, count);
|
||||
is_empty = kfifo_is_empty(&info->port.xmit_fifo);
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
info->xmit_head = (info->xmit_head + c) &
|
||||
(SERIAL_XMIT_SIZE - 1);
|
||||
info->xmit_cnt += c;
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
buf += c;
|
||||
count -= c;
|
||||
total += c;
|
||||
}
|
||||
|
||||
if (info->xmit_cnt && !tty->flow.stopped)
|
||||
if (!is_empty && !tty->flow.stopped)
|
||||
if (!tty->hw_stopped || mxser_16550A_or_MUST(info))
|
||||
mxser_start_tx(info);
|
||||
|
||||
return total;
|
||||
return written;
|
||||
}
|
||||
|
||||
static int mxser_put_char(struct tty_struct *tty, unsigned char ch)
|
||||
{
|
||||
struct mxser_port *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
|
||||
return 0;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
info->port.xmit_buf[info->xmit_head++] = ch;
|
||||
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
|
||||
info->xmit_cnt++;
|
||||
ret = kfifo_put(&info->port.xmit_fifo, ch);
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -970,7 +937,7 @@ static void mxser_flush_chars(struct tty_struct *tty)
|
|||
{
|
||||
struct mxser_port *info = tty->driver_data;
|
||||
|
||||
if (!info->xmit_cnt || tty->flow.stopped ||
|
||||
if (kfifo_is_empty(&info->port.xmit_fifo) || tty->flow.stopped ||
|
||||
(tty->hw_stopped && !mxser_16550A_or_MUST(info)))
|
||||
return;
|
||||
|
||||
|
@ -980,16 +947,15 @@ static void mxser_flush_chars(struct tty_struct *tty)
|
|||
static unsigned int mxser_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct mxser_port *info = tty->driver_data;
|
||||
int ret;
|
||||
|
||||
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
|
||||
return ret < 0 ? 0 : ret;
|
||||
return kfifo_avail(&info->port.xmit_fifo);
|
||||
}
|
||||
|
||||
static unsigned int mxser_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct mxser_port *info = tty->driver_data;
|
||||
return info->xmit_cnt;
|
||||
|
||||
return kfifo_len(&info->port.xmit_fifo);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1378,7 +1344,7 @@ static void mxser_start(struct tty_struct *tty)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
if (info->xmit_cnt)
|
||||
if (!kfifo_is_empty(&info->port.xmit_fifo))
|
||||
__mxser_start_tx(info);
|
||||
spin_unlock_irqrestore(&info->slock, flags);
|
||||
}
|
||||
|
@ -1609,7 +1575,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
|
|||
return;
|
||||
}
|
||||
|
||||
if (!port->xmit_cnt || tty->flow.stopped ||
|
||||
if (kfifo_is_empty(&port->port.xmit_fifo) || tty->flow.stopped ||
|
||||
(tty->hw_stopped && !mxser_16550A_or_MUST(port))) {
|
||||
__mxser_stop_tx(port);
|
||||
return;
|
||||
|
@ -1617,18 +1583,19 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
|
|||
|
||||
count = port->xmit_fifo_size;
|
||||
do {
|
||||
outb(port->port.xmit_buf[port->xmit_tail++],
|
||||
port->ioaddr + UART_TX);
|
||||
port->xmit_tail &= SERIAL_XMIT_SIZE - 1;
|
||||
port->icount.tx++;
|
||||
if (!--port->xmit_cnt)
|
||||
unsigned char c;
|
||||
|
||||
if (!kfifo_get(&port->port.xmit_fifo, &c))
|
||||
break;
|
||||
|
||||
outb(c, port->ioaddr + UART_TX);
|
||||
port->icount.tx++;
|
||||
} while (--count > 0);
|
||||
|
||||
if (port->xmit_cnt < WAKEUP_CHARS)
|
||||
if (kfifo_len(&port->port.xmit_fifo) < WAKEUP_CHARS)
|
||||
tty_wakeup(tty);
|
||||
|
||||
if (!port->xmit_cnt)
|
||||
if (kfifo_is_empty(&port->port.xmit_fifo))
|
||||
__mxser_stop_tx(port);
|
||||
}
|
||||
|
||||
|
|
|
@ -704,13 +704,10 @@ static const struct acpi_device_id serdev_acpi_devices_blacklist[] = {
|
|||
static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level,
|
||||
void *data, void **return_value)
|
||||
{
|
||||
struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
|
||||
struct serdev_controller *ctrl = data;
|
||||
struct acpi_device *adev;
|
||||
|
||||
if (acpi_bus_get_device(handle, &adev))
|
||||
return AE_OK;
|
||||
|
||||
if (acpi_device_enumerated(adev))
|
||||
if (!adev || acpi_device_enumerated(adev))
|
||||
return AE_OK;
|
||||
|
||||
/* Skip if black listed */
|
||||
|
|
|
@ -403,7 +403,7 @@ static void serial21285_setup_ports(void)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_21285_CONSOLE
|
||||
static void serial21285_console_putchar(struct uart_port *port, int ch)
|
||||
static void serial21285_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (*CSR_UARTFLG & 0x20)
|
||||
barrier();
|
||||
|
|
|
@ -82,7 +82,7 @@ static ssize_t lpc_address_show(struct device *dev,
|
|||
addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) |
|
||||
(aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL));
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
|
||||
return sysfs_emit(buf, "0x%x\n", addr);
|
||||
}
|
||||
|
||||
static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr)
|
||||
|
@ -124,7 +124,7 @@ static ssize_t sirq_show(struct device *dev,
|
|||
reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
|
||||
reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg);
|
||||
return sysfs_emit(buf, "%u\n", reg);
|
||||
}
|
||||
|
||||
static int aspeed_vuart_set_sirq(struct aspeed_vuart *vuart, u32 sirq)
|
||||
|
@ -171,7 +171,7 @@ static ssize_t sirq_polarity_show(struct device *dev,
|
|||
reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
|
||||
reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0);
|
||||
return sysfs_emit(buf, "%u\n", reg ? 1 : 0);
|
||||
}
|
||||
|
||||
static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart,
|
||||
|
@ -487,7 +487,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
|
|||
port.port.irq = irq_of_parse_and_map(np, 0);
|
||||
port.port.handle_irq = aspeed_vuart_handle_irq;
|
||||
port.port.iotype = UPIO_MEM;
|
||||
port.port.type = PORT_16550A;
|
||||
port.port.type = PORT_ASPEED_VUART;
|
||||
port.port.uartclk = clk;
|
||||
port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
|
||||
| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
|
@ -44,6 +45,10 @@ struct bcm2835aux_data {
|
|||
u32 cntl;
|
||||
};
|
||||
|
||||
struct bcm2835_aux_serial_driver_data {
|
||||
resource_size_t offset;
|
||||
};
|
||||
|
||||
static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
|
||||
{
|
||||
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
|
@ -80,9 +85,12 @@ static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
|
|||
|
||||
static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct bcm2835_aux_serial_driver_data *bcm_data;
|
||||
struct uart_8250_port up = { };
|
||||
struct bcm2835aux_data *data;
|
||||
resource_size_t offset = 0;
|
||||
struct resource *res;
|
||||
unsigned int uartclk;
|
||||
int ret;
|
||||
|
||||
/* allocate the custom structure */
|
||||
|
@ -109,9 +117,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/* get the clock - this also enables the HW */
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(data->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n");
|
||||
data->clk = devm_clk_get_optional(&pdev->dev, NULL);
|
||||
|
||||
/* get the interrupt */
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
|
@ -125,8 +131,24 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "memory resource not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
up.port.mapbase = res->start;
|
||||
up.port.mapsize = resource_size(res);
|
||||
|
||||
bcm_data = device_get_match_data(&pdev->dev);
|
||||
|
||||
/* Some UEFI implementations (e.g. tianocore/edk2 for the Raspberry Pi)
|
||||
* describe the miniuart with a base address that encompasses the auxiliary
|
||||
* registers shared between the miniuart and spi.
|
||||
*
|
||||
* This is due to historical reasons, see discussion here :
|
||||
* https://edk2.groups.io/g/devel/topic/87501357#84349
|
||||
*
|
||||
* We need to add the offset between the miniuart and auxiliary
|
||||
* registers to get the real miniuart base address.
|
||||
*/
|
||||
if (bcm_data)
|
||||
offset = bcm_data->offset;
|
||||
|
||||
up.port.mapbase = res->start + offset;
|
||||
up.port.mapsize = resource_size(res) - offset;
|
||||
|
||||
/* Check for a fixed line number */
|
||||
ret = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
|
@ -141,12 +163,19 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
uartclk = clk_get_rate(data->clk);
|
||||
if (!uartclk) {
|
||||
ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
|
||||
}
|
||||
|
||||
/* the HW-clock divider for bcm2835aux is 8,
|
||||
* but 8250 expects a divider of 16,
|
||||
* so we have to multiply the actual clock by 2
|
||||
* to get identical baudrates.
|
||||
*/
|
||||
up.port.uartclk = clk_get_rate(data->clk) * 2;
|
||||
up.port.uartclk = uartclk * 2;
|
||||
|
||||
/* register the port */
|
||||
ret = serial8250_register_8250_port(&up);
|
||||
|
@ -173,16 +202,27 @@ static int bcm2835aux_serial_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = {
|
||||
.offset = 0x40,
|
||||
};
|
||||
|
||||
static const struct of_device_id bcm2835aux_serial_match[] = {
|
||||
{ .compatible = "brcm,bcm2835-aux-uart" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm2835aux_serial_match);
|
||||
|
||||
static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = {
|
||||
{ "BCM2836", (kernel_ulong_t)&bcm2835_acpi_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
|
||||
|
||||
static struct platform_driver bcm2835aux_serial_driver = {
|
||||
.driver = {
|
||||
.name = "bcm2835-aux-uart",
|
||||
.of_match_table = bcm2835aux_serial_match,
|
||||
.acpi_match_table = bcm2835aux_serial_acpi_match,
|
||||
},
|
||||
.probe = bcm2835aux_serial_probe,
|
||||
.remove = bcm2835aux_serial_remove,
|
||||
|
|
|
@ -64,10 +64,19 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct uart_port *up = &p->port;
|
||||
int ret;
|
||||
|
||||
if (dma->tx_running)
|
||||
if (dma->tx_running) {
|
||||
if (up->x_char) {
|
||||
dmaengine_pause(dma->txchan);
|
||||
uart_xchar_out(up, UART_TX);
|
||||
dmaengine_resume(dma->txchan);
|
||||
}
|
||||
return 0;
|
||||
} else if (up->x_char) {
|
||||
uart_xchar_out(up, UART_TX);
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
|
||||
/* We have been called from __dma_tx_complete() */
|
||||
|
|
|
@ -86,7 +86,7 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
|
|||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
static void serial_putc(struct uart_port *port, int c)
|
||||
static void serial_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
|
|
|
@ -623,7 +623,12 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
|
|||
|
||||
maxnr = pci_resource_len(pcidev, bar) >> (board->reg_shift + 3);
|
||||
|
||||
nr_ports = board->num_ports ? board->num_ports : pcidev->device & 0x0f;
|
||||
if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO)
|
||||
nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1);
|
||||
else if (board->num_ports)
|
||||
nr_ports = board->num_ports;
|
||||
else
|
||||
nr_ports = pcidev->device & 0x0f;
|
||||
|
||||
priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
|
||||
if (!priv)
|
||||
|
@ -722,22 +727,6 @@ static int __maybe_unused exar_resume(struct device *dev)
|
|||
|
||||
static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
|
||||
|
||||
static const struct exar8250_board acces_com_2x = {
|
||||
.num_ports = 2,
|
||||
.setup = pci_xr17c154_setup,
|
||||
};
|
||||
|
||||
static const struct exar8250_board acces_com_4x = {
|
||||
.num_ports = 4,
|
||||
.setup = pci_xr17c154_setup,
|
||||
};
|
||||
|
||||
static const struct exar8250_board acces_com_8x = {
|
||||
.num_ports = 8,
|
||||
.setup = pci_xr17c154_setup,
|
||||
};
|
||||
|
||||
|
||||
static const struct exar8250_board pbn_fastcom335_2 = {
|
||||
.num_ports = 2,
|
||||
.setup = pci_fastcom335_setup,
|
||||
|
@ -822,13 +811,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
|
|||
}
|
||||
|
||||
static const struct pci_device_id exar_pci_tbl[] = {
|
||||
EXAR_DEVICE(ACCESSIO, COM_2S, acces_com_2x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_4S, acces_com_4x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_8S, acces_com_8x),
|
||||
EXAR_DEVICE(ACCESSIO, COM232_8, acces_com_8x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_2SM, acces_com_2x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_4SM, acces_com_4x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_8SM, acces_com_8x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_2S, pbn_exar_XR17C15x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_4S, pbn_exar_XR17C15x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_8S, pbn_exar_XR17C15x),
|
||||
EXAR_DEVICE(ACCESSIO, COM232_8, pbn_exar_XR17C15x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_2SM, pbn_exar_XR17C15x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_4SM, pbn_exar_XR17C15x),
|
||||
EXAR_DEVICE(ACCESSIO, COM_8SM, pbn_exar_XR17C15x),
|
||||
|
||||
CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect),
|
||||
CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect),
|
||||
|
|
|
@ -52,7 +52,7 @@ static void early_out(struct uart_port *port, int offset, uint8_t value)
|
|||
writel(value, port->membase + (offset << 2));
|
||||
}
|
||||
|
||||
static void ingenic_early_console_putc(struct uart_port *port, int c)
|
||||
static void ingenic_early_console_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
uint8_t lsr;
|
||||
|
||||
|
|
|
@ -117,8 +117,7 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
|||
{
|
||||
struct dw_dma_slave *param = &lpss->dma_param;
|
||||
struct pci_dev *pdev = to_pci_dev(port->dev);
|
||||
unsigned int dma_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0);
|
||||
struct pci_dev *dma_dev = pci_get_slot(pdev->bus, dma_devfn);
|
||||
struct pci_dev *dma_dev;
|
||||
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_BYT_UART1:
|
||||
|
@ -137,6 +136,8 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
|
||||
|
||||
param->dma_dev = &dma_dev->dev;
|
||||
param->m_master = 0;
|
||||
param->p_master = 1;
|
||||
|
@ -152,6 +153,14 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void byt_serial_exit(struct lpss8250 *lpss)
|
||||
{
|
||||
struct dw_dma_slave *param = &lpss->dma_param;
|
||||
|
||||
/* Paired with pci_get_slot() in the byt_serial_setup() above */
|
||||
put_device(param->dma_dev);
|
||||
}
|
||||
|
||||
static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_dma *dma = &lpss->data.dma;
|
||||
|
@ -170,6 +179,13 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ehl_serial_exit(struct lpss8250 *lpss)
|
||||
{
|
||||
struct uart_8250_port *up = serial8250_get_port(lpss->data.line);
|
||||
|
||||
up->dma = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static const struct dw_dma_platform_data qrk_serial_dma_pdata = {
|
||||
.nr_channels = 2,
|
||||
|
@ -344,8 +360,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
return 0;
|
||||
|
||||
err_exit:
|
||||
if (lpss->board->exit)
|
||||
lpss->board->exit(lpss);
|
||||
lpss->board->exit(lpss);
|
||||
pci_free_irq_vectors(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
@ -356,8 +371,7 @@ static void lpss8250_remove(struct pci_dev *pdev)
|
|||
|
||||
serial8250_unregister_port(lpss->data.line);
|
||||
|
||||
if (lpss->board->exit)
|
||||
lpss->board->exit(lpss);
|
||||
lpss->board->exit(lpss);
|
||||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
|
@ -365,12 +379,14 @@ static const struct lpss8250_board byt_board = {
|
|||
.freq = 100000000,
|
||||
.base_baud = 2764800,
|
||||
.setup = byt_serial_setup,
|
||||
.exit = byt_serial_exit,
|
||||
};
|
||||
|
||||
static const struct lpss8250_board ehl_board = {
|
||||
.freq = 200000000,
|
||||
.base_baud = 12500000,
|
||||
.setup = ehl_serial_setup,
|
||||
.exit = ehl_serial_exit,
|
||||
};
|
||||
|
||||
static const struct lpss8250_board qrk_board = {
|
||||
|
|
|
@ -73,6 +73,11 @@ static int pnw_setup(struct mid8250 *mid, struct uart_port *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pnw_exit(struct mid8250 *mid)
|
||||
{
|
||||
pci_dev_put(mid->dma_dev);
|
||||
}
|
||||
|
||||
static int tng_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct mid8250 *mid = p->private_data;
|
||||
|
@ -124,6 +129,11 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tng_exit(struct mid8250 *mid)
|
||||
{
|
||||
pci_dev_put(mid->dma_dev);
|
||||
}
|
||||
|
||||
static int dnv_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct mid8250 *mid = p->private_data;
|
||||
|
@ -312,11 +322,9 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (!uart.port.membase)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mid->board->setup) {
|
||||
ret = mid->board->setup(mid, &uart.port);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = mid->board->setup(mid, &uart.port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mid8250_dma_setup(mid, &uart);
|
||||
if (ret)
|
||||
|
@ -330,9 +338,9 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
pci_set_drvdata(pdev, mid);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (mid->board->exit)
|
||||
mid->board->exit(mid);
|
||||
mid->board->exit(mid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -342,8 +350,7 @@ static void mid8250_remove(struct pci_dev *pdev)
|
|||
|
||||
serial8250_unregister_port(mid->line);
|
||||
|
||||
if (mid->board->exit)
|
||||
mid->board->exit(mid);
|
||||
mid->board->exit(mid);
|
||||
}
|
||||
|
||||
static const struct mid8250_board pnw_board = {
|
||||
|
@ -351,6 +358,7 @@ static const struct mid8250_board pnw_board = {
|
|||
.freq = 50000000,
|
||||
.base_baud = 115200,
|
||||
.setup = pnw_setup,
|
||||
.exit = pnw_exit,
|
||||
};
|
||||
|
||||
static const struct mid8250_board tng_board = {
|
||||
|
@ -358,6 +366,7 @@ static const struct mid8250_board tng_board = {
|
|||
.freq = 38400000,
|
||||
.base_baud = 1843200,
|
||||
.setup = tng_setup,
|
||||
.exit = tng_exit,
|
||||
};
|
||||
|
||||
static const struct mid8250_board dnv_board = {
|
||||
|
@ -368,16 +377,14 @@ static const struct mid8250_board dnv_board = {
|
|||
.exit = dnv_exit,
|
||||
};
|
||||
|
||||
#define MID_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
|
||||
|
||||
static const struct pci_device_id pci_ids[] = {
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART1, pnw_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART2, pnw_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART3, pnw_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_TNG_UART, tng_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_CDF_UART, dnv_board),
|
||||
MID_DEVICE(PCI_DEVICE_ID_INTEL_DNV_UART, dnv_board),
|
||||
{ },
|
||||
{ PCI_DEVICE_DATA(INTEL, PNW_UART1, &pnw_board) },
|
||||
{ PCI_DEVICE_DATA(INTEL, PNW_UART2, &pnw_board) },
|
||||
{ PCI_DEVICE_DATA(INTEL, PNW_UART3, &pnw_board) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TNG_UART, &tng_board) },
|
||||
{ PCI_DEVICE_DATA(INTEL, CDF_UART, &dnv_board) },
|
||||
{ PCI_DEVICE_DATA(INTEL, DNV_UART, &dnv_board) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci_ids);
|
||||
|
||||
|
|
|
@ -289,10 +289,10 @@ static void
|
|||
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned short fraction_L_mapping[] = {
|
||||
static const unsigned short fraction_L_mapping[] = {
|
||||
0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF
|
||||
};
|
||||
unsigned short fraction_M_mapping[] = {
|
||||
static const unsigned short fraction_M_mapping[] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3
|
||||
};
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
|
|
@ -357,21 +357,7 @@ static void omap_8250_set_termios(struct uart_port *port,
|
|||
unsigned char cval = 0;
|
||||
unsigned int baud;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
cval = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
cval = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
cval = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
cval = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
cval |= UART_LCR_STOP;
|
||||
|
|
|
@ -307,6 +307,14 @@ static const struct serial8250_config uart_config[] = {
|
|||
.rxtrig_bytes = {1, 32, 64, 112},
|
||||
.flags = UART_CAP_FIFO | UART_CAP_SLEEP,
|
||||
},
|
||||
[PORT_ASPEED_VUART] = {
|
||||
.name = "ASPEED VUART",
|
||||
.fifo_size = 16,
|
||||
.tx_loadsz = 16,
|
||||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
|
||||
.rxtrig_bytes = {1, 4, 8, 14},
|
||||
.flags = UART_CAP_FIFO,
|
||||
},
|
||||
};
|
||||
|
||||
/* Uart divisor latch read */
|
||||
|
@ -1615,6 +1623,18 @@ static inline void start_tx_rs485(struct uart_port *port)
|
|||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct uart_8250_em485 *em485 = up->em485;
|
||||
|
||||
/*
|
||||
* While serial8250_em485_handle_stop_tx() is a noop if
|
||||
* em485->active_timer != &em485->stop_tx_timer, it might happen that
|
||||
* the timer is still armed and triggers only after the current bunch of
|
||||
* chars is send and em485->active_timer == &em485->stop_tx_timer again.
|
||||
* So cancel the timer. There is still a theoretical race condition if
|
||||
* the timer is already running and only comes around to check for
|
||||
* em485->active_timer when &em485->stop_tx_timer is armed again.
|
||||
*/
|
||||
if (em485->active_timer == &em485->stop_tx_timer)
|
||||
hrtimer_try_to_cancel(&em485->stop_tx_timer);
|
||||
|
||||
em485->active_timer = NULL;
|
||||
|
||||
if (em485->tx_stopped) {
|
||||
|
@ -1657,6 +1677,9 @@ static void serial8250_start_tx(struct uart_port *port)
|
|||
|
||||
serial8250_rpm_get_tx(up);
|
||||
|
||||
if (!port->x_char && uart_circ_empty(&port->state->xmit))
|
||||
return;
|
||||
|
||||
if (em485 &&
|
||||
em485->active_timer == &em485->start_tx_timer)
|
||||
return;
|
||||
|
@ -1799,9 +1822,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
|||
int count;
|
||||
|
||||
if (port->x_char) {
|
||||
serial_out(up, UART_TX, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
uart_xchar_out(port, UART_TX);
|
||||
return;
|
||||
}
|
||||
if (uart_tx_stopped(port)) {
|
||||
|
@ -2582,21 +2603,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
|
|||
{
|
||||
unsigned char cval;
|
||||
|
||||
switch (c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
cval = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
cval = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
cval = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
cval = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
cval = UART_LCR_WLEN(tty_get_char_size(c_cflag));
|
||||
|
||||
if (c_cflag & CSTOPB)
|
||||
cval |= UART_LCR_STOP;
|
||||
|
@ -3296,7 +3303,7 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults);
|
|||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
|
||||
static void serial8250_console_putchar(struct uart_port *port, int ch)
|
||||
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ static const struct of_device_id tegra_uart_of_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_uart_of_match);
|
||||
|
||||
static const struct acpi_device_id tegra_uart_acpi_match[] = {
|
||||
static const struct acpi_device_id tegra_uart_acpi_match[] __maybe_unused = {
|
||||
{ "NVDA0100", 0 },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -479,11 +479,12 @@ config SERIAL_8250_LPSS
|
|||
select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS)
|
||||
select RATIONAL
|
||||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present on the UART found on various Intel platforms such as:
|
||||
Selecting this option will enable handling of the UART found on
|
||||
various Intel platforms such as:
|
||||
- Intel Baytrail SoC
|
||||
- Intel Braswell SoC
|
||||
- Intel Quark X1000 SoC
|
||||
that are not covered by the more generic SERIAL_8250_PCI option.
|
||||
|
||||
config SERIAL_8250_MID
|
||||
tristate "Support for serial ports on Intel MID platforms"
|
||||
|
@ -494,17 +495,18 @@ config SERIAL_8250_MID
|
|||
select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
|
||||
select RATIONAL
|
||||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present on the UART found on Intel Medfield SOC and various other
|
||||
Intel platforms.
|
||||
Selecting this option will enable handling of the UART found on
|
||||
Intel Medfield SOC and various other Intel platforms that is not
|
||||
covered by the more generic SERIAL_8250_PCI option.
|
||||
|
||||
config SERIAL_8250_PERICOM
|
||||
tristate "Support for Pericom and Acces I/O serial ports"
|
||||
default SERIAL_8250
|
||||
depends on SERIAL_8250 && PCI
|
||||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present on the Pericom and Acces I/O UARTs.
|
||||
Selecting this option will enable handling of the Pericom and Acces
|
||||
I/O UARTs that are not covered by the more generic SERIAL_8250_PCI
|
||||
option.
|
||||
|
||||
config SERIAL_8250_PXA
|
||||
tristate "PXA serial port support"
|
||||
|
|
|
@ -139,6 +139,7 @@ config SERIAL_ATMEL_CONSOLE
|
|||
bool "Support for console on AT91 serial port"
|
||||
depends on SERIAL_ATMEL=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Say Y here if you wish to use an on-chip UART on a Atmel
|
||||
AT91 processor as the system console (the system
|
||||
|
@ -236,7 +237,7 @@ config SERIAL_CLPS711X_CONSOLE
|
|||
|
||||
config SERIAL_SAMSUNG
|
||||
tristate "Samsung SoC serial support"
|
||||
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || COMPILE_TEST
|
||||
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || ARCH_ARTPEC || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Support for the on-chip UARTs on the Samsung
|
||||
|
@ -1099,7 +1100,8 @@ config SERIAL_TIMBERDALE
|
|||
config SERIAL_BCM63XX
|
||||
tristate "Broadcom BCM63xx/BCM33xx UART support"
|
||||
select SERIAL_CORE
|
||||
depends on COMMON_CLK
|
||||
depends on ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST
|
||||
default ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC
|
||||
help
|
||||
This enables the driver for the onchip UART core found on
|
||||
the following chipsets:
|
||||
|
@ -1445,6 +1447,7 @@ config SERIAL_STM32_CONSOLE
|
|||
config SERIAL_MVEBU_UART
|
||||
bool "Marvell EBU serial port support"
|
||||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver is for Marvell EBU SoC's UART. If you have a machine
|
||||
|
@ -1562,6 +1565,31 @@ config SERIAL_LITEUART_CONSOLE
|
|||
and warnings and which allows logins in single user mode).
|
||||
Otherwise, say 'N'.
|
||||
|
||||
config SERIAL_SUNPLUS
|
||||
tristate "Sunplus UART support"
|
||||
depends on ARCH_SUNPLUS || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Select this option if you would like to use Sunplus serial port on
|
||||
Sunplus SoC SP7021.
|
||||
If you enable this option, Sunplus serial ports in the system will
|
||||
be registered as ttySUPx.
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called sunplus-uart.
|
||||
|
||||
config SERIAL_SUNPLUS_CONSOLE
|
||||
bool "Console on Sunplus UART"
|
||||
depends on SERIAL_SUNPLUS
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Select this option if you would like to use a Sunplus UART as the
|
||||
system console.
|
||||
Even if you say Y here, the currently visible virtual console
|
||||
(/dev/tty0) will still be used as the system console by default, but
|
||||
you can alter that using a kernel command line option such as
|
||||
"console=ttySUPx".
|
||||
|
||||
endmenu
|
||||
|
||||
config SERIAL_MCTRL_GPIO
|
||||
|
|
|
@ -87,6 +87,7 @@ obj-$(CONFIG_SERIAL_RDA) += rda-uart.o
|
|||
obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o
|
||||
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
|
||||
obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o
|
||||
obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o
|
||||
|
||||
# GPIOLIB helpers for modem control lines
|
||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||
|
|
|
@ -298,7 +298,7 @@ static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
|
|||
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
|
||||
|
||||
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
|
||||
static void altera_jtaguart_console_putc(struct uart_port *port, int c)
|
||||
static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned long status;
|
||||
unsigned long flags;
|
||||
|
@ -318,7 +318,7 @@ static void altera_jtaguart_console_putc(struct uart_port *port, int c)
|
|||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
#else
|
||||
static void altera_jtaguart_console_putc(struct uart_port *port, int c)
|
||||
static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
|
|
|
@ -438,7 +438,7 @@ static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
|
|||
|
||||
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
|
||||
|
||||
static void altera_uart_console_putc(struct uart_port *port, int c)
|
||||
static void altera_uart_console_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
ALTERA_UART_STATUS_TRDY_MSK))
|
||||
|
|
|
@ -110,38 +110,38 @@ static void pl010_enable_ms(struct uart_port *port)
|
|||
writel(cr, uap->port.membase + UART010_CR);
|
||||
}
|
||||
|
||||
static void pl010_rx_chars(struct uart_amba_port *uap)
|
||||
static void pl010_rx_chars(struct uart_port *port)
|
||||
{
|
||||
unsigned int status, ch, flag, rsr, max_count = 256;
|
||||
|
||||
status = readb(uap->port.membase + UART01x_FR);
|
||||
status = readb(port->membase + UART01x_FR);
|
||||
while (UART_RX_DATA(status) && max_count--) {
|
||||
ch = readb(uap->port.membase + UART01x_DR);
|
||||
ch = readb(port->membase + UART01x_DR);
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
uap->port.icount.rx++;
|
||||
port->icount.rx++;
|
||||
|
||||
/*
|
||||
* Note that the error handling code is
|
||||
* out of the main execution path
|
||||
*/
|
||||
rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
|
||||
rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
|
||||
if (unlikely(rsr & UART01x_RSR_ANY)) {
|
||||
writel(0, uap->port.membase + UART01x_ECR);
|
||||
writel(0, port->membase + UART01x_ECR);
|
||||
|
||||
if (rsr & UART01x_RSR_BE) {
|
||||
rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
|
||||
uap->port.icount.brk++;
|
||||
if (uart_handle_break(&uap->port))
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
goto ignore_char;
|
||||
} else if (rsr & UART01x_RSR_PE)
|
||||
uap->port.icount.parity++;
|
||||
port->icount.parity++;
|
||||
else if (rsr & UART01x_RSR_FE)
|
||||
uap->port.icount.frame++;
|
||||
port->icount.frame++;
|
||||
if (rsr & UART01x_RSR_OE)
|
||||
uap->port.icount.overrun++;
|
||||
port->icount.overrun++;
|
||||
|
||||
rsr &= uap->port.read_status_mask;
|
||||
rsr &= port->read_status_mask;
|
||||
|
||||
if (rsr & UART01x_RSR_BE)
|
||||
flag = TTY_BREAK;
|
||||
|
@ -151,56 +151,57 @@ static void pl010_rx_chars(struct uart_amba_port *uap)
|
|||
flag = TTY_FRAME;
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(&uap->port, ch))
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
goto ignore_char;
|
||||
|
||||
uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
|
||||
uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
|
||||
|
||||
ignore_char:
|
||||
status = readb(uap->port.membase + UART01x_FR);
|
||||
status = readb(port->membase + UART01x_FR);
|
||||
}
|
||||
tty_flip_buffer_push(&uap->port.state->port);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void pl010_tx_chars(struct uart_amba_port *uap)
|
||||
static void pl010_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &uap->port.state->xmit;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int count;
|
||||
|
||||
if (uap->port.x_char) {
|
||||
writel(uap->port.x_char, uap->port.membase + UART01x_DR);
|
||||
uap->port.icount.tx++;
|
||||
uap->port.x_char = 0;
|
||||
if (port->x_char) {
|
||||
writel(port->x_char, port->membase + UART01x_DR);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
|
||||
pl010_stop_tx(&uap->port);
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
pl010_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
count = uap->port.fifosize >> 1;
|
||||
count = port->fifosize >> 1;
|
||||
do {
|
||||
writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
|
||||
writel(xmit->buf[xmit->tail], port->membase + UART01x_DR);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
uap->port.icount.tx++;
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
pl010_stop_tx(&uap->port);
|
||||
pl010_stop_tx(port);
|
||||
}
|
||||
|
||||
static void pl010_modem_status(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_port *port = &uap->port;
|
||||
unsigned int status, delta;
|
||||
|
||||
writel(0, uap->port.membase + UART010_ICR);
|
||||
writel(0, port->membase + UART010_ICR);
|
||||
|
||||
status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
|
||||
status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
|
||||
|
||||
delta = status ^ uap->old_status;
|
||||
uap->old_status = status;
|
||||
|
@ -209,65 +210,63 @@ static void pl010_modem_status(struct uart_amba_port *uap)
|
|||
return;
|
||||
|
||||
if (delta & UART01x_FR_DCD)
|
||||
uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
|
||||
uart_handle_dcd_change(port, status & UART01x_FR_DCD);
|
||||
|
||||
if (delta & UART01x_FR_DSR)
|
||||
uap->port.icount.dsr++;
|
||||
port->icount.dsr++;
|
||||
|
||||
if (delta & UART01x_FR_CTS)
|
||||
uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS);
|
||||
uart_handle_cts_change(port, status & UART01x_FR_CTS);
|
||||
|
||||
wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
static irqreturn_t pl010_int(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_amba_port *uap = dev_id;
|
||||
struct uart_port *port = &uap->port;
|
||||
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
|
||||
int handled = 0;
|
||||
|
||||
spin_lock(&uap->port.lock);
|
||||
spin_lock(&port->lock);
|
||||
|
||||
status = readb(uap->port.membase + UART010_IIR);
|
||||
status = readb(port->membase + UART010_IIR);
|
||||
if (status) {
|
||||
do {
|
||||
if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
|
||||
pl010_rx_chars(uap);
|
||||
pl010_rx_chars(port);
|
||||
if (status & UART010_IIR_MIS)
|
||||
pl010_modem_status(uap);
|
||||
if (status & UART010_IIR_TIS)
|
||||
pl010_tx_chars(uap);
|
||||
pl010_tx_chars(port);
|
||||
|
||||
if (pass_counter-- == 0)
|
||||
break;
|
||||
|
||||
status = readb(uap->port.membase + UART010_IIR);
|
||||
status = readb(port->membase + UART010_IIR);
|
||||
} while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
|
||||
UART010_IIR_TIS));
|
||||
handled = 1;
|
||||
}
|
||||
|
||||
spin_unlock(&uap->port.lock);
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static unsigned int pl010_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int status = readb(uap->port.membase + UART01x_FR);
|
||||
unsigned int status = readb(port->membase + UART01x_FR);
|
||||
|
||||
return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
||||
static unsigned int pl010_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int result = 0;
|
||||
unsigned int status;
|
||||
|
||||
status = readb(uap->port.membase + UART01x_FR);
|
||||
status = readb(port->membase + UART01x_FR);
|
||||
if (status & UART01x_FR_DCD)
|
||||
result |= TIOCM_CAR;
|
||||
if (status & UART01x_FR_DSR)
|
||||
|
@ -284,24 +283,22 @@ static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
if (uap->data)
|
||||
uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
|
||||
uap->data->set_mctrl(uap->dev, port->membase, mctrl);
|
||||
}
|
||||
|
||||
static void pl010_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int lcr_h;
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
lcr_h = readb(uap->port.membase + UART010_LCRH);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
lcr_h = readb(port->membase + UART010_LCRH);
|
||||
if (break_state == -1)
|
||||
lcr_h |= UART01x_LCRH_BRK;
|
||||
else
|
||||
lcr_h &= ~UART01x_LCRH_BRK;
|
||||
writel(lcr_h, uap->port.membase + UART010_LCRH);
|
||||
spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
writel(lcr_h, port->membase + UART010_LCRH);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int pl010_startup(struct uart_port *port)
|
||||
|
@ -317,25 +314,25 @@ static int pl010_startup(struct uart_port *port)
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
uap->port.uartclk = clk_get_rate(uap->clk);
|
||||
port->uartclk = clk_get_rate(uap->clk);
|
||||
|
||||
/*
|
||||
* Allocate the IRQ
|
||||
*/
|
||||
retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
|
||||
retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", uap);
|
||||
if (retval)
|
||||
goto clk_dis;
|
||||
|
||||
/*
|
||||
* initialise the old status of the modem signals
|
||||
*/
|
||||
uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
|
||||
uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
|
||||
|
||||
/*
|
||||
* Finally, enable interrupts
|
||||
*/
|
||||
writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,
|
||||
uap->port.membase + UART010_CR);
|
||||
port->membase + UART010_CR);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -353,17 +350,17 @@ static void pl010_shutdown(struct uart_port *port)
|
|||
/*
|
||||
* Free the interrupt
|
||||
*/
|
||||
free_irq(uap->port.irq, uap);
|
||||
free_irq(port->irq, uap);
|
||||
|
||||
/*
|
||||
* disable all interrupts, disable the port
|
||||
*/
|
||||
writel(0, uap->port.membase + UART010_CR);
|
||||
writel(0, port->membase + UART010_CR);
|
||||
|
||||
/* disable break condition and fifos */
|
||||
writel(readb(uap->port.membase + UART010_LCRH) &
|
||||
writel(readb(port->membase + UART010_LCRH) &
|
||||
~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
|
||||
uap->port.membase + UART010_LCRH);
|
||||
port->membase + UART010_LCRH);
|
||||
|
||||
/*
|
||||
* Shut down the clock producer
|
||||
|
@ -375,8 +372,6 @@ static void
|
|||
pl010_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int lcr_h, old_cr;
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
@ -384,7 +379,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
/*
|
||||
* Ask the core to calculate the divisor for us.
|
||||
*/
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16);
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
|
||||
quot = uart_get_divisor(port, baud);
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
|
@ -408,63 +403,63 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
if (!(termios->c_cflag & PARODD))
|
||||
lcr_h |= UART01x_LCRH_EPS;
|
||||
}
|
||||
if (uap->port.fifosize > 1)
|
||||
if (port->fifosize > 1)
|
||||
lcr_h |= UART01x_LCRH_FEN;
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/*
|
||||
* Update the per-port timeout.
|
||||
*/
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
uap->port.read_status_mask = UART01x_RSR_OE;
|
||||
port->read_status_mask = UART01x_RSR_OE;
|
||||
if (termios->c_iflag & INPCK)
|
||||
uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
|
||||
port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
|
||||
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||
uap->port.read_status_mask |= UART01x_RSR_BE;
|
||||
port->read_status_mask |= UART01x_RSR_BE;
|
||||
|
||||
/*
|
||||
* Characters to ignore
|
||||
*/
|
||||
uap->port.ignore_status_mask = 0;
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
|
||||
port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
|
||||
if (termios->c_iflag & IGNBRK) {
|
||||
uap->port.ignore_status_mask |= UART01x_RSR_BE;
|
||||
port->ignore_status_mask |= UART01x_RSR_BE;
|
||||
/*
|
||||
* If we're ignoring parity and break indicators,
|
||||
* ignore overruns too (for real raw support).
|
||||
*/
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
uap->port.ignore_status_mask |= UART01x_RSR_OE;
|
||||
port->ignore_status_mask |= UART01x_RSR_OE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore all characters if CREAD is not set.
|
||||
*/
|
||||
if ((termios->c_cflag & CREAD) == 0)
|
||||
uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX;
|
||||
port->ignore_status_mask |= UART_DUMMY_RSR_RX;
|
||||
|
||||
old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE;
|
||||
old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE;
|
||||
|
||||
if (UART_ENABLE_MS(port, termios->c_cflag))
|
||||
old_cr |= UART010_CR_MSIE;
|
||||
|
||||
/* Set baud rate */
|
||||
quot -= 1;
|
||||
writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM);
|
||||
writel(quot & 0xff, uap->port.membase + UART010_LCRL);
|
||||
writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM);
|
||||
writel(quot & 0xff, port->membase + UART010_LCRL);
|
||||
|
||||
/*
|
||||
* ----------v----------v----------v----------v-----
|
||||
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
|
||||
* ----------^----------^----------^----------^-----
|
||||
*/
|
||||
writel(lcr_h, uap->port.membase + UART010_LCRH);
|
||||
writel(old_cr, uap->port.membase + UART010_CR);
|
||||
writel(lcr_h, port->membase + UART010_LCRH);
|
||||
writel(old_cr, port->membase + UART010_CR);
|
||||
|
||||
spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
||||
|
@ -556,23 +551,22 @@ static struct uart_amba_port *amba_ports[UART_NR];
|
|||
|
||||
#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
|
||||
|
||||
static void pl010_console_putchar(struct uart_port *port, int ch)
|
||||
static void pl010_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int status;
|
||||
|
||||
do {
|
||||
status = readb(uap->port.membase + UART01x_FR);
|
||||
status = readb(port->membase + UART01x_FR);
|
||||
barrier();
|
||||
} while (!UART_TX_READY(status));
|
||||
writel(ch, uap->port.membase + UART01x_DR);
|
||||
writel(ch, port->membase + UART01x_DR);
|
||||
}
|
||||
|
||||
static void
|
||||
pl010_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_amba_port *uap = amba_ports[co->index];
|
||||
struct uart_port *port = &uap->port;
|
||||
unsigned int status, old_cr;
|
||||
|
||||
clk_enable(uap->clk);
|
||||
|
@ -580,20 +574,20 @@ pl010_console_write(struct console *co, const char *s, unsigned int count)
|
|||
/*
|
||||
* First save the CR then disable the interrupts
|
||||
*/
|
||||
old_cr = readb(uap->port.membase + UART010_CR);
|
||||
writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR);
|
||||
old_cr = readb(port->membase + UART010_CR);
|
||||
writel(UART01x_CR_UARTEN, port->membase + UART010_CR);
|
||||
|
||||
uart_console_write(&uap->port, s, count, pl010_console_putchar);
|
||||
uart_console_write(port, s, count, pl010_console_putchar);
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the TCR
|
||||
*/
|
||||
do {
|
||||
status = readb(uap->port.membase + UART01x_FR);
|
||||
status = readb(port->membase + UART01x_FR);
|
||||
barrier();
|
||||
} while (status & UART01x_FR_BUSY);
|
||||
writel(old_cr, uap->port.membase + UART010_CR);
|
||||
writel(old_cr, port->membase + UART010_CR);
|
||||
|
||||
clk_disable(uap->clk);
|
||||
}
|
||||
|
|
|
@ -2255,7 +2255,7 @@ static struct uart_amba_port *amba_ports[UART_NR];
|
|||
|
||||
#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
|
||||
|
||||
static void pl011_console_putchar(struct uart_port *port, int ch)
|
||||
static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
@ -2471,7 +2471,7 @@ static struct console amba_console = {
|
|||
|
||||
#define AMBA_CONSOLE (&amba_console)
|
||||
|
||||
static void qdf2400_e44_putc(struct uart_port *port, int c)
|
||||
static void qdf2400_e44_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
|
||||
cpu_relax();
|
||||
|
@ -2487,7 +2487,7 @@ static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned
|
|||
uart_console_write(&dev->port, s, n, qdf2400_e44_putc);
|
||||
}
|
||||
|
||||
static void pl011_putc(struct uart_port *port, int c)
|
||||
static void pl011_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
|
||||
cpu_relax();
|
||||
|
|
|
@ -413,7 +413,7 @@ static void apbuart_flush_fifo(struct uart_port *port)
|
|||
|
||||
#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
|
||||
|
||||
static void apbuart_console_putchar(struct uart_port *port, int ch)
|
||||
static void apbuart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
unsigned int status;
|
||||
do {
|
||||
|
|
|
@ -613,7 +613,7 @@ static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up)
|
|||
} while ((status & AR933X_UART_DATA_TX_CSR) == 0);
|
||||
}
|
||||
|
||||
static void ar933x_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void ar933x_uart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
|
|
@ -508,7 +508,7 @@ static int arc_serial_console_setup(struct console *co, char *options)
|
|||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static void arc_serial_console_putchar(struct uart_port *port, int ch)
|
||||
static void arc_serial_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (!(UART_GET_STATUS(port) & TXEMPTY))
|
||||
cpu_relax();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*
|
||||
* DMA support added by Chip Coldwell.
|
||||
*/
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -2540,7 +2541,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
|
||||
static void atmel_console_putchar(struct uart_port *port, int ch)
|
||||
static void atmel_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY))
|
||||
cpu_relax();
|
||||
|
@ -2672,6 +2673,30 @@ static struct console atmel_console = {
|
|||
.data = &atmel_uart,
|
||||
};
|
||||
|
||||
static void atmel_serial_early_write(struct console *con, const char *s,
|
||||
unsigned int n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, atmel_console_putchar);
|
||||
}
|
||||
|
||||
static int __init atmel_early_console_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = atmel_serial_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(atmel_serial, "atmel,at91rm9200-usart",
|
||||
atmel_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(atmel_serial, "atmel,at91sam9260-usart",
|
||||
atmel_early_console_setup);
|
||||
|
||||
#define ATMEL_CONSOLE_DEVICE (&atmel_console)
|
||||
|
||||
#else
|
||||
|
|
|
@ -681,7 +681,7 @@ static void wait_for_xmitr(struct uart_port *port)
|
|||
/*
|
||||
* output given char
|
||||
*/
|
||||
static void bcm_console_putchar(struct uart_port *port, int ch)
|
||||
static void bcm_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
bcm_uart_writel(port, ch, UART_FIFO_REG);
|
||||
|
|
|
@ -348,7 +348,7 @@ static const struct uart_ops uart_clps711x_ops = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
|
||||
static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
|
||||
static void uart_clps711x_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct clps711x_port *s = dev_get_drvdata(port->dev);
|
||||
u32 sysflg = 0;
|
||||
|
|
|
@ -381,7 +381,7 @@ static const struct uart_ops digicolor_uart_ops = {
|
|||
.request_port = digicolor_uart_request_port,
|
||||
};
|
||||
|
||||
static void digicolor_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void digicolor_uart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (digicolor_uart_tx_full(port))
|
||||
cpu_relax();
|
||||
|
|
|
@ -802,7 +802,7 @@ static void __init dz_init_ports(void)
|
|||
* restored. Welcome to the world of PDP-11!
|
||||
* -------------------------------------------------------------------
|
||||
*/
|
||||
static void dz_console_putchar(struct uart_port *uport, int ch)
|
||||
static void dz_console_putchar(struct uart_port *uport, unsigned char ch)
|
||||
{
|
||||
struct dz_port *dport = to_dport(uport);
|
||||
unsigned long flags;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
/*
|
||||
* Semihosting-based debug console
|
||||
*/
|
||||
static void smh_putc(struct uart_port *port, int c)
|
||||
static void smh_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
#ifdef CONFIG_ARM64
|
||||
asm volatile("mov x1, %0\n"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <linux/serial_core.h>
|
||||
#include <asm/sbi.h>
|
||||
|
||||
static void sbi_putc(struct uart_port *port, int c)
|
||||
static void sbi_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
sbi_console_putchar(c);
|
||||
}
|
||||
|
|
|
@ -157,27 +157,29 @@ static void linflex_stop_rx(struct uart_port *port)
|
|||
writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER);
|
||||
}
|
||||
|
||||
static void linflex_put_char(struct uart_port *sport, unsigned char c)
|
||||
{
|
||||
unsigned long status;
|
||||
|
||||
writeb(c, sport->membase + BDRL);
|
||||
|
||||
/* Waiting for data transmission completed. */
|
||||
while (((status = readl(sport->membase + UARTSR)) &
|
||||
LINFLEXD_UARTSR_DTFTFF) !=
|
||||
LINFLEXD_UARTSR_DTFTFF)
|
||||
;
|
||||
|
||||
writel(status | LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
|
||||
}
|
||||
|
||||
static inline void linflex_transmit_buffer(struct uart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->state->xmit;
|
||||
unsigned char c;
|
||||
unsigned long status;
|
||||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
c = xmit->buf[xmit->tail];
|
||||
writeb(c, sport->membase + BDRL);
|
||||
|
||||
/* Waiting for data transmission completed. */
|
||||
while (((status = readl(sport->membase + UARTSR)) &
|
||||
LINFLEXD_UARTSR_DTFTFF) !=
|
||||
LINFLEXD_UARTSR_DTFTFF)
|
||||
;
|
||||
|
||||
linflex_put_char(sport, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->icount.tx++;
|
||||
|
||||
writel(status | LINFLEXD_UARTSR_DTFTFF,
|
||||
sport->membase + UARTSR);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
@ -201,21 +203,11 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
|
|||
struct uart_port *sport = dev_id;
|
||||
struct circ_buf *xmit = &sport->state->xmit;
|
||||
unsigned long flags;
|
||||
unsigned long status;
|
||||
|
||||
spin_lock_irqsave(&sport->lock, flags);
|
||||
|
||||
if (sport->x_char) {
|
||||
writeb(sport->x_char, sport->membase + BDRL);
|
||||
|
||||
/* waiting for data transmission completed */
|
||||
while (((status = readl(sport->membase + UARTSR)) &
|
||||
LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF)
|
||||
;
|
||||
|
||||
writel(status | LINFLEXD_UARTSR_DTFTFF,
|
||||
sport->membase + UARTSR);
|
||||
|
||||
linflex_put_char(sport, sport->x_char);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -225,10 +217,6 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
linflex_transmit_buffer(sport);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(sport);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&sport->lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -565,7 +553,7 @@ static const struct uart_ops linflex_pops = {
|
|||
static struct uart_port *linflex_ports[UART_NR];
|
||||
|
||||
#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
|
||||
static void linflex_console_putchar(struct uart_port *port, int ch)
|
||||
static void linflex_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
unsigned long cr;
|
||||
|
||||
|
@ -590,7 +578,7 @@ static void linflex_console_putchar(struct uart_port *port, int ch)
|
|||
}
|
||||
}
|
||||
|
||||
static void linflex_earlycon_putchar(struct uart_port *port, int ch)
|
||||
static void linflex_earlycon_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
unsigned long flags;
|
||||
char *ret;
|
||||
|
|
|
@ -931,7 +931,8 @@ static void lpuart_rxint(struct lpuart_port *sport)
|
|||
sport->port.sysrq = 0;
|
||||
}
|
||||
|
||||
tty_insert_flip_char(port, rx, flg);
|
||||
if (tty_insert_flip_char(port, rx, flg) == 0)
|
||||
sport->port.icount.buf_overrun++;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -1024,7 +1025,8 @@ static void lpuart32_rxint(struct lpuart_port *sport)
|
|||
flg = TTY_OVERRUN;
|
||||
}
|
||||
|
||||
tty_insert_flip_char(port, rx, flg);
|
||||
if (tty_insert_flip_char(port, rx, flg) == 0)
|
||||
sport->port.icount.buf_overrun++;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -1116,7 +1118,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
|||
struct dma_chan *chan = sport->dma_rx_chan;
|
||||
struct circ_buf *ring = &sport->rx_ring;
|
||||
unsigned long flags;
|
||||
int count = 0;
|
||||
int count = 0, copied;
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
unsigned long sr = lpuart32_read(&sport->port, UARTSTAT);
|
||||
|
@ -1218,20 +1220,24 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
|||
if (ring->head < ring->tail) {
|
||||
count = sport->rx_sgl.length - ring->tail;
|
||||
|
||||
tty_insert_flip_string(port, ring->buf + ring->tail, count);
|
||||
copied = tty_insert_flip_string(port, ring->buf + ring->tail, count);
|
||||
if (copied != count)
|
||||
sport->port.icount.buf_overrun++;
|
||||
ring->tail = 0;
|
||||
sport->port.icount.rx += count;
|
||||
sport->port.icount.rx += copied;
|
||||
}
|
||||
|
||||
/* Finally we read data from tail to head */
|
||||
if (ring->tail < ring->head) {
|
||||
count = ring->head - ring->tail;
|
||||
tty_insert_flip_string(port, ring->buf + ring->tail, count);
|
||||
copied = tty_insert_flip_string(port, ring->buf + ring->tail, count);
|
||||
if (copied != count)
|
||||
sport->port.icount.buf_overrun++;
|
||||
/* Wrap ring->head if needed */
|
||||
if (ring->head >= sport->rx_sgl.length)
|
||||
ring->head = 0;
|
||||
ring->tail = ring->head;
|
||||
sport->port.icount.rx += count;
|
||||
sport->port.icount.rx += copied;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
@ -2327,13 +2333,13 @@ static const struct uart_ops lpuart32_pops = {
|
|||
static struct lpuart_port *lpuart_ports[UART_NR];
|
||||
|
||||
#ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE
|
||||
static void lpuart_console_putchar(struct uart_port *port, int ch)
|
||||
static void lpuart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TDRE);
|
||||
writeb(ch, port->membase + UARTDR);
|
||||
}
|
||||
|
||||
static void lpuart32_console_putchar(struct uart_port *port, int ch)
|
||||
static void lpuart32_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE);
|
||||
lpuart32_write(port, ch, UARTDATA);
|
||||
|
|
|
@ -455,9 +455,14 @@ static void imx_uart_stop_tx(struct uart_port *port)
|
|||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (sport->tx_state == SEND) {
|
||||
sport->tx_state = WAIT_AFTER_SEND;
|
||||
start_hrtimer_ms(&sport->trigger_stop_tx,
|
||||
|
||||
if (port->rs485.delay_rts_after_send > 0) {
|
||||
start_hrtimer_ms(&sport->trigger_stop_tx,
|
||||
port->rs485.delay_rts_after_send);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/* continue without any delay */
|
||||
}
|
||||
|
||||
if (sport->tx_state == WAIT_AFTER_RTS ||
|
||||
|
@ -698,9 +703,14 @@ static void imx_uart_start_tx(struct uart_port *port)
|
|||
imx_uart_stop_rx(port);
|
||||
|
||||
sport->tx_state = WAIT_AFTER_RTS;
|
||||
start_hrtimer_ms(&sport->trigger_start_tx,
|
||||
|
||||
if (port->rs485.delay_rts_before_send > 0) {
|
||||
start_hrtimer_ms(&sport->trigger_start_tx,
|
||||
port->rs485.delay_rts_before_send);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/* continue without any delay */
|
||||
}
|
||||
|
||||
if (sport->tx_state == WAIT_AFTER_SEND
|
||||
|
@ -1258,7 +1268,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
|
|||
}
|
||||
|
||||
#define TXTL_DEFAULT 2 /* reset default */
|
||||
#define RXTL_DEFAULT 1 /* reset default */
|
||||
#define RXTL_DEFAULT 8 /* 8 characters or aging timer */
|
||||
#define TXTL_DMA 8 /* DMA burst setting */
|
||||
#define RXTL_DMA 9 /* DMA burst setting */
|
||||
|
||||
|
@ -1958,7 +1968,7 @@ static const struct uart_ops imx_uart_pops = {
|
|||
static struct imx_port *imx_uart_ports[UART_NR];
|
||||
|
||||
#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
|
||||
static void imx_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#define UTS_TXFULL (1<<4) /* TxFIFO full */
|
||||
#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
|
||||
|
||||
static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
|
||||
static void imx_uart_console_early_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL)
|
||||
cpu_relax();
|
||||
|
|
|
@ -990,7 +990,7 @@ static struct zilog_layout * __init get_zs(int chip)
|
|||
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
|
||||
|
||||
#ifdef CONFIG_SERIAL_IP22_ZILOG_CONSOLE
|
||||
static void ip22zilog_put_char(struct uart_port *port, int ch)
|
||||
static void ip22zilog_put_char(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
int loops = ZS_PUT_CHAR_MAX_DELAY;
|
||||
|
|
|
@ -350,7 +350,7 @@ static void cls_assert_modem_signals(struct jsm_channel *ch)
|
|||
static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
|
||||
{
|
||||
int qleft = 0;
|
||||
u8 linestatus = 0;
|
||||
u8 linestatus;
|
||||
u8 error_mask = 0;
|
||||
u16 head;
|
||||
u16 tail;
|
||||
|
@ -365,8 +365,6 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
|
|||
head = ch->ch_r_head & RQUEUEMASK;
|
||||
tail = ch->ch_r_tail & RQUEUEMASK;
|
||||
|
||||
/* Get our cached LSR */
|
||||
linestatus = ch->ch_cached_lsr;
|
||||
ch->ch_cached_lsr = 0;
|
||||
|
||||
/* Store how much space we have left in the queue */
|
||||
|
@ -737,21 +735,7 @@ static void cls_param(struct jsm_channel *ch)
|
|||
if (ch->ch_c_cflag & CSTOPB)
|
||||
lcr |= UART_LCR_STOP;
|
||||
|
||||
switch (ch->ch_c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr |= UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr |= UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr |= UART_LCR_WLEN7;
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
lcr |= UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
lcr |= UART_LCR_WLEN(tty_get_char_size(ch->ch_c_cflag));
|
||||
|
||||
ier = readb(&ch->ch_cls_uart->ier);
|
||||
uart_lcr = readb(&ch->ch_cls_uart->lcr);
|
||||
|
|
|
@ -291,7 +291,8 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
|
|||
ch->ch_cached_lsr = 0;
|
||||
|
||||
/* Store how much space we have left in the queue */
|
||||
if ((qleft = tail - head - 1) < 0)
|
||||
qleft = tail - head - 1;
|
||||
if (qleft < 0)
|
||||
qleft += RQUEUEMASK + 1;
|
||||
|
||||
/*
|
||||
|
@ -1008,21 +1009,7 @@ static void neo_param(struct jsm_channel *ch)
|
|||
if (ch->ch_c_cflag & CSTOPB)
|
||||
lcr |= UART_LCR_STOP;
|
||||
|
||||
switch (ch->ch_c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr |= UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr |= UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr |= UART_LCR_WLEN7;
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
lcr |= UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
lcr |= UART_LCR_WLEN(tty_get_char_size(ch->ch_c_cflag));
|
||||
|
||||
ier = readb(&ch->ch_neo_uart->ier);
|
||||
uart_lcr = readb(&ch->ch_neo_uart->lcr);
|
||||
|
|
|
@ -749,7 +749,8 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
|
|||
int qleft;
|
||||
|
||||
/* Store how much space we have left in the queue */
|
||||
if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
|
||||
qleft = ch->ch_r_tail - ch->ch_r_head - 1;
|
||||
if (qleft < 0)
|
||||
qleft += RQUEUEMASK + 1;
|
||||
|
||||
/*
|
||||
|
|
|
@ -403,16 +403,16 @@ static int kgdboc_option_setup(char *opt)
|
|||
{
|
||||
if (!opt) {
|
||||
pr_err("config string not provided\n");
|
||||
return -EINVAL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strlen(opt) >= MAX_CONFIG_LEN) {
|
||||
pr_err("config string too long\n");
|
||||
return -ENOSPC;
|
||||
return 1;
|
||||
}
|
||||
strcpy(config, opt);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("kgdboc=", kgdboc_option_setup);
|
||||
|
|
|
@ -598,7 +598,7 @@ static const struct uart_ops lqasc_pops = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_LANTIQ_CONSOLE
|
||||
static void
|
||||
lqasc_console_putchar(struct uart_port *port, int ch)
|
||||
lqasc_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
int fifofree;
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ static void liteuart_timer(struct timer_list *t)
|
|||
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
|
||||
}
|
||||
|
||||
static void liteuart_putchar(struct uart_port *port, int ch)
|
||||
static void liteuart_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (litex_read8(port->membase + OFF_TXFULL))
|
||||
cpu_relax();
|
||||
|
|
|
@ -122,7 +122,7 @@ static void wait_for_xmit_ready(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
|
||||
static void lpc32xx_hsuart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
wait_for_xmit_ready(port);
|
||||
writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
|
||||
|
@ -276,10 +276,11 @@ static void __serial_lpc32xx_rx(struct uart_port *port)
|
|||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static void serial_lpc32xx_stop_tx(struct uart_port *port);
|
||||
|
||||
static void __serial_lpc32xx_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int tmp;
|
||||
|
||||
if (port->x_char) {
|
||||
writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
|
||||
|
@ -306,11 +307,8 @@ static void __serial_lpc32xx_tx(struct uart_port *port)
|
|||
uart_write_wakeup(port);
|
||||
|
||||
exit_tx:
|
||||
if (uart_circ_empty(xmit)) {
|
||||
tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
|
||||
tmp &= ~LPC32XX_HSU_TX_INT_EN;
|
||||
writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
|
||||
}
|
||||
if (uart_circ_empty(xmit))
|
||||
serial_lpc32xx_stop_tx(port);
|
||||
}
|
||||
|
||||
static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
|
||||
|
|
|
@ -554,7 +554,6 @@ static void max3100_shutdown(struct uart_port *port)
|
|||
del_timer_sync(&s->timer);
|
||||
|
||||
if (s->workqueue) {
|
||||
flush_workqueue(s->workqueue);
|
||||
destroy_workqueue(s->workqueue);
|
||||
s->workqueue = NULL;
|
||||
}
|
||||
|
|
|
@ -338,7 +338,7 @@ static void mcf_tx_chars(struct mcf_uart *pp)
|
|||
}
|
||||
|
||||
while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
|
||||
if (xmit->head == xmit->tail)
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
|
||||
|
@ -348,9 +348,8 @@ static void mcf_tx_chars(struct mcf_uart *pp)
|
|||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (xmit->head == xmit->tail) {
|
||||
pp->imr &= ~MCFUART_UIR_TXREADY;
|
||||
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
||||
if (uart_circ_empty(xmit)) {
|
||||
mcf_stop_tx(port);
|
||||
/* Disable TX to negate RTS automatically */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED)
|
||||
writeb(MCFUART_UCR_TXDISABLE,
|
||||
|
|
|
@ -513,7 +513,7 @@ static void meson_uart_enable_tx_engine(struct uart_port *port)
|
|||
writel(val, port->membase + AML_UART_CONTROL);
|
||||
}
|
||||
|
||||
static void meson_console_putchar(struct uart_port *port, int ch)
|
||||
static void meson_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
|
|
@ -400,7 +400,7 @@ static const struct uart_ops mlb_usio_ops = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_MILBEAUT_USIO_CONSOLE
|
||||
|
||||
static void mlb_usio_console_putchar(struct uart_port *port, int c)
|
||||
static void mlb_usio_console_putchar(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (!(readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TDRE))
|
||||
cpu_relax();
|
||||
|
|
|
@ -83,11 +83,11 @@ static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port);
|
|||
|
||||
struct psc_ops {
|
||||
void (*fifo_init)(struct uart_port *port);
|
||||
int (*raw_rx_rdy)(struct uart_port *port);
|
||||
int (*raw_tx_rdy)(struct uart_port *port);
|
||||
int (*rx_rdy)(struct uart_port *port);
|
||||
int (*tx_rdy)(struct uart_port *port);
|
||||
int (*tx_empty)(struct uart_port *port);
|
||||
unsigned int (*raw_rx_rdy)(struct uart_port *port);
|
||||
unsigned int (*raw_tx_rdy)(struct uart_port *port);
|
||||
unsigned int (*rx_rdy)(struct uart_port *port);
|
||||
unsigned int (*tx_rdy)(struct uart_port *port);
|
||||
unsigned int (*tx_empty)(struct uart_port *port);
|
||||
void (*stop_rx)(struct uart_port *port);
|
||||
void (*start_tx)(struct uart_port *port);
|
||||
void (*stop_tx)(struct uart_port *port);
|
||||
|
@ -203,34 +203,34 @@ static void mpc52xx_psc_fifo_init(struct uart_port *port)
|
|||
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
|
||||
static unsigned int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_status)
|
||||
& MPC52xx_PSC_SR_RXRDY;
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
|
||||
static unsigned int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_status)
|
||||
& MPC52xx_PSC_SR_TXRDY;
|
||||
}
|
||||
|
||||
|
||||
static int mpc52xx_psc_rx_rdy(struct uart_port *port)
|
||||
static unsigned int mpc52xx_psc_rx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_isr)
|
||||
& port->read_status_mask
|
||||
& MPC52xx_PSC_IMR_RXRDY;
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_tx_rdy(struct uart_port *port)
|
||||
static unsigned int mpc52xx_psc_tx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_isr)
|
||||
& port->read_status_mask
|
||||
& MPC52xx_PSC_IMR_TXRDY;
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_tx_empty(struct uart_port *port)
|
||||
static unsigned int mpc52xx_psc_tx_empty(struct uart_port *port)
|
||||
{
|
||||
u16 sts = in_be16(&PSC(port)->mpc52xx_psc_status);
|
||||
|
||||
|
@ -1365,7 +1365,7 @@ static const struct uart_ops mpc52xx_uart_ops = {
|
|||
/* Interrupt handling */
|
||||
/* ======================================================================== */
|
||||
|
||||
static inline int
|
||||
static inline unsigned int
|
||||
mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
|
|
@ -432,7 +432,7 @@ static const struct uart_ops mps2_uart_pops = {
|
|||
static DEFINE_IDR(ports_idr);
|
||||
|
||||
#ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE
|
||||
static void mps2_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void mps2_uart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)
|
||||
cpu_relax();
|
||||
|
@ -484,7 +484,7 @@ static struct console mps2_uart_console = {
|
|||
|
||||
#define MPS2_SERIAL_CONSOLE (&mps2_uart_console)
|
||||
|
||||
static void mps2_early_putchar(struct uart_port *port, int ch)
|
||||
static void mps2_early_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (readb(port->membase + UARTn_STATE) & UARTn_STATE_TX_FULL)
|
||||
cpu_relax();
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
|
@ -68,12 +70,36 @@
|
|||
#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR \
|
||||
| STAT_PAR_ERR | STAT_OVR_ERR)
|
||||
|
||||
/*
|
||||
* Marvell Armada 3700 Functional Specifications describes that bit 21 of UART
|
||||
* Clock Control register controls UART1 and bit 20 controls UART2. But in
|
||||
* reality bit 21 controls UART2 and bit 20 controls UART1. This seems to be an
|
||||
* error in Marvell's documentation. Hence following CLK_DIS macros are swapped.
|
||||
*/
|
||||
|
||||
#define UART_BRDV 0x10
|
||||
/* These bits are located in UART1 address space and control UART2 */
|
||||
#define UART2_CLK_DIS BIT(21)
|
||||
/* These bits are located in UART1 address space and control UART1 */
|
||||
#define UART1_CLK_DIS BIT(20)
|
||||
/* These bits are located in UART1 address space and control both UARTs */
|
||||
#define CLK_NO_XTAL BIT(19)
|
||||
#define CLK_TBG_DIV1_SHIFT 15
|
||||
#define CLK_TBG_DIV1_MASK 0x7
|
||||
#define CLK_TBG_DIV1_MAX 6
|
||||
#define CLK_TBG_DIV2_SHIFT 12
|
||||
#define CLK_TBG_DIV2_MASK 0x7
|
||||
#define CLK_TBG_DIV2_MAX 6
|
||||
#define CLK_TBG_SEL_SHIFT 10
|
||||
#define CLK_TBG_SEL_MASK 0x3
|
||||
/* These bits are located in both UARTs address space */
|
||||
#define BRDV_BAUD_MASK 0x3FF
|
||||
#define BRDV_BAUD_MAX BRDV_BAUD_MASK
|
||||
|
||||
#define UART_OSAMP 0x14
|
||||
#define OSAMP_DEFAULT_DIVISOR 16
|
||||
#define OSAMP_DIVISORS_MASK 0x3F3F3F3F
|
||||
#define OSAMP_MAX_DIVISOR 63
|
||||
|
||||
#define MVEBU_NR_UARTS 2
|
||||
|
||||
|
@ -153,6 +179,8 @@ static struct mvebu_uart *to_mvuart(struct uart_port *port)
|
|||
|
||||
static struct uart_port mvebu_uart_ports[MVEBU_NR_UARTS];
|
||||
|
||||
static DEFINE_SPINLOCK(mvebu_uart_lock);
|
||||
|
||||
/* Core UART Driver Operations */
|
||||
static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
|
@ -445,31 +473,79 @@ static void mvebu_uart_shutdown(struct uart_port *port)
|
|||
static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
|
||||
{
|
||||
unsigned int d_divisor, m_divisor;
|
||||
unsigned long flags;
|
||||
u32 brdv, osamp;
|
||||
|
||||
if (!port->uartclk)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* The baudrate is derived from the UART clock thanks to two divisors:
|
||||
* > D ("baud generator"): can divide the clock from 2 to 2^10 - 1.
|
||||
* > M ("fractional divisor"): allows a better accuracy for
|
||||
* baudrates higher than 230400.
|
||||
* The baudrate is derived from the UART clock thanks to divisors:
|
||||
* > d1 * d2 ("TBG divisors"): can divide only TBG clock from 1 to 6
|
||||
* > D ("baud generator"): can divide the clock from 1 to 1023
|
||||
* > M ("fractional divisor"): allows a better accuracy (from 1 to 63)
|
||||
*
|
||||
* As the derivation of M is rather complicated, the code sticks to its
|
||||
* default value (x16) when all the prescalers are zeroed, and only
|
||||
* makes use of D to configure the desired baudrate.
|
||||
* Exact formulas for calculating baudrate:
|
||||
*
|
||||
* with default x16 scheme:
|
||||
* baudrate = xtal / (d * 16)
|
||||
* baudrate = tbg / (d1 * d2 * d * 16)
|
||||
*
|
||||
* with fractional divisor:
|
||||
* baudrate = 10 * xtal / (d * (3 * (m1 + m2) + 2 * (m3 + m4)))
|
||||
* baudrate = 10 * tbg / (d1*d2 * d * (3 * (m1 + m2) + 2 * (m3 + m4)))
|
||||
*
|
||||
* Oversampling value:
|
||||
* osamp = (m1 << 0) | (m2 << 8) | (m3 << 16) | (m4 << 24);
|
||||
*
|
||||
* Where m1 controls number of clock cycles per bit for bits 1,2,3;
|
||||
* m2 for bits 4,5,6; m3 for bits 7,8 and m4 for bits 9,10.
|
||||
*
|
||||
* To simplify baudrate setup set all the M prescalers to the same
|
||||
* value. For baudrates 9600 Bd and higher, it is enough to use the
|
||||
* default (x16) divisor or fractional divisor with M = 63, so there
|
||||
* is no need to use real fractional support (where the M prescalers
|
||||
* are not equal).
|
||||
*
|
||||
* When all the M prescalers are zeroed then default (x16) divisor is
|
||||
* used. Default x16 scheme is more stable than M (fractional divisor),
|
||||
* so use M only when D divisor is not enough to derive baudrate.
|
||||
*
|
||||
* Member port->uartclk is either xtal clock rate or TBG clock rate
|
||||
* divided by (d1 * d2). So d1 and d2 are already set by the UART clock
|
||||
* driver (and UART driver itself cannot change them). Moreover they are
|
||||
* shared between both UARTs.
|
||||
*/
|
||||
|
||||
m_divisor = OSAMP_DEFAULT_DIVISOR;
|
||||
d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
|
||||
|
||||
if (d_divisor > BRDV_BAUD_MAX) {
|
||||
/*
|
||||
* Experiments show that small M divisors are unstable.
|
||||
* Use maximal possible M = 63 and calculate D divisor.
|
||||
*/
|
||||
m_divisor = OSAMP_MAX_DIVISOR;
|
||||
d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor);
|
||||
}
|
||||
|
||||
if (d_divisor < 1)
|
||||
d_divisor = 1;
|
||||
else if (d_divisor > BRDV_BAUD_MAX)
|
||||
d_divisor = BRDV_BAUD_MAX;
|
||||
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
brdv = readl(port->membase + UART_BRDV);
|
||||
brdv &= ~BRDV_BAUD_MASK;
|
||||
brdv |= d_divisor;
|
||||
writel(brdv, port->membase + UART_BRDV);
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
|
||||
osamp = readl(port->membase + UART_OSAMP);
|
||||
osamp &= ~OSAMP_DIVISORS_MASK;
|
||||
if (m_divisor != OSAMP_DEFAULT_DIVISOR)
|
||||
osamp |= (m_divisor << 0) | (m_divisor << 8) |
|
||||
(m_divisor << 16) | (m_divisor << 24);
|
||||
writel(osamp, port->membase + UART_OSAMP);
|
||||
|
||||
return 0;
|
||||
|
@ -499,14 +575,16 @@ static void mvebu_uart_set_termios(struct uart_port *port,
|
|||
port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR;
|
||||
|
||||
/*
|
||||
* Maximal divisor is 1023 * 16 when using default (x16) scheme.
|
||||
* Maximum achievable frequency with simple baudrate divisor is 230400.
|
||||
* Since the error per bit frame would be of more than 15%, achieving
|
||||
* higher frequencies would require to implement the fractional divisor
|
||||
* feature.
|
||||
* Maximal divisor is 1023 and maximal fractional divisor is 63. And
|
||||
* experiments show that baudrates above 1/80 of parent clock rate are
|
||||
* not stable. So disallow baudrates above 1/80 of the parent clock
|
||||
* rate. If port->uartclk is not available, then
|
||||
* mvebu_uart_baud_rate_set() fails, so values min_baud and max_baud
|
||||
* in this case do not matter.
|
||||
*/
|
||||
min_baud = DIV_ROUND_UP(port->uartclk, 1023 * 16);
|
||||
max_baud = 230400;
|
||||
min_baud = DIV_ROUND_UP(port->uartclk, BRDV_BAUD_MAX *
|
||||
OSAMP_MAX_DIVISOR);
|
||||
max_baud = port->uartclk / 80;
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
|
||||
if (mvebu_uart_baud_rate_set(port, baud)) {
|
||||
|
@ -598,7 +676,7 @@ static const struct uart_ops mvebu_uart_ops = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_MVEBU_CONSOLE
|
||||
/* Early Console */
|
||||
static void mvebu_uart_putc(struct uart_port *port, int c)
|
||||
static void mvebu_uart_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned int st;
|
||||
|
||||
|
@ -659,7 +737,7 @@ static void wait_for_xmite(struct uart_port *port)
|
|||
(val & STAT_TX_EMP), 1, 10000);
|
||||
}
|
||||
|
||||
static void mvebu_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void mvebu_uart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
writel(ch, port->membase + UART_TSH(port));
|
||||
|
@ -762,6 +840,7 @@ static int mvebu_uart_suspend(struct device *dev)
|
|||
{
|
||||
struct mvebu_uart *mvuart = dev_get_drvdata(dev);
|
||||
struct uart_port *port = mvuart->port;
|
||||
unsigned long flags;
|
||||
|
||||
uart_suspend_port(&mvebu_uart_driver, port);
|
||||
|
||||
|
@ -770,7 +849,9 @@ static int mvebu_uart_suspend(struct device *dev)
|
|||
mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port));
|
||||
mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port));
|
||||
mvuart->pm_regs.stat = readl(port->membase + UART_STAT);
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV);
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP);
|
||||
|
||||
device_set_wakeup_enable(dev, true);
|
||||
|
@ -782,13 +863,16 @@ static int mvebu_uart_resume(struct device *dev)
|
|||
{
|
||||
struct mvebu_uart *mvuart = dev_get_drvdata(dev);
|
||||
struct uart_port *port = mvuart->port;
|
||||
unsigned long flags;
|
||||
|
||||
writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port));
|
||||
writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port));
|
||||
writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port));
|
||||
writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port));
|
||||
writel(mvuart->pm_regs.stat, port->membase + UART_STAT);
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV);
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP);
|
||||
|
||||
uart_resume_port(&mvebu_uart_driver, port);
|
||||
|
@ -972,6 +1056,477 @@ static struct platform_driver mvebu_uart_platform_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
/* This code is based on clk-fixed-factor.c driver and modified. */
|
||||
|
||||
struct mvebu_uart_clock {
|
||||
struct clk_hw clk_hw;
|
||||
int clock_idx;
|
||||
u32 pm_context_reg1;
|
||||
u32 pm_context_reg2;
|
||||
};
|
||||
|
||||
struct mvebu_uart_clock_base {
|
||||
struct mvebu_uart_clock clocks[2];
|
||||
unsigned int parent_rates[5];
|
||||
int parent_idx;
|
||||
unsigned int div;
|
||||
void __iomem *reg1;
|
||||
void __iomem *reg2;
|
||||
bool configured;
|
||||
};
|
||||
|
||||
#define PARENT_CLOCK_XTAL 4
|
||||
|
||||
#define to_uart_clock(hw) container_of(hw, struct mvebu_uart_clock, clk_hw)
|
||||
#define to_uart_clock_base(uart_clock) container_of(uart_clock, \
|
||||
struct mvebu_uart_clock_base, clocks[uart_clock->clock_idx])
|
||||
|
||||
static int mvebu_uart_clock_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
unsigned int prev_clock_idx, prev_clock_rate, prev_d1d2;
|
||||
unsigned int parent_clock_idx, parent_clock_rate;
|
||||
unsigned long flags;
|
||||
unsigned int d1, d2;
|
||||
u64 divisor;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* This function just reconfigures UART Clock Control register (located
|
||||
* in UART1 address space which controls both UART1 and UART2) to
|
||||
* selected UART base clock and recalculates current UART1/UART2
|
||||
* divisors in their address spaces, so that final baudrate will not be
|
||||
* changed by switching UART parent clock. This is required for
|
||||
* otherwise kernel's boot log stops working - we need to ensure that
|
||||
* UART baudrate does not change during this setup. It is a one time
|
||||
* operation, it will execute only once and set `configured` to true,
|
||||
* and be skipped on subsequent calls. Because this UART Clock Control
|
||||
* register (UART_BRDV) is shared between UART1 baudrate function,
|
||||
* UART1 clock selector and UART2 clock selector, every access to
|
||||
* UART_BRDV (reg1) needs to be protected by a lock.
|
||||
*/
|
||||
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
|
||||
if (uart_clock_base->configured) {
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
parent_clock_idx = uart_clock_base->parent_idx;
|
||||
parent_clock_rate = uart_clock_base->parent_rates[parent_clock_idx];
|
||||
|
||||
val = readl(uart_clock_base->reg1);
|
||||
|
||||
if (uart_clock_base->div > CLK_TBG_DIV1_MAX) {
|
||||
d1 = CLK_TBG_DIV1_MAX;
|
||||
d2 = uart_clock_base->div / CLK_TBG_DIV1_MAX;
|
||||
} else {
|
||||
d1 = uart_clock_base->div;
|
||||
d2 = 1;
|
||||
}
|
||||
|
||||
if (val & CLK_NO_XTAL) {
|
||||
prev_clock_idx = (val >> CLK_TBG_SEL_SHIFT) & CLK_TBG_SEL_MASK;
|
||||
prev_d1d2 = ((val >> CLK_TBG_DIV1_SHIFT) & CLK_TBG_DIV1_MASK) *
|
||||
((val >> CLK_TBG_DIV2_SHIFT) & CLK_TBG_DIV2_MASK);
|
||||
} else {
|
||||
prev_clock_idx = PARENT_CLOCK_XTAL;
|
||||
prev_d1d2 = 1;
|
||||
}
|
||||
|
||||
/* Note that uart_clock_base->parent_rates[i] may not be available */
|
||||
prev_clock_rate = uart_clock_base->parent_rates[prev_clock_idx];
|
||||
|
||||
/* Recalculate UART1 divisor so UART1 baudrate does not change */
|
||||
if (prev_clock_rate) {
|
||||
divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
|
||||
parent_clock_rate * prev_d1d2,
|
||||
prev_clock_rate * d1 * d2);
|
||||
if (divisor < 1)
|
||||
divisor = 1;
|
||||
else if (divisor > BRDV_BAUD_MAX)
|
||||
divisor = BRDV_BAUD_MAX;
|
||||
val = (val & ~BRDV_BAUD_MASK) | divisor;
|
||||
}
|
||||
|
||||
if (parent_clock_idx != PARENT_CLOCK_XTAL) {
|
||||
/* Do not use XTAL, select TBG clock and TBG d1 * d2 divisors */
|
||||
val |= CLK_NO_XTAL;
|
||||
val &= ~(CLK_TBG_DIV1_MASK << CLK_TBG_DIV1_SHIFT);
|
||||
val |= d1 << CLK_TBG_DIV1_SHIFT;
|
||||
val &= ~(CLK_TBG_DIV2_MASK << CLK_TBG_DIV2_SHIFT);
|
||||
val |= d2 << CLK_TBG_DIV2_SHIFT;
|
||||
val &= ~(CLK_TBG_SEL_MASK << CLK_TBG_SEL_SHIFT);
|
||||
val |= parent_clock_idx << CLK_TBG_SEL_SHIFT;
|
||||
} else {
|
||||
/* Use XTAL, TBG bits are then ignored */
|
||||
val &= ~CLK_NO_XTAL;
|
||||
}
|
||||
|
||||
writel(val, uart_clock_base->reg1);
|
||||
|
||||
/* Recalculate UART2 divisor so UART2 baudrate does not change */
|
||||
if (prev_clock_rate) {
|
||||
val = readl(uart_clock_base->reg2);
|
||||
divisor = DIV_U64_ROUND_CLOSEST((u64)(val & BRDV_BAUD_MASK) *
|
||||
parent_clock_rate * prev_d1d2,
|
||||
prev_clock_rate * d1 * d2);
|
||||
if (divisor < 1)
|
||||
divisor = 1;
|
||||
else if (divisor > BRDV_BAUD_MAX)
|
||||
divisor = BRDV_BAUD_MAX;
|
||||
val = (val & ~BRDV_BAUD_MASK) | divisor;
|
||||
writel(val, uart_clock_base->reg2);
|
||||
}
|
||||
|
||||
uart_clock_base->configured = true;
|
||||
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_uart_clock_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
|
||||
val = readl(uart_clock_base->reg1);
|
||||
|
||||
if (uart_clock->clock_idx == 0)
|
||||
val &= ~UART1_CLK_DIS;
|
||||
else
|
||||
val &= ~UART2_CLK_DIS;
|
||||
|
||||
writel(val, uart_clock_base->reg1);
|
||||
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mvebu_uart_clock_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
|
||||
val = readl(uart_clock_base->reg1);
|
||||
|
||||
if (uart_clock->clock_idx == 0)
|
||||
val |= UART1_CLK_DIS;
|
||||
else
|
||||
val |= UART2_CLK_DIS;
|
||||
|
||||
writel(val, uart_clock_base->reg1);
|
||||
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_uart_clock_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
u32 val;
|
||||
|
||||
val = readl(uart_clock_base->reg1);
|
||||
|
||||
if (uart_clock->clock_idx == 0)
|
||||
return !(val & UART1_CLK_DIS);
|
||||
else
|
||||
return !(val & UART2_CLK_DIS);
|
||||
}
|
||||
|
||||
static int mvebu_uart_clock_save_context(struct clk_hw *hw)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
uart_clock->pm_context_reg1 = readl(uart_clock_base->reg1);
|
||||
uart_clock->pm_context_reg2 = readl(uart_clock_base->reg2);
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mvebu_uart_clock_restore_context(struct clk_hw *hw)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mvebu_uart_lock, flags);
|
||||
writel(uart_clock->pm_context_reg1, uart_clock_base->reg1);
|
||||
writel(uart_clock->pm_context_reg2, uart_clock_base->reg2);
|
||||
spin_unlock_irqrestore(&mvebu_uart_lock, flags);
|
||||
}
|
||||
|
||||
static unsigned long mvebu_uart_clock_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
|
||||
return parent_rate / uart_clock_base->div;
|
||||
}
|
||||
|
||||
static long mvebu_uart_clock_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct mvebu_uart_clock *uart_clock = to_uart_clock(hw);
|
||||
struct mvebu_uart_clock_base *uart_clock_base =
|
||||
to_uart_clock_base(uart_clock);
|
||||
|
||||
return *parent_rate / uart_clock_base->div;
|
||||
}
|
||||
|
||||
static int mvebu_uart_clock_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
/*
|
||||
* We must report success but we can do so unconditionally because
|
||||
* mvebu_uart_clock_round_rate returns values that ensure this call is a
|
||||
* nop.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops mvebu_uart_clock_ops = {
|
||||
.prepare = mvebu_uart_clock_prepare,
|
||||
.enable = mvebu_uart_clock_enable,
|
||||
.disable = mvebu_uart_clock_disable,
|
||||
.is_enabled = mvebu_uart_clock_is_enabled,
|
||||
.save_context = mvebu_uart_clock_save_context,
|
||||
.restore_context = mvebu_uart_clock_restore_context,
|
||||
.round_rate = mvebu_uart_clock_round_rate,
|
||||
.set_rate = mvebu_uart_clock_set_rate,
|
||||
.recalc_rate = mvebu_uart_clock_recalc_rate,
|
||||
};
|
||||
|
||||
static int mvebu_uart_clock_register(struct device *dev,
|
||||
struct mvebu_uart_clock *uart_clock,
|
||||
const char *name,
|
||||
const char *parent_name)
|
||||
{
|
||||
struct clk_init_data init = { };
|
||||
|
||||
uart_clock->clk_hw.init = &init;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &mvebu_uart_clock_ops;
|
||||
init.flags = 0;
|
||||
init.num_parents = 1;
|
||||
init.parent_names = &parent_name;
|
||||
|
||||
return devm_clk_hw_register(dev, &uart_clock->clk_hw);
|
||||
}
|
||||
|
||||
static int mvebu_uart_clock_probe(struct platform_device *pdev)
|
||||
{
|
||||
static const char *const uart_clk_names[] = { "uart_1", "uart_2" };
|
||||
static const char *const parent_clk_names[] = { "TBG-A-P", "TBG-B-P",
|
||||
"TBG-A-S", "TBG-B-S",
|
||||
"xtal" };
|
||||
struct clk *parent_clks[ARRAY_SIZE(parent_clk_names)];
|
||||
struct mvebu_uart_clock_base *uart_clock_base;
|
||||
struct clk_hw_onecell_data *hw_clk_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
int i, parent_clk_idx, ret;
|
||||
unsigned long div, rate;
|
||||
struct resource *res;
|
||||
unsigned int d1, d2;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(uart_clk_names) !=
|
||||
ARRAY_SIZE(uart_clock_base->clocks));
|
||||
BUILD_BUG_ON(ARRAY_SIZE(parent_clk_names) !=
|
||||
ARRAY_SIZE(uart_clock_base->parent_rates));
|
||||
|
||||
uart_clock_base = devm_kzalloc(dev,
|
||||
sizeof(*uart_clock_base),
|
||||
GFP_KERNEL);
|
||||
if (!uart_clock_base)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "Couldn't get first register\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* UART Clock Control register (reg1 / UART_BRDV) is in the address
|
||||
* space of UART1 (standard UART variant), controls parent clock and
|
||||
* dividers for both UART1 and UART2 and is supplied via DT as the first
|
||||
* resource. Therefore use ioremap() rather than ioremap_resource() to
|
||||
* avoid conflicts with UART1 driver. Access to UART_BRDV is protected
|
||||
* by a lock shared between clock and UART driver.
|
||||
*/
|
||||
uart_clock_base->reg1 = devm_ioremap(dev, res->start,
|
||||
resource_size(res));
|
||||
if (!uart_clock_base->reg1)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "Couldn't get second register\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* UART 2 Baud Rate Divisor register (reg2 / UART_BRDV) is in address
|
||||
* space of UART2 (extended UART variant), controls only one UART2
|
||||
* specific divider and is supplied via DT as second resource.
|
||||
* Therefore use ioremap() rather than ioremap_resource() to avoid
|
||||
* conflicts with UART2 driver. Access to UART_BRDV is protected by a
|
||||
* by lock shared between clock and UART driver.
|
||||
*/
|
||||
uart_clock_base->reg2 = devm_ioremap(dev, res->start,
|
||||
resource_size(res));
|
||||
if (!uart_clock_base->reg2)
|
||||
return -ENOMEM;
|
||||
|
||||
hw_clk_data = devm_kzalloc(dev,
|
||||
struct_size(hw_clk_data, hws,
|
||||
ARRAY_SIZE(uart_clk_names)),
|
||||
GFP_KERNEL);
|
||||
if (!hw_clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
hw_clk_data->num = ARRAY_SIZE(uart_clk_names);
|
||||
for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
|
||||
hw_clk_data->hws[i] = &uart_clock_base->clocks[i].clk_hw;
|
||||
uart_clock_base->clocks[i].clock_idx = i;
|
||||
}
|
||||
|
||||
parent_clk_idx = -1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
|
||||
parent_clks[i] = devm_clk_get(dev, parent_clk_names[i]);
|
||||
if (IS_ERR(parent_clks[i])) {
|
||||
if (PTR_ERR(parent_clks[i]) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_warn(dev, "Couldn't get the parent clock %s: %ld\n",
|
||||
parent_clk_names[i], PTR_ERR(parent_clks[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(parent_clks[i]);
|
||||
if (ret) {
|
||||
dev_warn(dev, "Couldn't enable parent clock %s: %d\n",
|
||||
parent_clk_names[i], ret);
|
||||
continue;
|
||||
}
|
||||
rate = clk_get_rate(parent_clks[i]);
|
||||
uart_clock_base->parent_rates[i] = rate;
|
||||
|
||||
if (i != PARENT_CLOCK_XTAL) {
|
||||
/*
|
||||
* Calculate the smallest TBG d1 and d2 divisors that
|
||||
* still can provide 9600 baudrate.
|
||||
*/
|
||||
d1 = DIV_ROUND_UP(rate, 9600 * OSAMP_MAX_DIVISOR *
|
||||
BRDV_BAUD_MAX);
|
||||
if (d1 < 1)
|
||||
d1 = 1;
|
||||
else if (d1 > CLK_TBG_DIV1_MAX)
|
||||
d1 = CLK_TBG_DIV1_MAX;
|
||||
|
||||
d2 = DIV_ROUND_UP(rate, 9600 * OSAMP_MAX_DIVISOR *
|
||||
BRDV_BAUD_MAX * d1);
|
||||
if (d2 < 1)
|
||||
d2 = 1;
|
||||
else if (d2 > CLK_TBG_DIV2_MAX)
|
||||
d2 = CLK_TBG_DIV2_MAX;
|
||||
} else {
|
||||
/*
|
||||
* When UART clock uses XTAL clock as a source then it
|
||||
* is not possible to use d1 and d2 divisors.
|
||||
*/
|
||||
d1 = d2 = 1;
|
||||
}
|
||||
|
||||
/* Skip clock source which cannot provide 9600 baudrate */
|
||||
if (rate > 9600 * OSAMP_MAX_DIVISOR * BRDV_BAUD_MAX * d1 * d2)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Choose TBG clock source with the smallest divisors. Use XTAL
|
||||
* clock source only in case TBG is not available as XTAL cannot
|
||||
* be used for baudrates higher than 230400.
|
||||
*/
|
||||
if (parent_clk_idx == -1 ||
|
||||
(i != PARENT_CLOCK_XTAL && div > d1 * d2)) {
|
||||
parent_clk_idx = i;
|
||||
div = d1 * d2;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(parent_clk_names); i++) {
|
||||
if (i == parent_clk_idx || IS_ERR(parent_clks[i]))
|
||||
continue;
|
||||
clk_disable_unprepare(parent_clks[i]);
|
||||
devm_clk_put(dev, parent_clks[i]);
|
||||
}
|
||||
|
||||
if (parent_clk_idx == -1) {
|
||||
dev_err(dev, "No usable parent clock\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
uart_clock_base->parent_idx = parent_clk_idx;
|
||||
uart_clock_base->div = div;
|
||||
|
||||
dev_notice(dev, "Using parent clock %s as base UART clock\n",
|
||||
__clk_get_name(parent_clks[parent_clk_idx]));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uart_clk_names); i++) {
|
||||
ret = mvebu_uart_clock_register(dev,
|
||||
&uart_clock_base->clocks[i],
|
||||
uart_clk_names[i],
|
||||
__clk_get_name(parent_clks[parent_clk_idx]));
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't register UART clock %d: %d\n",
|
||||
i, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
|
||||
hw_clk_data);
|
||||
}
|
||||
|
||||
static const struct of_device_id mvebu_uart_clock_of_match[] = {
|
||||
{ .compatible = "marvell,armada-3700-uart-clock", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver mvebu_uart_clock_platform_driver = {
|
||||
.probe = mvebu_uart_clock_probe,
|
||||
.driver = {
|
||||
.name = "mvebu-uart-clock",
|
||||
.of_match_table = mvebu_uart_clock_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mvebu_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -980,10 +1535,19 @@ static int __init mvebu_uart_init(void)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&mvebu_uart_platform_driver);
|
||||
if (ret)
|
||||
ret = platform_driver_register(&mvebu_uart_clock_platform_driver);
|
||||
if (ret) {
|
||||
uart_unregister_driver(&mvebu_uart_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
ret = platform_driver_register(&mvebu_uart_platform_driver);
|
||||
if (ret) {
|
||||
platform_driver_unregister(&mvebu_uart_clock_platform_driver);
|
||||
uart_unregister_driver(&mvebu_uart_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(mvebu_uart_init);
|
||||
|
|
|
@ -1305,7 +1305,7 @@ static const struct uart_ops mxs_auart_ops = {
|
|||
static struct mxs_auart_port *auart_port[MXS_AUART_PORTS];
|
||||
|
||||
#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
|
||||
static void mxs_auart_console_putchar(struct uart_port *port, int ch)
|
||||
static void mxs_auart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct mxs_auart_port *s = to_auart_port(port);
|
||||
unsigned int to = 1000;
|
||||
|
|
|
@ -808,21 +808,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
cval = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
cval = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
cval = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
cval = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
cval |= UART_LCR_STOP;
|
||||
|
@ -1194,7 +1180,7 @@ static void omap_serial_early_out(struct uart_port *port, int offset,
|
|||
writew(value, port->membase + offset);
|
||||
}
|
||||
|
||||
static void omap_serial_early_putc(struct uart_port *port, int c)
|
||||
static void omap_serial_early_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
|
@ -1238,7 +1224,7 @@ static struct uart_omap_port *serial_omap_console_ports[OMAP_MAX_HSUART_PORTS];
|
|||
|
||||
static struct uart_driver serial_omap_reg;
|
||||
|
||||
static void serial_omap_console_putchar(struct uart_port *port, int ch)
|
||||
static void serial_omap_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct uart_omap_port *up = to_uart_omap_port(port);
|
||||
|
||||
|
|
|
@ -516,7 +516,7 @@ static const struct uart_ops owl_uart_ops = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_OWL_CONSOLE
|
||||
|
||||
static void owl_console_putchar(struct uart_port *port, int ch)
|
||||
static void owl_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
|
|
@ -1600,7 +1600,7 @@ static const struct uart_ops pch_uart_ops = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
|
||||
static void pch_console_putchar(struct uart_port *port, int ch)
|
||||
static void pch_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct eg20t_port *priv =
|
||||
container_of(port, struct eg20t_port, port);
|
||||
|
|
|
@ -691,7 +691,7 @@ static const struct uart_ops pic32_uart_ops = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_PIC32_CONSOLE
|
||||
/* output given char */
|
||||
static void pic32_console_putchar(struct uart_port *port, int ch)
|
||||
static void pic32_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct pic32_sport *sport = to_pic32_sport(port);
|
||||
|
||||
|
|
|
@ -1944,7 +1944,7 @@ static void __exit exit_pmz(void)
|
|||
|
||||
#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
|
||||
|
||||
static void pmz_console_putchar(struct uart_port *port, int ch)
|
||||
static void pmz_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct uart_pmac_port *uap =
|
||||
container_of(port, struct uart_pmac_port, port);
|
||||
|
|
|
@ -430,21 +430,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
unsigned int baud, quot;
|
||||
unsigned int dll;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
cval = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
cval = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
cval = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
cval = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag));
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
cval |= UART_LCR_STOP;
|
||||
|
@ -619,7 +605,7 @@ static void wait_for_xmitr(struct uart_pxa_port *up)
|
|||
}
|
||||
}
|
||||
|
||||
static void serial_pxa_console_putchar(struct uart_port *port, int ch)
|
||||
static void serial_pxa_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
|
||||
|
||||
|
|
|
@ -397,7 +397,7 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
||||
static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch)
|
||||
static void qcom_geni_serial_wr_char(struct uart_port *uport, unsigned char ch)
|
||||
{
|
||||
struct qcom_geni_private_data *private_data = uport->private_data;
|
||||
|
||||
|
|
|
@ -573,7 +573,7 @@ static const struct uart_ops rda_uart_ops = {
|
|||
|
||||
#ifdef CONFIG_SERIAL_RDA_CONSOLE
|
||||
|
||||
static void rda_console_putchar(struct uart_port *port, int ch)
|
||||
static void rda_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
if (!port->membase)
|
||||
return;
|
||||
|
|
|
@ -695,7 +695,7 @@ void __init sa1100_register_uart(int idx, int port)
|
|||
|
||||
|
||||
#ifdef CONFIG_SERIAL_SA1100_CONSOLE
|
||||
static void sa1100_console_putchar(struct uart_port *port, int ch)
|
||||
static void sa1100_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
|
|
@ -63,7 +63,7 @@ enum s3c24xx_port_type {
|
|||
};
|
||||
|
||||
struct s3c24xx_uart_info {
|
||||
char *name;
|
||||
const char *name;
|
||||
enum s3c24xx_port_type type;
|
||||
unsigned int port_type;
|
||||
unsigned int fifosize;
|
||||
|
@ -85,9 +85,9 @@ struct s3c24xx_uart_info {
|
|||
};
|
||||
|
||||
struct s3c24xx_serial_drv_data {
|
||||
struct s3c24xx_uart_info *info;
|
||||
struct s3c2410_uartcfg *def_cfg;
|
||||
unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
|
||||
const struct s3c24xx_uart_info info;
|
||||
const struct s3c2410_uartcfg def_cfg;
|
||||
const unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
|
||||
};
|
||||
|
||||
struct s3c24xx_uart_dma {
|
||||
|
@ -136,14 +136,14 @@ struct s3c24xx_uart_port {
|
|||
unsigned int tx_mode;
|
||||
unsigned int rx_mode;
|
||||
|
||||
struct s3c24xx_uart_info *info;
|
||||
const struct s3c24xx_uart_info *info;
|
||||
struct clk *clk;
|
||||
struct clk *baudclk;
|
||||
struct uart_port port;
|
||||
struct s3c24xx_serial_drv_data *drv_data;
|
||||
const struct s3c24xx_serial_drv_data *drv_data;
|
||||
|
||||
/* reference to platform data */
|
||||
struct s3c2410_uartcfg *cfg;
|
||||
const struct s3c2410_uartcfg *cfg;
|
||||
|
||||
struct s3c24xx_uart_dma *dma;
|
||||
|
||||
|
@ -164,7 +164,7 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport);
|
|||
#define portaddrl(port, reg) \
|
||||
((unsigned long *)(unsigned long)((port)->membase + (reg)))
|
||||
|
||||
static u32 rd_reg(struct uart_port *port, u32 reg)
|
||||
static u32 rd_reg(const struct uart_port *port, u32 reg)
|
||||
{
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM:
|
||||
|
@ -179,7 +179,7 @@ static u32 rd_reg(struct uart_port *port, u32 reg)
|
|||
|
||||
#define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg)))
|
||||
|
||||
static void wr_reg(struct uart_port *port, u32 reg, u32 val)
|
||||
static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
|
||||
{
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM:
|
||||
|
@ -195,7 +195,7 @@ static void wr_reg(struct uart_port *port, u32 reg, u32 val)
|
|||
|
||||
/* Byte-order aware bit setting/clearing functions. */
|
||||
|
||||
static inline void s3c24xx_set_bit(struct uart_port *port, int idx,
|
||||
static inline void s3c24xx_set_bit(const struct uart_port *port, int idx,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -208,7 +208,7 @@ static inline void s3c24xx_set_bit(struct uart_port *port, int idx,
|
|||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static inline void s3c24xx_clear_bit(struct uart_port *port, int idx,
|
||||
static inline void s3c24xx_clear_bit(const struct uart_port *port, int idx,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -228,12 +228,12 @@ static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
|
|||
|
||||
/* translate a port to the device name */
|
||||
|
||||
static inline const char *s3c24xx_serial_portname(struct uart_port *port)
|
||||
static inline const char *s3c24xx_serial_portname(const struct uart_port *port)
|
||||
{
|
||||
return to_platform_device(port->dev)->name;
|
||||
}
|
||||
|
||||
static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
|
||||
static int s3c24xx_serial_txempty_nofifo(const struct uart_port *port)
|
||||
{
|
||||
return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE;
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
|
|||
|
||||
static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
const struct uart_port *port = &ourport->port;
|
||||
u32 ucon;
|
||||
|
||||
/* Mask Tx interrupt */
|
||||
|
@ -387,7 +387,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
|
|||
|
||||
static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
const struct uart_port *port = &ourport->port;
|
||||
u32 ucon, ufcon;
|
||||
|
||||
/* Set ufcon txtrig */
|
||||
|
@ -573,16 +573,16 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
static inline struct s3c24xx_uart_info
|
||||
static inline const struct s3c24xx_uart_info
|
||||
*s3c24xx_port_to_info(struct uart_port *port)
|
||||
{
|
||||
return to_ourport(port)->info;
|
||||
}
|
||||
|
||||
static inline struct s3c2410_uartcfg
|
||||
*s3c24xx_port_to_cfg(struct uart_port *port)
|
||||
static inline const struct s3c2410_uartcfg
|
||||
*s3c24xx_port_to_cfg(const struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport;
|
||||
const struct s3c24xx_uart_port *ourport;
|
||||
|
||||
if (port->dev == NULL)
|
||||
return NULL;
|
||||
|
@ -591,10 +591,10 @@ static inline struct s3c2410_uartcfg
|
|||
return ourport->cfg;
|
||||
}
|
||||
|
||||
static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
|
||||
static int s3c24xx_serial_rx_fifocnt(const struct s3c24xx_uart_port *ourport,
|
||||
unsigned long ufstat)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = ourport->info;
|
||||
const struct s3c24xx_uart_info *info = ourport->info;
|
||||
|
||||
if (ufstat & info->rx_fifofull)
|
||||
return ourport->port.fifosize;
|
||||
|
@ -921,11 +921,8 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
|
|||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
|
||||
spin_unlock(&port->lock);
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
spin_lock(&port->lock);
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
s3c24xx_serial_stop_tx(port);
|
||||
|
@ -947,8 +944,8 @@ static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id)
|
|||
/* interrupt handler for s3c64xx and later SoC's.*/
|
||||
static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
const struct s3c24xx_uart_port *ourport = id;
|
||||
const struct uart_port *port = &ourport->port;
|
||||
unsigned int pend = rd_regl(port, S3C64XX_UINTP);
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
|
||||
|
@ -966,8 +963,8 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
|
|||
/* interrupt handler for Apple SoC's.*/
|
||||
static irqreturn_t apple_serial_handle_irq(int irq, void *id)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
const struct s3c24xx_uart_port *ourport = id;
|
||||
const struct uart_port *port = &ourport->port;
|
||||
unsigned int pend = rd_regl(port, S3C2410_UTRSTAT);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
|
@ -986,7 +983,7 @@ static irqreturn_t apple_serial_handle_irq(int irq, void *id)
|
|||
|
||||
static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
|
||||
unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
|
||||
|
||||
|
@ -1405,7 +1402,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
|
|||
|
||||
static inline int s3c24xx_serial_getsource(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
unsigned int ucon;
|
||||
|
||||
if (info->num_clks == 1)
|
||||
|
@ -1419,7 +1416,7 @@ static inline int s3c24xx_serial_getsource(struct uart_port *port)
|
|||
static void s3c24xx_serial_setsource(struct uart_port *port,
|
||||
unsigned int clk_sel)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
unsigned int ucon;
|
||||
|
||||
if (info->num_clks == 1)
|
||||
|
@ -1438,7 +1435,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
|
|||
unsigned int req_baud, struct clk **best_clk,
|
||||
unsigned int *clk_num)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = ourport->info;
|
||||
const struct s3c24xx_uart_info *info = ourport->info;
|
||||
struct clk *clk;
|
||||
unsigned long rate;
|
||||
unsigned int cnt, baud, quot, best_quot = 0;
|
||||
|
@ -1499,7 +1496,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
|
|||
* This table takes the fractional value of the baud divisor and gives
|
||||
* the recommended setting for the UDIVSLOT register.
|
||||
*/
|
||||
static u16 udivslot_table[16] = {
|
||||
static const u16 udivslot_table[16] = {
|
||||
[0] = 0x0000,
|
||||
[1] = 0x0080,
|
||||
[2] = 0x0808,
|
||||
|
@ -1522,7 +1519,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
|
||||
const struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
struct clk *clk = ERR_PTR(-EINVAL);
|
||||
unsigned long flags;
|
||||
|
@ -1675,7 +1672,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|||
|
||||
static const char *s3c24xx_serial_type(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
const struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
|
||||
switch (ourport->info->type) {
|
||||
case TYPE_S3C24XX:
|
||||
|
@ -1691,7 +1688,7 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
|
|||
|
||||
static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
|
||||
if (flags & UART_CONFIG_TYPE)
|
||||
port->type = info->port_type;
|
||||
|
@ -1703,7 +1700,7 @@ static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
|
|||
static int
|
||||
s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
|
||||
if (ser->type != PORT_UNKNOWN && ser->type != info->port_type)
|
||||
return -EINVAL;
|
||||
|
@ -1873,9 +1870,9 @@ s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
|
|||
*/
|
||||
|
||||
static void s3c24xx_serial_resetport(struct uart_port *port,
|
||||
struct s3c2410_uartcfg *cfg)
|
||||
const struct s3c2410_uartcfg *cfg)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
unsigned long ucon = rd_regl(port, S3C2410_UCON);
|
||||
|
||||
ucon &= (info->clksel_mask | info->ucon_mask);
|
||||
|
@ -1979,7 +1976,7 @@ s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
|||
static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct device *dev = ourport->port.dev;
|
||||
struct s3c24xx_uart_info *info = ourport->info;
|
||||
const struct s3c24xx_uart_info *info = ourport->info;
|
||||
char clk_name[MAX_CLK_NAME_LENGTH];
|
||||
unsigned int clk_sel;
|
||||
struct clk *clk;
|
||||
|
@ -2021,7 +2018,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
|||
struct platform_device *platdev)
|
||||
{
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct s3c2410_uartcfg *cfg = ourport->cfg;
|
||||
const struct s3c2410_uartcfg *cfg = ourport->cfg;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
|
@ -2150,23 +2147,14 @@ err:
|
|||
|
||||
/* Device driver serial port probe */
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id s3c24xx_uart_dt_match[];
|
||||
#endif
|
||||
|
||||
static int probe_index;
|
||||
|
||||
static inline struct s3c24xx_serial_drv_data *
|
||||
static inline const struct s3c24xx_serial_drv_data *
|
||||
s3c24xx_get_driver_data(struct platform_device *pdev)
|
||||
{
|
||||
#ifdef CONFIG_OF
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
if (dev_of_node(&pdev->dev))
|
||||
return of_device_get_match_data(&pdev->dev);
|
||||
|
||||
match = of_match_node(s3c24xx_uart_dt_match, pdev->dev.of_node);
|
||||
return (struct s3c24xx_serial_drv_data *)match->data;
|
||||
}
|
||||
#endif
|
||||
return (struct s3c24xx_serial_drv_data *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
@ -2197,10 +2185,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ourport->baudclk = ERR_PTR(-EINVAL);
|
||||
ourport->info = ourport->drv_data->info;
|
||||
ourport->info = &ourport->drv_data->info;
|
||||
ourport->cfg = (dev_get_platdata(&pdev->dev)) ?
|
||||
dev_get_platdata(&pdev->dev) :
|
||||
ourport->drv_data->def_cfg;
|
||||
&ourport->drv_data->def_cfg;
|
||||
|
||||
switch (ourport->info->type) {
|
||||
case TYPE_S3C24XX:
|
||||
|
@ -2419,7 +2407,7 @@ static struct uart_port *cons_uart;
|
|||
static int
|
||||
s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
|
||||
{
|
||||
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
const struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
|
||||
unsigned long ufstat, utrstat;
|
||||
|
||||
if (ufcon & S3C2410_UFCON_FIFOMODE) {
|
||||
|
@ -2450,7 +2438,7 @@ s3c24xx_port_configured(unsigned int ucon)
|
|||
|
||||
static int s3c24xx_serial_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
const struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
unsigned int ufstat;
|
||||
|
||||
ufstat = rd_regl(port, S3C2410_UFSTAT);
|
||||
|
@ -2478,7 +2466,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
|
|||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static void
|
||||
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
|
||||
s3c24xx_serial_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
|
||||
|
||||
|
@ -2615,8 +2603,8 @@ static struct console s3c24xx_serial_console = {
|
|||
#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
|
||||
|
||||
#ifdef CONFIG_CPU_S3C2410
|
||||
static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = {
|
||||
.info = &(struct s3c24xx_uart_info) {
|
||||
static const struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = {
|
||||
.info = {
|
||||
.name = "Samsung S3C2410 UART",
|
||||
.type = TYPE_S3C24XX,
|
||||
.port_type = PORT_S3C2410,
|
||||
|
@ -2632,19 +2620,19 @@ static struct s3c24xx_serial_drv_data s3c2410_serial_drv_data = {
|
|||
.clksel_mask = S3C2410_UCON_CLKMASK,
|
||||
.clksel_shift = S3C2410_UCON_CLKSHIFT,
|
||||
},
|
||||
.def_cfg = &(struct s3c2410_uartcfg) {
|
||||
.def_cfg = {
|
||||
.ucon = S3C2410_UCON_DEFAULT,
|
||||
.ufcon = S3C2410_UFCON_DEFAULT,
|
||||
},
|
||||
};
|
||||
#define S3C2410_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2410_serial_drv_data)
|
||||
#define S3C2410_SERIAL_DRV_DATA (&s3c2410_serial_drv_data)
|
||||
#else
|
||||
#define S3C2410_SERIAL_DRV_DATA (kernel_ulong_t)NULL
|
||||
#define S3C2410_SERIAL_DRV_DATA NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_S3C2412
|
||||
static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
|
||||
.info = &(struct s3c24xx_uart_info) {
|
||||
static const struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
|
||||
.info = {
|
||||
.name = "Samsung S3C2412 UART",
|
||||
.type = TYPE_S3C24XX,
|
||||
.port_type = PORT_S3C2412,
|
||||
|
@ -2661,20 +2649,20 @@ static struct s3c24xx_serial_drv_data s3c2412_serial_drv_data = {
|
|||
.clksel_mask = S3C2412_UCON_CLKMASK,
|
||||
.clksel_shift = S3C2412_UCON_CLKSHIFT,
|
||||
},
|
||||
.def_cfg = &(struct s3c2410_uartcfg) {
|
||||
.def_cfg = {
|
||||
.ucon = S3C2410_UCON_DEFAULT,
|
||||
.ufcon = S3C2410_UFCON_DEFAULT,
|
||||
},
|
||||
};
|
||||
#define S3C2412_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2412_serial_drv_data)
|
||||
#define S3C2412_SERIAL_DRV_DATA (&s3c2412_serial_drv_data)
|
||||
#else
|
||||
#define S3C2412_SERIAL_DRV_DATA (kernel_ulong_t)NULL
|
||||
#define S3C2412_SERIAL_DRV_DATA NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2416) || \
|
||||
defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2442)
|
||||
static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
|
||||
.info = &(struct s3c24xx_uart_info) {
|
||||
static const struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
|
||||
.info = {
|
||||
.name = "Samsung S3C2440 UART",
|
||||
.type = TYPE_S3C24XX,
|
||||
.port_type = PORT_S3C2440,
|
||||
|
@ -2692,19 +2680,19 @@ static struct s3c24xx_serial_drv_data s3c2440_serial_drv_data = {
|
|||
.clksel_shift = S3C2412_UCON_CLKSHIFT,
|
||||
.ucon_mask = S3C2440_UCON0_DIVMASK,
|
||||
},
|
||||
.def_cfg = &(struct s3c2410_uartcfg) {
|
||||
.def_cfg = {
|
||||
.ucon = S3C2410_UCON_DEFAULT,
|
||||
.ufcon = S3C2410_UFCON_DEFAULT,
|
||||
},
|
||||
};
|
||||
#define S3C2440_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c2440_serial_drv_data)
|
||||
#define S3C2440_SERIAL_DRV_DATA (&s3c2440_serial_drv_data)
|
||||
#else
|
||||
#define S3C2440_SERIAL_DRV_DATA (kernel_ulong_t)NULL
|
||||
#define S3C2440_SERIAL_DRV_DATA NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410)
|
||||
static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
|
||||
.info = &(struct s3c24xx_uart_info) {
|
||||
static const struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
|
||||
.info = {
|
||||
.name = "Samsung S3C6400 UART",
|
||||
.type = TYPE_S3C6400,
|
||||
.port_type = PORT_S3C6400,
|
||||
|
@ -2721,19 +2709,19 @@ static struct s3c24xx_serial_drv_data s3c6400_serial_drv_data = {
|
|||
.clksel_mask = S3C6400_UCON_CLKMASK,
|
||||
.clksel_shift = S3C6400_UCON_CLKSHIFT,
|
||||
},
|
||||
.def_cfg = &(struct s3c2410_uartcfg) {
|
||||
.def_cfg = {
|
||||
.ucon = S3C2410_UCON_DEFAULT,
|
||||
.ufcon = S3C2410_UFCON_DEFAULT,
|
||||
},
|
||||
};
|
||||
#define S3C6400_SERIAL_DRV_DATA ((kernel_ulong_t)&s3c6400_serial_drv_data)
|
||||
#define S3C6400_SERIAL_DRV_DATA (&s3c6400_serial_drv_data)
|
||||
#else
|
||||
#define S3C6400_SERIAL_DRV_DATA (kernel_ulong_t)NULL
|
||||
#define S3C6400_SERIAL_DRV_DATA NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_S5PV210
|
||||
static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
|
||||
.info = &(struct s3c24xx_uart_info) {
|
||||
static const struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
|
||||
.info = {
|
||||
.name = "Samsung S5PV210 UART",
|
||||
.type = TYPE_S3C6400,
|
||||
.port_type = PORT_S3C6400,
|
||||
|
@ -2749,20 +2737,20 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
|
|||
.clksel_mask = S5PV210_UCON_CLKMASK,
|
||||
.clksel_shift = S5PV210_UCON_CLKSHIFT,
|
||||
},
|
||||
.def_cfg = &(struct s3c2410_uartcfg) {
|
||||
.def_cfg = {
|
||||
.ucon = S5PV210_UCON_DEFAULT,
|
||||
.ufcon = S5PV210_UFCON_DEFAULT,
|
||||
},
|
||||
.fifosize = { 256, 64, 16, 16 },
|
||||
};
|
||||
#define S5PV210_SERIAL_DRV_DATA ((kernel_ulong_t)&s5pv210_serial_drv_data)
|
||||
#define S5PV210_SERIAL_DRV_DATA (&s5pv210_serial_drv_data)
|
||||
#else
|
||||
#define S5PV210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
|
||||
#define S5PV210_SERIAL_DRV_DATA NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_EXYNOS)
|
||||
#define EXYNOS_COMMON_SERIAL_DRV_DATA() \
|
||||
.info = &(struct s3c24xx_uart_info) { \
|
||||
.info = { \
|
||||
.name = "Samsung Exynos UART", \
|
||||
.type = TYPE_S3C6400, \
|
||||
.port_type = PORT_S3C6400, \
|
||||
|
@ -2778,40 +2766,40 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
|
|||
.clksel_mask = 0, \
|
||||
.clksel_shift = 0, \
|
||||
}, \
|
||||
.def_cfg = &(struct s3c2410_uartcfg) { \
|
||||
.def_cfg = { \
|
||||
.ucon = S5PV210_UCON_DEFAULT, \
|
||||
.ufcon = S5PV210_UFCON_DEFAULT, \
|
||||
.has_fracval = 1, \
|
||||
} \
|
||||
|
||||
static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
|
||||
static const struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
|
||||
EXYNOS_COMMON_SERIAL_DRV_DATA(),
|
||||
.fifosize = { 256, 64, 16, 16 },
|
||||
};
|
||||
|
||||
static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
|
||||
static const struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
|
||||
EXYNOS_COMMON_SERIAL_DRV_DATA(),
|
||||
.fifosize = { 64, 256, 16, 256 },
|
||||
};
|
||||
|
||||
static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
|
||||
static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
|
||||
EXYNOS_COMMON_SERIAL_DRV_DATA(),
|
||||
.fifosize = { 256, 64, 64, 64 },
|
||||
};
|
||||
|
||||
#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data)
|
||||
#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data)
|
||||
#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos850_serial_drv_data)
|
||||
#define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data)
|
||||
#define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data)
|
||||
#define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data)
|
||||
|
||||
#else
|
||||
#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
|
||||
#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
|
||||
#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
|
||||
#define EXYNOS4210_SERIAL_DRV_DATA NULL
|
||||
#define EXYNOS5433_SERIAL_DRV_DATA NULL
|
||||
#define EXYNOS850_SERIAL_DRV_DATA NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_APPLE
|
||||
static struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
|
||||
.info = &(struct s3c24xx_uart_info) {
|
||||
static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
|
||||
.info = {
|
||||
.name = "Apple S5L UART",
|
||||
.type = TYPE_APPLE_S5L,
|
||||
.port_type = PORT_8250,
|
||||
|
@ -2827,44 +2815,77 @@ static struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
|
|||
.clksel_mask = 0,
|
||||
.clksel_shift = 0,
|
||||
},
|
||||
.def_cfg = &(struct s3c2410_uartcfg) {
|
||||
.def_cfg = {
|
||||
.ucon = APPLE_S5L_UCON_DEFAULT,
|
||||
.ufcon = S3C2410_UFCON_DEFAULT,
|
||||
},
|
||||
};
|
||||
#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)&s5l_serial_drv_data)
|
||||
#define S5L_SERIAL_DRV_DATA (&s5l_serial_drv_data)
|
||||
#else
|
||||
#define S5L_SERIAL_DRV_DATA ((kernel_ulong_t)NULL)
|
||||
#define S5L_SERIAL_DRV_DATA NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARCH_ARTPEC)
|
||||
static const struct s3c24xx_serial_drv_data artpec8_serial_drv_data = {
|
||||
.info = {
|
||||
.name = "Axis ARTPEC-8 UART",
|
||||
.type = TYPE_S3C6400,
|
||||
.port_type = PORT_S3C6400,
|
||||
.fifosize = 64,
|
||||
.has_divslot = 1,
|
||||
.rx_fifomask = S5PV210_UFSTAT_RXMASK,
|
||||
.rx_fifoshift = S5PV210_UFSTAT_RXSHIFT,
|
||||
.rx_fifofull = S5PV210_UFSTAT_RXFULL,
|
||||
.tx_fifofull = S5PV210_UFSTAT_TXFULL,
|
||||
.tx_fifomask = S5PV210_UFSTAT_TXMASK,
|
||||
.tx_fifoshift = S5PV210_UFSTAT_TXSHIFT,
|
||||
.def_clk_sel = S3C2410_UCON_CLKSEL0,
|
||||
.num_clks = 1,
|
||||
.clksel_mask = 0,
|
||||
.clksel_shift = 0,
|
||||
},
|
||||
.def_cfg = {
|
||||
.ucon = S5PV210_UCON_DEFAULT,
|
||||
.ufcon = S5PV210_UFCON_DEFAULT,
|
||||
.has_fracval = 1,
|
||||
}
|
||||
};
|
||||
#define ARTPEC8_SERIAL_DRV_DATA (&artpec8_serial_drv_data)
|
||||
#else
|
||||
#define ARTPEC8_SERIAL_DRV_DATA (NULL)
|
||||
#endif
|
||||
|
||||
static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
|
||||
{
|
||||
.name = "s3c2410-uart",
|
||||
.driver_data = S3C2410_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)S3C2410_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "s3c2412-uart",
|
||||
.driver_data = S3C2412_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)S3C2412_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "s3c2440-uart",
|
||||
.driver_data = S3C2440_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)S3C2440_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "s3c6400-uart",
|
||||
.driver_data = S3C6400_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)S3C6400_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "s5pv210-uart",
|
||||
.driver_data = S5PV210_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)S5PV210_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "exynos4210-uart",
|
||||
.driver_data = EXYNOS4210_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)EXYNOS4210_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "exynos5433-uart",
|
||||
.driver_data = EXYNOS5433_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)EXYNOS5433_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "s5l-uart",
|
||||
.driver_data = S5L_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)S5L_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "exynos850-uart",
|
||||
.driver_data = EXYNOS850_SERIAL_DRV_DATA,
|
||||
.driver_data = (kernel_ulong_t)EXYNOS850_SERIAL_DRV_DATA,
|
||||
}, {
|
||||
.name = "artpec8-uart",
|
||||
.driver_data = (kernel_ulong_t)ARTPEC8_SERIAL_DRV_DATA,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
@ -2873,23 +2894,25 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_serial_driver_ids);
|
|||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id s3c24xx_uart_dt_match[] = {
|
||||
{ .compatible = "samsung,s3c2410-uart",
|
||||
.data = (void *)S3C2410_SERIAL_DRV_DATA },
|
||||
.data = S3C2410_SERIAL_DRV_DATA },
|
||||
{ .compatible = "samsung,s3c2412-uart",
|
||||
.data = (void *)S3C2412_SERIAL_DRV_DATA },
|
||||
.data = S3C2412_SERIAL_DRV_DATA },
|
||||
{ .compatible = "samsung,s3c2440-uart",
|
||||
.data = (void *)S3C2440_SERIAL_DRV_DATA },
|
||||
.data = S3C2440_SERIAL_DRV_DATA },
|
||||
{ .compatible = "samsung,s3c6400-uart",
|
||||
.data = (void *)S3C6400_SERIAL_DRV_DATA },
|
||||
.data = S3C6400_SERIAL_DRV_DATA },
|
||||
{ .compatible = "samsung,s5pv210-uart",
|
||||
.data = (void *)S5PV210_SERIAL_DRV_DATA },
|
||||
.data = S5PV210_SERIAL_DRV_DATA },
|
||||
{ .compatible = "samsung,exynos4210-uart",
|
||||
.data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
|
||||
.data = EXYNOS4210_SERIAL_DRV_DATA },
|
||||
{ .compatible = "samsung,exynos5433-uart",
|
||||
.data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
|
||||
.data = EXYNOS5433_SERIAL_DRV_DATA },
|
||||
{ .compatible = "apple,s5l-uart",
|
||||
.data = (void *)S5L_SERIAL_DRV_DATA },
|
||||
.data = S5L_SERIAL_DRV_DATA },
|
||||
{ .compatible = "samsung,exynos850-uart",
|
||||
.data = (void *)EXYNOS850_SERIAL_DRV_DATA },
|
||||
.data = EXYNOS850_SERIAL_DRV_DATA },
|
||||
{ .compatible = "axis,artpec8-uart",
|
||||
.data = ARTPEC8_SERIAL_DRV_DATA },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
|
||||
|
@ -2935,7 +2958,7 @@ module_exit(samsung_serial_exit);
|
|||
* Early console.
|
||||
*/
|
||||
|
||||
static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val)
|
||||
static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val)
|
||||
{
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM:
|
||||
|
@ -2949,23 +2972,24 @@ static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val)
|
|||
|
||||
struct samsung_early_console_data {
|
||||
u32 txfull_mask;
|
||||
u32 rxfifo_mask;
|
||||
};
|
||||
|
||||
static void samsung_early_busyuart(struct uart_port *port)
|
||||
static void samsung_early_busyuart(const struct uart_port *port)
|
||||
{
|
||||
while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
|
||||
;
|
||||
}
|
||||
|
||||
static void samsung_early_busyuart_fifo(struct uart_port *port)
|
||||
static void samsung_early_busyuart_fifo(const struct uart_port *port)
|
||||
{
|
||||
struct samsung_early_console_data *data = port->private_data;
|
||||
const struct samsung_early_console_data *data = port->private_data;
|
||||
|
||||
while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
|
||||
;
|
||||
}
|
||||
|
||||
static void samsung_early_putc(struct uart_port *port, int c)
|
||||
static void samsung_early_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
|
||||
samsung_early_busyuart_fifo(port);
|
||||
|
@ -2983,6 +3007,26 @@ static void samsung_early_write(struct console *con, const char *s,
|
|||
uart_console_write(&dev->port, s, n, samsung_early_putc);
|
||||
}
|
||||
|
||||
static int samsung_early_read(struct console *con, char *s, unsigned int n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
const struct samsung_early_console_data *data = dev->port.private_data;
|
||||
int ch, ufstat, num_read = 0;
|
||||
|
||||
while (num_read < n) {
|
||||
ufstat = rd_regl(&dev->port, S3C2410_UFSTAT);
|
||||
if (!(ufstat & data->rxfifo_mask))
|
||||
break;
|
||||
ch = rd_reg(&dev->port, S3C2410_URXH);
|
||||
if (ch == NO_POLL_CHAR)
|
||||
break;
|
||||
|
||||
s[num_read++] = ch;
|
||||
}
|
||||
|
||||
return num_read;
|
||||
}
|
||||
|
||||
static int __init samsung_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
|
@ -2990,12 +3034,14 @@ static int __init samsung_early_console_setup(struct earlycon_device *device,
|
|||
return -ENODEV;
|
||||
|
||||
device->con->write = samsung_early_write;
|
||||
device->con->read = samsung_early_read;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* S3C2410 */
|
||||
static struct samsung_early_console_data s3c2410_early_console_data = {
|
||||
.txfull_mask = S3C2410_UFSTAT_TXFULL,
|
||||
.rxfifo_mask = S3C2410_UFSTAT_RXFULL | S3C2410_UFSTAT_RXMASK,
|
||||
};
|
||||
|
||||
static int __init s3c2410_early_console_setup(struct earlycon_device *device,
|
||||
|
@ -3011,6 +3057,7 @@ OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
|
|||
/* S3C2412, S3C2440, S3C64xx */
|
||||
static struct samsung_early_console_data s3c2440_early_console_data = {
|
||||
.txfull_mask = S3C2440_UFSTAT_TXFULL,
|
||||
.rxfifo_mask = S3C2440_UFSTAT_RXFULL | S3C2440_UFSTAT_RXMASK,
|
||||
};
|
||||
|
||||
static int __init s3c2440_early_console_setup(struct earlycon_device *device,
|
||||
|
@ -3030,6 +3077,7 @@ OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
|
|||
/* S5PV210, Exynos */
|
||||
static struct samsung_early_console_data s5pv210_early_console_data = {
|
||||
.txfull_mask = S5PV210_UFSTAT_TXFULL,
|
||||
.rxfifo_mask = S5PV210_UFSTAT_RXFULL | S5PV210_UFSTAT_RXMASK,
|
||||
};
|
||||
|
||||
static int __init s5pv210_early_console_setup(struct earlycon_device *device,
|
||||
|
@ -3043,6 +3091,8 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
|
|||
s5pv210_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
|
||||
s5pv210_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart",
|
||||
s5pv210_early_console_setup);
|
||||
|
||||
/* Apple S5L */
|
||||
static int __init apple_s5l_early_console_setup(struct earlycon_device *device,
|
||||
|
|
|
@ -820,7 +820,7 @@ static void __init sbd_probe_duarts(void)
|
|||
* console output. The console_lock is held by the caller, so we
|
||||
* shouldn't be interrupted for more console activity.
|
||||
*/
|
||||
static void sbd_console_putchar(struct uart_port *uport, int ch)
|
||||
static void sbd_console_putchar(struct uart_port *uport, unsigned char ch)
|
||||
{
|
||||
struct sbd_port *sport = to_sport(uport);
|
||||
|
||||
|
|
|
@ -289,6 +289,14 @@
|
|||
* XON1, XON2, XOFF1 and
|
||||
* XOFF2
|
||||
*/
|
||||
#define SC16IS7XX_EFR_FLOWCTRL_BITS (SC16IS7XX_EFR_AUTORTS_BIT | \
|
||||
SC16IS7XX_EFR_AUTOCTS_BIT | \
|
||||
SC16IS7XX_EFR_XOFF2_DETECT_BIT | \
|
||||
SC16IS7XX_EFR_SWFLOW3_BIT | \
|
||||
SC16IS7XX_EFR_SWFLOW2_BIT | \
|
||||
SC16IS7XX_EFR_SWFLOW1_BIT | \
|
||||
SC16IS7XX_EFR_SWFLOW0_BIT)
|
||||
|
||||
|
||||
/* Misc definitions */
|
||||
#define SC16IS7XX_FIFO_SIZE (64)
|
||||
|
@ -298,6 +306,7 @@ struct sc16is7xx_devtype {
|
|||
char name[10];
|
||||
int nr_gpio;
|
||||
int nr_uart;
|
||||
int has_mctrl;
|
||||
};
|
||||
|
||||
#define SC16IS7XX_RECONF_MD (1 << 0)
|
||||
|
@ -306,7 +315,8 @@ struct sc16is7xx_devtype {
|
|||
|
||||
struct sc16is7xx_one_config {
|
||||
unsigned int flags;
|
||||
u8 ier_clear;
|
||||
u8 ier_mask;
|
||||
u8 ier_val;
|
||||
};
|
||||
|
||||
struct sc16is7xx_one {
|
||||
|
@ -314,8 +324,10 @@ struct sc16is7xx_one {
|
|||
u8 line;
|
||||
struct kthread_work tx_work;
|
||||
struct kthread_work reg_work;
|
||||
struct kthread_delayed_work ms_work;
|
||||
struct sc16is7xx_one_config config;
|
||||
bool irda_mode;
|
||||
unsigned int old_mctrl;
|
||||
};
|
||||
|
||||
struct sc16is7xx_port {
|
||||
|
@ -340,6 +352,9 @@ static struct uart_driver sc16is7xx_uart = {
|
|||
.nr = SC16IS7XX_MAX_DEVS,
|
||||
};
|
||||
|
||||
static void sc16is7xx_ier_set(struct uart_port *port, u8 bit);
|
||||
static void sc16is7xx_stop_tx(struct uart_port *port);
|
||||
|
||||
#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e)))
|
||||
#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
|
||||
|
||||
|
@ -432,30 +447,35 @@ static const struct sc16is7xx_devtype sc16is74x_devtype = {
|
|||
.name = "SC16IS74X",
|
||||
.nr_gpio = 0,
|
||||
.nr_uart = 1,
|
||||
.has_mctrl = 0,
|
||||
};
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is750_devtype = {
|
||||
.name = "SC16IS750",
|
||||
.nr_gpio = 8,
|
||||
.nr_gpio = 4,
|
||||
.nr_uart = 1,
|
||||
.has_mctrl = 1,
|
||||
};
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is752_devtype = {
|
||||
.name = "SC16IS752",
|
||||
.nr_gpio = 8,
|
||||
.nr_gpio = 0,
|
||||
.nr_uart = 2,
|
||||
.has_mctrl = 1,
|
||||
};
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is760_devtype = {
|
||||
.name = "SC16IS760",
|
||||
.nr_gpio = 8,
|
||||
.nr_gpio = 4,
|
||||
.nr_uart = 1,
|
||||
.has_mctrl = 1,
|
||||
};
|
||||
|
||||
static const struct sc16is7xx_devtype sc16is762_devtype = {
|
||||
.name = "SC16IS762",
|
||||
.nr_gpio = 8,
|
||||
.nr_gpio = 0,
|
||||
.nr_uart = 2,
|
||||
.has_mctrl = 1,
|
||||
};
|
||||
|
||||
static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
|
||||
|
@ -523,8 +543,10 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
|
|||
|
||||
/* Enable enhanced features */
|
||||
regcache_cache_bypass(s->regmap, true);
|
||||
sc16is7xx_port_write(port, SC16IS7XX_EFR_REG,
|
||||
SC16IS7XX_EFR_ENABLE_BIT);
|
||||
sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
|
||||
SC16IS7XX_EFR_ENABLE_BIT,
|
||||
SC16IS7XX_EFR_ENABLE_BIT);
|
||||
|
||||
regcache_cache_bypass(s->regmap, false);
|
||||
|
||||
/* Put LCR back to the normal mode */
|
||||
|
@ -635,6 +657,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
|
|||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int txlen, to_send, i;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(port->x_char)) {
|
||||
sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char);
|
||||
|
@ -643,8 +666,12 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
|
|||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sc16is7xx_stop_tx(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get length of data pending in circular buffer */
|
||||
to_send = uart_circ_chars_pending(xmit);
|
||||
|
@ -671,8 +698,56 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
|
|||
sc16is7xx_fifo_write(port, to_send);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
sc16is7xx_stop_tx(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static unsigned int sc16is7xx_get_hwmctrl(struct uart_port *port)
|
||||
{
|
||||
u8 msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
|
||||
unsigned int mctrl = 0;
|
||||
|
||||
mctrl |= (msr & SC16IS7XX_MSR_CTS_BIT) ? TIOCM_CTS : 0;
|
||||
mctrl |= (msr & SC16IS7XX_MSR_DSR_BIT) ? TIOCM_DSR : 0;
|
||||
mctrl |= (msr & SC16IS7XX_MSR_CD_BIT) ? TIOCM_CAR : 0;
|
||||
mctrl |= (msr & SC16IS7XX_MSR_RI_BIT) ? TIOCM_RNG : 0;
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
|
||||
{
|
||||
struct uart_port *port = &one->port;
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
unsigned int status, changed;
|
||||
|
||||
lockdep_assert_held_once(&s->efr_lock);
|
||||
|
||||
status = sc16is7xx_get_hwmctrl(port);
|
||||
changed = status ^ one->old_mctrl;
|
||||
|
||||
if (changed == 0)
|
||||
return;
|
||||
|
||||
one->old_mctrl = status;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if ((changed & TIOCM_RNG) && (status & TIOCM_RNG))
|
||||
port->icount.rng++;
|
||||
if (changed & TIOCM_DSR)
|
||||
port->icount.dsr++;
|
||||
if (changed & TIOCM_CAR)
|
||||
uart_handle_dcd_change(port, status & TIOCM_CAR);
|
||||
if (changed & TIOCM_CTS)
|
||||
uart_handle_cts_change(port, status & TIOCM_CTS);
|
||||
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
||||
|
@ -681,6 +756,7 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
|||
|
||||
do {
|
||||
unsigned int iir, rxlen;
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
|
||||
if (iir & SC16IS7XX_IIR_NO_INT_BIT)
|
||||
|
@ -697,6 +773,11 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
|||
if (rxlen)
|
||||
sc16is7xx_handle_rx(port, rxlen, iir);
|
||||
break;
|
||||
/* CTSRTS interrupt comes only when CTS goes inactive */
|
||||
case SC16IS7XX_IIR_CTSRTS_SRC:
|
||||
case SC16IS7XX_IIR_MSI_SRC:
|
||||
sc16is7xx_update_mlines(one);
|
||||
break;
|
||||
case SC16IS7XX_IIR_THRI_SRC:
|
||||
sc16is7xx_handle_tx(port);
|
||||
break;
|
||||
|
@ -735,6 +816,7 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
|
|||
{
|
||||
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
(port->rs485.delay_rts_before_send > 0))
|
||||
|
@ -743,6 +825,10 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
|
|||
mutex_lock(&s->efr_lock);
|
||||
sc16is7xx_handle_tx(port);
|
||||
mutex_unlock(&s->efr_lock);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void sc16is7xx_reconf_rs485(struct uart_port *port)
|
||||
|
@ -777,22 +863,27 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
|
|||
spin_unlock_irqrestore(&one->port.lock, irqflags);
|
||||
|
||||
if (config.flags & SC16IS7XX_RECONF_MD) {
|
||||
u8 mcr = 0;
|
||||
|
||||
/* Device ignores RTS setting when hardware flow is enabled */
|
||||
if (one->port.mctrl & TIOCM_RTS)
|
||||
mcr |= SC16IS7XX_MCR_RTS_BIT;
|
||||
|
||||
if (one->port.mctrl & TIOCM_DTR)
|
||||
mcr |= SC16IS7XX_MCR_DTR_BIT;
|
||||
|
||||
if (one->port.mctrl & TIOCM_LOOP)
|
||||
mcr |= SC16IS7XX_MCR_LOOP_BIT;
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_RTS_BIT |
|
||||
SC16IS7XX_MCR_DTR_BIT |
|
||||
SC16IS7XX_MCR_LOOP_BIT,
|
||||
(one->port.mctrl & TIOCM_LOOP) ?
|
||||
SC16IS7XX_MCR_LOOP_BIT : 0);
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_RTS_BIT,
|
||||
(one->port.mctrl & TIOCM_RTS) ?
|
||||
SC16IS7XX_MCR_RTS_BIT : 0);
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_DTR_BIT,
|
||||
(one->port.mctrl & TIOCM_DTR) ?
|
||||
SC16IS7XX_MCR_DTR_BIT : 0);
|
||||
mcr);
|
||||
}
|
||||
|
||||
if (config.flags & SC16IS7XX_RECONF_IER)
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
|
||||
config.ier_clear, 0);
|
||||
config.ier_mask, config.ier_val);
|
||||
|
||||
if (config.flags & SC16IS7XX_RECONF_RS485)
|
||||
sc16is7xx_reconf_rs485(&one->port);
|
||||
|
@ -803,8 +894,24 @@ static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
|
|||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
lockdep_assert_held_once(&port->lock);
|
||||
|
||||
one->config.flags |= SC16IS7XX_RECONF_IER;
|
||||
one->config.ier_clear |= bit;
|
||||
one->config.ier_mask |= bit;
|
||||
one->config.ier_val &= ~bit;
|
||||
kthread_queue_work(&s->kworker, &one->reg_work);
|
||||
}
|
||||
|
||||
static void sc16is7xx_ier_set(struct uart_port *port, u8 bit)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
lockdep_assert_held_once(&port->lock);
|
||||
|
||||
one->config.flags |= SC16IS7XX_RECONF_IER;
|
||||
one->config.ier_mask |= bit;
|
||||
one->config.ier_val |= bit;
|
||||
kthread_queue_work(&s->kworker, &one->reg_work);
|
||||
}
|
||||
|
||||
|
@ -818,6 +925,30 @@ static void sc16is7xx_stop_rx(struct uart_port *port)
|
|||
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
|
||||
}
|
||||
|
||||
static void sc16is7xx_ms_proc(struct kthread_work *ws)
|
||||
{
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(ws, ms_work.work);
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
|
||||
|
||||
if (one->port.state) {
|
||||
mutex_lock(&s->efr_lock);
|
||||
sc16is7xx_update_mlines(one);
|
||||
mutex_unlock(&s->efr_lock);
|
||||
|
||||
kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
|
||||
}
|
||||
}
|
||||
|
||||
static void sc16is7xx_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
|
||||
lockdep_assert_held_once(&port->lock);
|
||||
|
||||
kthread_queue_delayed_work(&s->kworker, &one->ms_work, 0);
|
||||
}
|
||||
|
||||
static void sc16is7xx_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
|
@ -826,6 +957,29 @@ static void sc16is7xx_start_tx(struct uart_port *port)
|
|||
kthread_queue_work(&s->kworker, &one->tx_work);
|
||||
}
|
||||
|
||||
static void sc16is7xx_throttle(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Hardware flow control is enabled and thus the device ignores RTS
|
||||
* value set in MCR register. Stop reading data from RX FIFO so the
|
||||
* AutoRTS feature will de-activate RTS output.
|
||||
*/
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void sc16is7xx_unthrottle(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sc16is7xx_ier_set(port, SC16IS7XX_IER_RDI_BIT);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
|
||||
{
|
||||
unsigned int lsr;
|
||||
|
@ -837,10 +991,10 @@ static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
|
|||
|
||||
static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
/* DCD and DSR are not wired and CTS/RTS is handled automatically
|
||||
* so just indicate DSR and CAR asserted
|
||||
*/
|
||||
return TIOCM_DSR | TIOCM_CAR;
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
/* Called with port lock taken so we can only return cached value */
|
||||
return one->old_mctrl;
|
||||
}
|
||||
|
||||
static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
|
@ -864,8 +1018,12 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
|||
struct ktermios *old)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
unsigned int lcr, flow = 0;
|
||||
int baud;
|
||||
unsigned long flags;
|
||||
|
||||
kthread_cancel_delayed_work_sync(&one->ms_work);
|
||||
|
||||
/* Mask termios capabilities we don't support */
|
||||
termios->c_cflag &= ~CMSPAR;
|
||||
|
@ -927,15 +1085,22 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
|||
regcache_cache_bypass(s->regmap, true);
|
||||
sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]);
|
||||
sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]);
|
||||
if (termios->c_cflag & CRTSCTS)
|
||||
|
||||
port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
|
||||
if (termios->c_cflag & CRTSCTS) {
|
||||
flow |= SC16IS7XX_EFR_AUTOCTS_BIT |
|
||||
SC16IS7XX_EFR_AUTORTS_BIT;
|
||||
port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
|
||||
}
|
||||
if (termios->c_iflag & IXON)
|
||||
flow |= SC16IS7XX_EFR_SWFLOW3_BIT;
|
||||
if (termios->c_iflag & IXOFF)
|
||||
flow |= SC16IS7XX_EFR_SWFLOW1_BIT;
|
||||
|
||||
sc16is7xx_port_write(port, SC16IS7XX_EFR_REG, flow);
|
||||
sc16is7xx_port_update(port,
|
||||
SC16IS7XX_EFR_REG,
|
||||
SC16IS7XX_EFR_FLOWCTRL_BITS,
|
||||
flow);
|
||||
regcache_cache_bypass(s->regmap, false);
|
||||
|
||||
/* Update LCR register */
|
||||
|
@ -951,8 +1116,15 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
|||
/* Setup baudrate generator */
|
||||
baud = sc16is7xx_set_baud(port, baud);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Update timeout according to new baud rate */
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
if (UART_ENABLE_MS(port, termios->c_cflag))
|
||||
sc16is7xx_enable_ms(port);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int sc16is7xx_config_rs485(struct uart_port *port,
|
||||
|
@ -993,6 +1165,7 @@ static int sc16is7xx_startup(struct uart_port *port)
|
|||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned int val;
|
||||
unsigned long flags;
|
||||
|
||||
sc16is7xx_power(port, 1);
|
||||
|
||||
|
@ -1010,8 +1183,9 @@ static int sc16is7xx_startup(struct uart_port *port)
|
|||
regcache_cache_bypass(s->regmap, true);
|
||||
|
||||
/* Enable write access to enhanced features and internal clock div */
|
||||
sc16is7xx_port_write(port, SC16IS7XX_EFR_REG,
|
||||
SC16IS7XX_EFR_ENABLE_BIT);
|
||||
sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
|
||||
SC16IS7XX_EFR_ENABLE_BIT,
|
||||
SC16IS7XX_EFR_ENABLE_BIT);
|
||||
|
||||
/* Enable TCR/TLR */
|
||||
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
|
||||
|
@ -1042,23 +1216,34 @@ static int sc16is7xx_startup(struct uart_port *port)
|
|||
SC16IS7XX_EFCR_TXDISABLE_BIT,
|
||||
0);
|
||||
|
||||
/* Enable RX, TX interrupts */
|
||||
val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT;
|
||||
/* Enable RX, CTS change and modem lines interrupts */
|
||||
val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_CTSI_BIT |
|
||||
SC16IS7XX_IER_MSI_BIT;
|
||||
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
|
||||
|
||||
/* Enable modem status polling */
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sc16is7xx_enable_ms(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sc16is7xx_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
kthread_cancel_delayed_work_sync(&one->ms_work);
|
||||
|
||||
/* Disable all interrupts */
|
||||
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
|
||||
/* Disable TX/RX */
|
||||
/* Disable TX/RX, clear auto RS485 and RTS invert */
|
||||
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
|
||||
SC16IS7XX_EFCR_RXDISABLE_BIT |
|
||||
SC16IS7XX_EFCR_TXDISABLE_BIT,
|
||||
SC16IS7XX_EFCR_TXDISABLE_BIT |
|
||||
SC16IS7XX_EFCR_AUTO_RS485_BIT |
|
||||
SC16IS7XX_EFCR_RTS_INVERT_BIT,
|
||||
SC16IS7XX_EFCR_RXDISABLE_BIT |
|
||||
SC16IS7XX_EFCR_TXDISABLE_BIT);
|
||||
|
||||
|
@ -1114,7 +1299,10 @@ static const struct uart_ops sc16is7xx_ops = {
|
|||
.get_mctrl = sc16is7xx_get_mctrl,
|
||||
.stop_tx = sc16is7xx_stop_tx,
|
||||
.start_tx = sc16is7xx_start_tx,
|
||||
.throttle = sc16is7xx_throttle,
|
||||
.unthrottle = sc16is7xx_unthrottle,
|
||||
.stop_rx = sc16is7xx_stop_rx,
|
||||
.enable_ms = sc16is7xx_enable_ms,
|
||||
.break_ctl = sc16is7xx_break_ctl,
|
||||
.startup = sc16is7xx_startup,
|
||||
.shutdown = sc16is7xx_shutdown,
|
||||
|
@ -1281,7 +1469,9 @@ static int sc16is7xx_probe(struct device *dev,
|
|||
s->p[i].port.uartclk = freq;
|
||||
s->p[i].port.rs485_config = sc16is7xx_config_rs485;
|
||||
s->p[i].port.ops = &sc16is7xx_ops;
|
||||
s->p[i].old_mctrl = 0;
|
||||
s->p[i].port.line = sc16is7xx_alloc_line();
|
||||
|
||||
if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) {
|
||||
ret = -ENOMEM;
|
||||
goto out_ports;
|
||||
|
@ -1293,9 +1483,17 @@ static int sc16is7xx_probe(struct device *dev,
|
|||
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG,
|
||||
SC16IS7XX_EFCR_RXDISABLE_BIT |
|
||||
SC16IS7XX_EFCR_TXDISABLE_BIT);
|
||||
|
||||
/* Use GPIO lines as modem status registers */
|
||||
if (devtype->has_mctrl)
|
||||
sc16is7xx_port_write(&s->p[i].port,
|
||||
SC16IS7XX_IOCONTROL_REG,
|
||||
SC16IS7XX_IOCONTROL_MODEM_BIT);
|
||||
|
||||
/* Initialize kthread work structs */
|
||||
kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
|
||||
kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
|
||||
kthread_init_delayed_work(&s->p[i].ms_work, sc16is7xx_ms_proc);
|
||||
/* Register port */
|
||||
uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
|
||||
|
||||
|
@ -1379,6 +1577,7 @@ static void sc16is7xx_remove(struct device *dev)
|
|||
#endif
|
||||
|
||||
for (i = 0; i < s->devtype->nr_uart; i++) {
|
||||
kthread_cancel_delayed_work_sync(&s->p[i].ms_work);
|
||||
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
|
||||
clear_bit(s->p[i].port.line, &sc16is7xx_lines);
|
||||
sc16is7xx_power(&s->p[i].port, 0);
|
||||
|
|
|
@ -828,7 +828,7 @@ static const struct uart_ops sccnxp_ops = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
|
||||
static void sccnxp_console_putchar(struct uart_port *port, int c)
|
||||
static void sccnxp_console_putchar(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
int tryes = 100000;
|
||||
|
||||
|
|
|
@ -1277,6 +1277,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|||
unsigned int baud;
|
||||
unsigned long flags;
|
||||
unsigned int lcr;
|
||||
unsigned char char_bits;
|
||||
int symb_bit = 1;
|
||||
struct clk *parent_clk = clk_get_parent(tup->uart_clk);
|
||||
unsigned long parent_clk_rate = clk_get_rate(parent_clk);
|
||||
|
@ -1316,25 +1317,10 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|||
}
|
||||
}
|
||||
|
||||
char_bits = tty_get_char_size(termios->c_cflag);
|
||||
symb_bit += char_bits;
|
||||
lcr &= ~UART_LCR_WLEN8;
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr |= UART_LCR_WLEN5;
|
||||
symb_bit += 5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr |= UART_LCR_WLEN6;
|
||||
symb_bit += 6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr |= UART_LCR_WLEN7;
|
||||
symb_bit += 7;
|
||||
break;
|
||||
default:
|
||||
lcr |= UART_LCR_WLEN8;
|
||||
symb_bit += 8;
|
||||
break;
|
||||
}
|
||||
lcr |= UART_LCR_WLEN(char_bits);
|
||||
|
||||
/* Stop bits */
|
||||
if (termios->c_cflag & CSTOPB) {
|
||||
|
|
|
@ -105,6 +105,7 @@ void uart_write_wakeup(struct uart_port *port)
|
|||
BUG_ON(!state);
|
||||
tty_port_tty_wakeup(&state->port);
|
||||
}
|
||||
EXPORT_SYMBOL(uart_write_wakeup);
|
||||
|
||||
static void uart_stop(struct tty_struct *tty)
|
||||
{
|
||||
|
@ -316,8 +317,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
|||
state->xmit.buf = NULL;
|
||||
uart_port_unlock(uport, flags);
|
||||
|
||||
if (xmit_buf)
|
||||
free_page((unsigned long)xmit_buf);
|
||||
free_page((unsigned long)xmit_buf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,7 +343,6 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag,
|
|||
*/
|
||||
port->timeout = (HZ * size) / baud + HZ/50;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(uart_update_timeout);
|
||||
|
||||
/**
|
||||
|
@ -445,7 +444,6 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
|||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(uart_get_baud_rate);
|
||||
|
||||
/**
|
||||
|
@ -470,7 +468,6 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
|
|||
|
||||
return quot;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(uart_get_divisor);
|
||||
|
||||
/* Caller holds port mutex */
|
||||
|
@ -644,6 +641,20 @@ static void uart_flush_buffer(struct tty_struct *tty)
|
|||
tty_port_tty_wakeup(&state->port);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function performs low-level write of high-priority XON/XOFF
|
||||
* character and accounting for it.
|
||||
*
|
||||
* Requires uart_port to implement .serial_out().
|
||||
*/
|
||||
void uart_xchar_out(struct uart_port *uport, int offset)
|
||||
{
|
||||
serial_port_out(uport, offset, uport->x_char);
|
||||
uport->icount.tx++;
|
||||
uport->x_char = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_xchar_out);
|
||||
|
||||
/*
|
||||
* This function is used to send a high-priority XON/XOFF character to
|
||||
* the device
|
||||
|
@ -1571,8 +1582,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
|||
state->xmit.buf = NULL;
|
||||
spin_unlock_irq(&uport->lock);
|
||||
|
||||
if (buf)
|
||||
free_page((unsigned long)buf);
|
||||
free_page((unsigned long)buf);
|
||||
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
}
|
||||
|
@ -1915,7 +1925,7 @@ static void uart_port_spin_lock_init(struct uart_port *port)
|
|||
*/
|
||||
void uart_console_write(struct uart_port *port, const char *s,
|
||||
unsigned int count,
|
||||
void (*putchar)(struct uart_port *, int))
|
||||
void (*putchar)(struct uart_port *, unsigned char))
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -2207,6 +2217,7 @@ unlock:
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(uart_suspend_port);
|
||||
|
||||
int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
{
|
||||
|
@ -2292,6 +2303,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(uart_resume_port);
|
||||
|
||||
static inline void
|
||||
uart_report_port(struct uart_driver *drv, struct uart_port *port)
|
||||
|
@ -2589,6 +2601,7 @@ out_kfree:
|
|||
out:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(uart_register_driver);
|
||||
|
||||
/**
|
||||
* uart_unregister_driver - remove a driver from the uart core layer
|
||||
|
@ -2612,6 +2625,7 @@ void uart_unregister_driver(struct uart_driver *drv)
|
|||
drv->state = NULL;
|
||||
drv->tty_driver = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(uart_unregister_driver);
|
||||
|
||||
struct tty_driver *uart_console_device(struct console *co, int *index)
|
||||
{
|
||||
|
@ -2946,6 +2960,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(uart_add_one_port);
|
||||
|
||||
/**
|
||||
* uart_remove_one_port - detach a driver defined port structure
|
||||
|
@ -3026,6 +3041,7 @@ out:
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(uart_remove_one_port);
|
||||
|
||||
/*
|
||||
* Are the two ports equivalent?
|
||||
|
@ -3202,14 +3218,6 @@ bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
|
|||
EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq);
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL(uart_write_wakeup);
|
||||
EXPORT_SYMBOL(uart_register_driver);
|
||||
EXPORT_SYMBOL(uart_unregister_driver);
|
||||
EXPORT_SYMBOL(uart_suspend_port);
|
||||
EXPORT_SYMBOL(uart_resume_port);
|
||||
EXPORT_SYMBOL(uart_add_one_port);
|
||||
EXPORT_SYMBOL(uart_remove_one_port);
|
||||
|
||||
/**
|
||||
* uart_get_rs485_mode() - retrieve rs485 properties for given uart
|
||||
* @port: uart device's target port
|
||||
|
|
|
@ -299,4 +299,42 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
|
||||
|
||||
void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (!gpios)
|
||||
return;
|
||||
|
||||
if (!gpios->mctrl_on)
|
||||
return;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; ++i) {
|
||||
if (!gpios->irq[i])
|
||||
continue;
|
||||
|
||||
enable_irq_wake(gpios->irq[i]);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake);
|
||||
|
||||
void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (!gpios)
|
||||
return;
|
||||
|
||||
if (!gpios->mctrl_on)
|
||||
return;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; ++i) {
|
||||
if (!gpios->irq[i])
|
||||
continue;
|
||||
|
||||
disable_irq_wake(gpios->irq[i]);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -91,6 +91,16 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
|
|||
*/
|
||||
void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
|
||||
|
||||
/*
|
||||
* Enable gpio wakeup interrupts to enable wake up source.
|
||||
*/
|
||||
void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios);
|
||||
|
||||
/*
|
||||
* Disable gpio wakeup interrupts to enable wake up source.
|
||||
*/
|
||||
void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios);
|
||||
|
||||
#else /* GPIOLIB */
|
||||
|
||||
static inline
|
||||
|
@ -142,6 +152,14 @@ static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
|||
{
|
||||
}
|
||||
|
||||
static inline void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* GPIOLIB */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
|
||||
#include <linux/io.h>
|
||||
|
||||
static char *serial_version = "1.11";
|
||||
static char *serial_name = "TX39/49 Serial driver";
|
||||
|
||||
#define PASS_LIMIT 256
|
||||
|
||||
#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
|
||||
|
@ -57,11 +54,6 @@ static char *serial_name = "TX39/49 Serial driver";
|
|||
*/
|
||||
#define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS
|
||||
|
||||
struct uart_txx9_port {
|
||||
struct uart_port port;
|
||||
/* No additional info for now */
|
||||
};
|
||||
|
||||
#define TXX9_REGION_SIZE 0x24
|
||||
|
||||
/* TXX9 Serial Registers */
|
||||
|
@ -163,42 +155,42 @@ struct uart_txx9_port {
|
|||
#define TXX9_SIBGR_BCLK_T6 0x00000300
|
||||
#define TXX9_SIBGR_BRD_MASK 0x000000ff
|
||||
|
||||
static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
|
||||
static inline unsigned int sio_in(struct uart_port *up, int offset)
|
||||
{
|
||||
switch (up->port.iotype) {
|
||||
switch (up->iotype) {
|
||||
default:
|
||||
return __raw_readl(up->port.membase + offset);
|
||||
return __raw_readl(up->membase + offset);
|
||||
case UPIO_PORT:
|
||||
return inl(up->port.iobase + offset);
|
||||
return inl(up->iobase + offset);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
sio_out(struct uart_txx9_port *up, int offset, int value)
|
||||
sio_out(struct uart_port *up, int offset, int value)
|
||||
{
|
||||
switch (up->port.iotype) {
|
||||
switch (up->iotype) {
|
||||
default:
|
||||
__raw_writel(value, up->port.membase + offset);
|
||||
__raw_writel(value, up->membase + offset);
|
||||
break;
|
||||
case UPIO_PORT:
|
||||
outl(value, up->port.iobase + offset);
|
||||
outl(value, up->iobase + offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
sio_mask(struct uart_txx9_port *up, int offset, unsigned int value)
|
||||
sio_mask(struct uart_port *up, int offset, unsigned int value)
|
||||
{
|
||||
sio_out(up, offset, sio_in(up, offset) & ~value);
|
||||
}
|
||||
static inline void
|
||||
sio_set(struct uart_txx9_port *up, int offset, unsigned int value)
|
||||
sio_set(struct uart_port *up, int offset, unsigned int value)
|
||||
{
|
||||
sio_out(up, offset, sio_in(up, offset) | value);
|
||||
}
|
||||
|
||||
static inline void
|
||||
sio_quot_set(struct uart_txx9_port *up, int quot)
|
||||
sio_quot_set(struct uart_port *up, int quot)
|
||||
{
|
||||
quot >>= 1;
|
||||
if (quot < 256)
|
||||
|
@ -213,32 +205,23 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
|
|||
sio_out(up, TXX9_SIBGR, 0xff | TXX9_SIBGR_BCLK_T6);
|
||||
}
|
||||
|
||||
static struct uart_txx9_port *to_uart_txx9_port(struct uart_port *port)
|
||||
static void serial_txx9_stop_tx(struct uart_port *up)
|
||||
{
|
||||
return container_of(port, struct uart_txx9_port, port);
|
||||
}
|
||||
|
||||
static void serial_txx9_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
|
||||
}
|
||||
|
||||
static void serial_txx9_start_tx(struct uart_port *port)
|
||||
static void serial_txx9_start_tx(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
|
||||
}
|
||||
|
||||
static void serial_txx9_stop_rx(struct uart_port *port)
|
||||
static void serial_txx9_stop_rx(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
|
||||
up->read_status_mask &= ~TXX9_SIDISR_RDIS;
|
||||
}
|
||||
|
||||
static void serial_txx9_initialize(struct uart_port *port)
|
||||
static void serial_txx9_initialize(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
unsigned int tmout = 10000;
|
||||
|
||||
sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
|
||||
|
@ -253,15 +236,15 @@ static void serial_txx9_initialize(struct uart_port *port)
|
|||
/* initial settings */
|
||||
sio_out(up, TXX9_SILCR,
|
||||
TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
|
||||
((up->port.flags & UPF_TXX9_USE_SCLK) ?
|
||||
((up->flags & UPF_TXX9_USE_SCLK) ?
|
||||
TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
|
||||
sio_quot_set(up, uart_get_divisor(port, 9600));
|
||||
sio_quot_set(up, uart_get_divisor(up, 9600));
|
||||
sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
|
||||
sio_out(up, TXX9_SIDICR, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
receive_chars(struct uart_txx9_port *up, unsigned int *status)
|
||||
receive_chars(struct uart_port *up, unsigned int *status)
|
||||
{
|
||||
unsigned char ch;
|
||||
unsigned int disr = *status;
|
||||
|
@ -272,11 +255,11 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status)
|
|||
do {
|
||||
ch = sio_in(up, TXX9_SIRFIFO);
|
||||
flag = TTY_NORMAL;
|
||||
up->port.icount.rx++;
|
||||
up->icount.rx++;
|
||||
|
||||
/* mask out RFDN_MASK bit added by previous overrun */
|
||||
next_ignore_status_mask =
|
||||
up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
|
||||
up->ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
|
||||
if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
|
||||
TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
|
||||
/*
|
||||
|
@ -284,21 +267,21 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status)
|
|||
*/
|
||||
if (disr & TXX9_SIDISR_UBRK) {
|
||||
disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER);
|
||||
up->port.icount.brk++;
|
||||
up->icount.brk++;
|
||||
/*
|
||||
* We do the SysRQ and SAK checking
|
||||
* here because otherwise the break
|
||||
* may get masked by ignore_status_mask
|
||||
* or read_status_mask.
|
||||
*/
|
||||
if (uart_handle_break(&up->port))
|
||||
if (uart_handle_break(up))
|
||||
goto ignore_char;
|
||||
} else if (disr & TXX9_SIDISR_UPER)
|
||||
up->port.icount.parity++;
|
||||
up->icount.parity++;
|
||||
else if (disr & TXX9_SIDISR_UFER)
|
||||
up->port.icount.frame++;
|
||||
up->icount.frame++;
|
||||
if (disr & TXX9_SIDISR_UOER) {
|
||||
up->port.icount.overrun++;
|
||||
up->icount.overrun++;
|
||||
/*
|
||||
* The receiver read buffer still hold
|
||||
* a char which caused overrun.
|
||||
|
@ -312,7 +295,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status)
|
|||
/*
|
||||
* Mask off conditions which should be ingored.
|
||||
*/
|
||||
disr &= up->port.read_status_mask;
|
||||
disr &= up->read_status_mask;
|
||||
|
||||
if (disr & TXX9_SIDISR_UBRK) {
|
||||
flag = TTY_BREAK;
|
||||
|
@ -321,34 +304,34 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status)
|
|||
else if (disr & TXX9_SIDISR_UFER)
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
if (uart_handle_sysrq_char(up, ch))
|
||||
goto ignore_char;
|
||||
|
||||
uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
|
||||
uart_insert_char(up, disr, TXX9_SIDISR_UOER, ch, flag);
|
||||
|
||||
ignore_char:
|
||||
up->port.ignore_status_mask = next_ignore_status_mask;
|
||||
up->ignore_status_mask = next_ignore_status_mask;
|
||||
disr = sio_in(up, TXX9_SIDISR);
|
||||
} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
|
||||
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
tty_flip_buffer_push(&up->state->port);
|
||||
|
||||
*status = disr;
|
||||
}
|
||||
|
||||
static inline void transmit_chars(struct uart_txx9_port *up)
|
||||
static inline void transmit_chars(struct uart_port *up)
|
||||
{
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
struct circ_buf *xmit = &up->state->xmit;
|
||||
int count;
|
||||
|
||||
if (up->port.x_char) {
|
||||
sio_out(up, TXX9_SITFIFO, up->port.x_char);
|
||||
up->port.icount.tx++;
|
||||
up->port.x_char = 0;
|
||||
if (up->x_char) {
|
||||
sio_out(up, TXX9_SITFIFO, up->x_char);
|
||||
up->icount.tx++;
|
||||
up->x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
|
||||
serial_txx9_stop_tx(&up->port);
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(up)) {
|
||||
serial_txx9_stop_tx(up);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -356,32 +339,32 @@ static inline void transmit_chars(struct uart_txx9_port *up)
|
|||
do {
|
||||
sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
up->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
uart_write_wakeup(up);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
serial_txx9_stop_tx(&up->port);
|
||||
serial_txx9_stop_tx(up);
|
||||
}
|
||||
|
||||
static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
int pass_counter = 0;
|
||||
struct uart_txx9_port *up = dev_id;
|
||||
struct uart_port *up = dev_id;
|
||||
unsigned int status;
|
||||
|
||||
while (1) {
|
||||
spin_lock(&up->port.lock);
|
||||
spin_lock(&up->lock);
|
||||
status = sio_in(up, TXX9_SIDISR);
|
||||
if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE))
|
||||
status &= ~TXX9_SIDISR_TDIS;
|
||||
if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
|
||||
TXX9_SIDISR_TOUT))) {
|
||||
spin_unlock(&up->port.lock);
|
||||
spin_unlock(&up->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -393,7 +376,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
|
|||
sio_mask(up, TXX9_SIDISR,
|
||||
TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
|
||||
TXX9_SIDISR_TOUT);
|
||||
spin_unlock(&up->port.lock);
|
||||
spin_unlock(&up->lock);
|
||||
|
||||
if (pass_counter++ > PASS_LIMIT)
|
||||
break;
|
||||
|
@ -402,22 +385,20 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
|
|||
return pass_counter ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static unsigned int serial_txx9_tx_empty(struct uart_port *port)
|
||||
static unsigned int serial_txx9_tx_empty(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
unsigned long flags;
|
||||
unsigned int ret;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
spin_lock_irqsave(&up->lock, flags);
|
||||
ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0;
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
spin_unlock_irqrestore(&up->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
|
||||
static unsigned int serial_txx9_get_mctrl(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
unsigned int ret;
|
||||
|
||||
/* no modem control lines */
|
||||
|
@ -428,9 +409,8 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
static void serial_txx9_set_mctrl(struct uart_port *up, unsigned int mctrl)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
|
||||
|
@ -438,24 +418,23 @@ static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
|
||||
}
|
||||
|
||||
static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
|
||||
static void serial_txx9_break_ctl(struct uart_port *up, int break_state)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
spin_lock_irqsave(&up->lock, flags);
|
||||
if (break_state == -1)
|
||||
sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
|
||||
else
|
||||
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
spin_unlock_irqrestore(&up->lock, flags);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
|
||||
/*
|
||||
* Wait for transmitter & holding register to empty
|
||||
*/
|
||||
static void wait_for_xmitr(struct uart_txx9_port *up)
|
||||
static void wait_for_xmitr(struct uart_port *up)
|
||||
{
|
||||
unsigned int tmout = 10000;
|
||||
|
||||
|
@ -465,7 +444,7 @@ static void wait_for_xmitr(struct uart_txx9_port *up)
|
|||
udelay(1);
|
||||
|
||||
/* Wait up to 1s for flow control if necessary */
|
||||
if (up->port.flags & UPF_CONS_FLOW) {
|
||||
if (up->flags & UPF_CONS_FLOW) {
|
||||
tmout = 1000000;
|
||||
while (--tmout &&
|
||||
(sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
|
||||
|
@ -480,11 +459,10 @@ static void wait_for_xmitr(struct uart_txx9_port *up)
|
|||
* in an interrupt or debug context.
|
||||
*/
|
||||
|
||||
static int serial_txx9_get_poll_char(struct uart_port *port)
|
||||
static int serial_txx9_get_poll_char(struct uart_port *up)
|
||||
{
|
||||
unsigned int ier;
|
||||
unsigned char c;
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
|
@ -507,10 +485,9 @@ static int serial_txx9_get_poll_char(struct uart_port *port)
|
|||
}
|
||||
|
||||
|
||||
static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
|
||||
static void serial_txx9_put_poll_char(struct uart_port *up, unsigned char c)
|
||||
{
|
||||
unsigned int ier;
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
|
@ -534,9 +511,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
|
|||
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static int serial_txx9_startup(struct uart_port *port)
|
||||
static int serial_txx9_startup(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
unsigned long flags;
|
||||
int retval;
|
||||
|
||||
|
@ -556,7 +532,7 @@ static int serial_txx9_startup(struct uart_port *port)
|
|||
*/
|
||||
sio_out(up, TXX9_SIDISR, 0);
|
||||
|
||||
retval = request_irq(up->port.irq, serial_txx9_interrupt,
|
||||
retval = request_irq(up->irq, serial_txx9_interrupt,
|
||||
IRQF_SHARED, "serial_txx9", up);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
@ -564,9 +540,9 @@ static int serial_txx9_startup(struct uart_port *port)
|
|||
/*
|
||||
* Now, initialize the UART
|
||||
*/
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
serial_txx9_set_mctrl(&up->port, up->port.mctrl);
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
spin_lock_irqsave(&up->lock, flags);
|
||||
serial_txx9_set_mctrl(up, up->mctrl);
|
||||
spin_unlock_irqrestore(&up->lock, flags);
|
||||
|
||||
/* Enable RX/TX */
|
||||
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
|
||||
|
@ -579,9 +555,8 @@ static int serial_txx9_startup(struct uart_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void serial_txx9_shutdown(struct uart_port *port)
|
||||
static void serial_txx9_shutdown(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
|
@ -589,9 +564,9 @@ static void serial_txx9_shutdown(struct uart_port *port)
|
|||
*/
|
||||
sio_out(up, TXX9_SIDICR, 0); /* disable all intrs */
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
serial_txx9_set_mctrl(&up->port, up->port.mctrl);
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
spin_lock_irqsave(&up->lock, flags);
|
||||
serial_txx9_set_mctrl(up, up->mctrl);
|
||||
spin_unlock_irqrestore(&up->lock, flags);
|
||||
|
||||
/*
|
||||
* Disable break condition
|
||||
|
@ -599,8 +574,8 @@ static void serial_txx9_shutdown(struct uart_port *port)
|
|||
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
|
||||
|
||||
#ifdef CONFIG_SERIAL_TXX9_CONSOLE
|
||||
if (up->port.cons && up->port.line == up->port.cons->index) {
|
||||
free_irq(up->port.irq, up);
|
||||
if (up->cons && up->line == up->cons->index) {
|
||||
free_irq(up->irq, up);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -614,14 +589,13 @@ static void serial_txx9_shutdown(struct uart_port *port)
|
|||
/* Disable RX/TX */
|
||||
sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
|
||||
|
||||
free_irq(up->port.irq, up);
|
||||
free_irq(up->irq, up);
|
||||
}
|
||||
|
||||
static void
|
||||
serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
unsigned int cval, fcr = 0;
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
@ -661,8 +635,8 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
/*
|
||||
* Ask the core to calculate the divisor for us.
|
||||
*/
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16/2);
|
||||
quot = uart_get_divisor(port, baud);
|
||||
baud = uart_get_baud_rate(up, termios, old, 0, up->uartclk/16/2);
|
||||
quot = uart_get_divisor(up, baud);
|
||||
|
||||
/* Set up FIFOs */
|
||||
/* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
|
||||
|
@ -672,45 +646,45 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
* Ok, we're now changing the port state. Do it with
|
||||
* interrupts disabled.
|
||||
*/
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
spin_lock_irqsave(&up->lock, flags);
|
||||
|
||||
/*
|
||||
* Update the per-port timeout.
|
||||
*/
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
uart_update_timeout(up, termios->c_cflag, baud);
|
||||
|
||||
up->port.read_status_mask = TXX9_SIDISR_UOER |
|
||||
up->read_status_mask = TXX9_SIDISR_UOER |
|
||||
TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS;
|
||||
if (termios->c_iflag & INPCK)
|
||||
up->port.read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
|
||||
up->read_status_mask |= TXX9_SIDISR_UFER | TXX9_SIDISR_UPER;
|
||||
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||
up->port.read_status_mask |= TXX9_SIDISR_UBRK;
|
||||
up->read_status_mask |= TXX9_SIDISR_UBRK;
|
||||
|
||||
/*
|
||||
* Characteres to ignore
|
||||
*/
|
||||
up->port.ignore_status_mask = 0;
|
||||
up->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
up->port.ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER;
|
||||
up->ignore_status_mask |= TXX9_SIDISR_UPER | TXX9_SIDISR_UFER;
|
||||
if (termios->c_iflag & IGNBRK) {
|
||||
up->port.ignore_status_mask |= TXX9_SIDISR_UBRK;
|
||||
up->ignore_status_mask |= TXX9_SIDISR_UBRK;
|
||||
/*
|
||||
* If we're ignoring parity and break indicators,
|
||||
* ignore overruns too (for real raw support).
|
||||
*/
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
up->port.ignore_status_mask |= TXX9_SIDISR_UOER;
|
||||
up->ignore_status_mask |= TXX9_SIDISR_UOER;
|
||||
}
|
||||
|
||||
/*
|
||||
* ignore all characters if CREAD is not set
|
||||
*/
|
||||
if ((termios->c_cflag & CREAD) == 0)
|
||||
up->port.ignore_status_mask |= TXX9_SIDISR_RDIS;
|
||||
up->ignore_status_mask |= TXX9_SIDISR_RDIS;
|
||||
|
||||
/* CTS flow control flag */
|
||||
if ((termios->c_cflag & CRTSCTS) &&
|
||||
(up->port.flags & UPF_TXX9_HAVE_CTS_LINE)) {
|
||||
(up->flags & UPF_TXX9_HAVE_CTS_LINE)) {
|
||||
sio_set(up, TXX9_SIFLCR,
|
||||
TXX9_SIFLCR_RCS | TXX9_SIFLCR_TES);
|
||||
} else {
|
||||
|
@ -722,8 +696,8 @@ serial_txx9_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
sio_quot_set(up, quot);
|
||||
sio_out(up, TXX9_SIFCR, fcr);
|
||||
|
||||
serial_txx9_set_mctrl(&up->port, up->port.mctrl);
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
serial_txx9_set_mctrl(up, up->mctrl);
|
||||
spin_unlock_irqrestore(&up->lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -742,76 +716,73 @@ serial_txx9_pm(struct uart_port *port, unsigned int state,
|
|||
serial_txx9_initialize(port);
|
||||
}
|
||||
|
||||
static int serial_txx9_request_resource(struct uart_txx9_port *up)
|
||||
static int serial_txx9_request_resource(struct uart_port *up)
|
||||
{
|
||||
unsigned int size = TXX9_REGION_SIZE;
|
||||
int ret = 0;
|
||||
|
||||
switch (up->port.iotype) {
|
||||
switch (up->iotype) {
|
||||
default:
|
||||
if (!up->port.mapbase)
|
||||
if (!up->mapbase)
|
||||
break;
|
||||
|
||||
if (!request_mem_region(up->port.mapbase, size, "serial_txx9")) {
|
||||
if (!request_mem_region(up->mapbase, size, "serial_txx9")) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (up->port.flags & UPF_IOREMAP) {
|
||||
up->port.membase = ioremap(up->port.mapbase, size);
|
||||
if (!up->port.membase) {
|
||||
release_mem_region(up->port.mapbase, size);
|
||||
if (up->flags & UPF_IOREMAP) {
|
||||
up->membase = ioremap(up->mapbase, size);
|
||||
if (!up->membase) {
|
||||
release_mem_region(up->mapbase, size);
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case UPIO_PORT:
|
||||
if (!request_region(up->port.iobase, size, "serial_txx9"))
|
||||
if (!request_region(up->iobase, size, "serial_txx9"))
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void serial_txx9_release_resource(struct uart_txx9_port *up)
|
||||
static void serial_txx9_release_resource(struct uart_port *up)
|
||||
{
|
||||
unsigned int size = TXX9_REGION_SIZE;
|
||||
|
||||
switch (up->port.iotype) {
|
||||
switch (up->iotype) {
|
||||
default:
|
||||
if (!up->port.mapbase)
|
||||
if (!up->mapbase)
|
||||
break;
|
||||
|
||||
if (up->port.flags & UPF_IOREMAP) {
|
||||
iounmap(up->port.membase);
|
||||
up->port.membase = NULL;
|
||||
if (up->flags & UPF_IOREMAP) {
|
||||
iounmap(up->membase);
|
||||
up->membase = NULL;
|
||||
}
|
||||
|
||||
release_mem_region(up->port.mapbase, size);
|
||||
release_mem_region(up->mapbase, size);
|
||||
break;
|
||||
|
||||
case UPIO_PORT:
|
||||
release_region(up->port.iobase, size);
|
||||
release_region(up->iobase, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void serial_txx9_release_port(struct uart_port *port)
|
||||
static void serial_txx9_release_port(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
serial_txx9_release_resource(up);
|
||||
}
|
||||
|
||||
static int serial_txx9_request_port(struct uart_port *port)
|
||||
static int serial_txx9_request_port(struct uart_port *up)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
return serial_txx9_request_resource(up);
|
||||
}
|
||||
|
||||
static void serial_txx9_config_port(struct uart_port *port, int uflags)
|
||||
static void serial_txx9_config_port(struct uart_port *up, int uflags)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
|
@ -821,14 +792,14 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
|
|||
ret = serial_txx9_request_resource(up);
|
||||
if (ret < 0)
|
||||
return;
|
||||
port->type = PORT_TXX9;
|
||||
up->port.fifosize = TXX9_SIO_TX_FIFO;
|
||||
up->type = PORT_TXX9;
|
||||
up->fifosize = TXX9_SIO_TX_FIFO;
|
||||
|
||||
#ifdef CONFIG_SERIAL_TXX9_CONSOLE
|
||||
if (up->port.line == up->port.cons->index)
|
||||
if (up->line == up->cons->index)
|
||||
return;
|
||||
#endif
|
||||
serial_txx9_initialize(port);
|
||||
serial_txx9_initialize(up);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
@ -859,7 +830,7 @@ static const struct uart_ops serial_txx9_pops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static struct uart_txx9_port serial_txx9_ports[UART_NR];
|
||||
static struct uart_port serial_txx9_ports[UART_NR];
|
||||
|
||||
static void __init serial_txx9_register_ports(struct uart_driver *drv,
|
||||
struct device *dev)
|
||||
|
@ -867,22 +838,20 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv,
|
|||
int i;
|
||||
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
struct uart_txx9_port *up = &serial_txx9_ports[i];
|
||||
struct uart_port *up = &serial_txx9_ports[i];
|
||||
|
||||
up->port.line = i;
|
||||
up->port.ops = &serial_txx9_pops;
|
||||
up->port.dev = dev;
|
||||
if (up->port.iobase || up->port.mapbase)
|
||||
uart_add_one_port(drv, &up->port);
|
||||
up->line = i;
|
||||
up->ops = &serial_txx9_pops;
|
||||
up->dev = dev;
|
||||
if (up->iobase || up->mapbase)
|
||||
uart_add_one_port(drv, up);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_TXX9_CONSOLE
|
||||
|
||||
static void serial_txx9_console_putchar(struct uart_port *port, int ch)
|
||||
static void serial_txx9_console_putchar(struct uart_port *up, unsigned char ch)
|
||||
{
|
||||
struct uart_txx9_port *up = to_uart_txx9_port(port);
|
||||
|
||||
wait_for_xmitr(up);
|
||||
sio_out(up, TXX9_SITFIFO, ch);
|
||||
}
|
||||
|
@ -896,7 +865,7 @@ static void serial_txx9_console_putchar(struct uart_port *port, int ch)
|
|||
static void
|
||||
serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_txx9_port *up = &serial_txx9_ports[co->index];
|
||||
struct uart_port *up = &serial_txx9_ports[co->index];
|
||||
unsigned int ier, flcr;
|
||||
|
||||
/*
|
||||
|
@ -908,10 +877,10 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
|
|||
* Disable flow-control if enabled (and unnecessary)
|
||||
*/
|
||||
flcr = sio_in(up, TXX9_SIFLCR);
|
||||
if (!(up->port.flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES))
|
||||
if (!(up->flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES))
|
||||
sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES);
|
||||
|
||||
uart_console_write(&up->port, s, count, serial_txx9_console_putchar);
|
||||
uart_console_write(up, s, count, serial_txx9_console_putchar);
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
|
@ -924,8 +893,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
|
|||
|
||||
static int __init serial_txx9_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
struct uart_txx9_port *up;
|
||||
struct uart_port *up;
|
||||
int baud = 9600;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
|
@ -939,16 +907,15 @@ static int __init serial_txx9_console_setup(struct console *co, char *options)
|
|||
if (co->index >= UART_NR)
|
||||
co->index = 0;
|
||||
up = &serial_txx9_ports[co->index];
|
||||
port = &up->port;
|
||||
if (!port->ops)
|
||||
if (!up->ops)
|
||||
return -ENODEV;
|
||||
|
||||
serial_txx9_initialize(&up->port);
|
||||
serial_txx9_initialize(up);
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
return uart_set_options(up, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver serial_txx9_reg;
|
||||
|
@ -989,9 +956,9 @@ int __init early_serial_txx9_setup(struct uart_port *port)
|
|||
if (port->line >= ARRAY_SIZE(serial_txx9_ports))
|
||||
return -ENODEV;
|
||||
|
||||
serial_txx9_ports[port->line].port = *port;
|
||||
serial_txx9_ports[port->line].port.ops = &serial_txx9_pops;
|
||||
serial_txx9_ports[port->line].port.flags |=
|
||||
serial_txx9_ports[port->line] = *port;
|
||||
serial_txx9_ports[port->line].ops = &serial_txx9_pops;
|
||||
serial_txx9_ports[port->line].flags |=
|
||||
UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1012,14 +979,14 @@ static DEFINE_MUTEX(serial_txx9_mutex);
|
|||
static int serial_txx9_register_port(struct uart_port *port)
|
||||
{
|
||||
int i;
|
||||
struct uart_txx9_port *uart;
|
||||
struct uart_port *uart;
|
||||
int ret = -ENOSPC;
|
||||
|
||||
mutex_lock(&serial_txx9_mutex);
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
uart = &serial_txx9_ports[i];
|
||||
if (uart_match_port(&uart->port, port)) {
|
||||
uart_remove_one_port(&serial_txx9_reg, &uart->port);
|
||||
if (uart_match_port(uart, port)) {
|
||||
uart_remove_one_port(&serial_txx9_reg, uart);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1027,24 +994,24 @@ static int serial_txx9_register_port(struct uart_port *port)
|
|||
/* Find unused port */
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
uart = &serial_txx9_ports[i];
|
||||
if (!(uart->port.iobase || uart->port.mapbase))
|
||||
if (!(uart->iobase || uart->mapbase))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < UART_NR) {
|
||||
uart->port.iobase = port->iobase;
|
||||
uart->port.membase = port->membase;
|
||||
uart->port.irq = port->irq;
|
||||
uart->port.uartclk = port->uartclk;
|
||||
uart->port.iotype = port->iotype;
|
||||
uart->port.flags = port->flags
|
||||
uart->iobase = port->iobase;
|
||||
uart->membase = port->membase;
|
||||
uart->irq = port->irq;
|
||||
uart->uartclk = port->uartclk;
|
||||
uart->iotype = port->iotype;
|
||||
uart->flags = port->flags
|
||||
| UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
|
||||
uart->port.mapbase = port->mapbase;
|
||||
uart->mapbase = port->mapbase;
|
||||
if (port->dev)
|
||||
uart->port.dev = port->dev;
|
||||
ret = uart_add_one_port(&serial_txx9_reg, &uart->port);
|
||||
uart->dev = port->dev;
|
||||
ret = uart_add_one_port(&serial_txx9_reg, uart);
|
||||
if (ret == 0)
|
||||
ret = uart->port.line;
|
||||
ret = uart->line;
|
||||
}
|
||||
mutex_unlock(&serial_txx9_mutex);
|
||||
return ret;
|
||||
|
@ -1059,16 +1026,16 @@ static int serial_txx9_register_port(struct uart_port *port)
|
|||
*/
|
||||
static void serial_txx9_unregister_port(int line)
|
||||
{
|
||||
struct uart_txx9_port *uart = &serial_txx9_ports[line];
|
||||
struct uart_port *uart = &serial_txx9_ports[line];
|
||||
|
||||
mutex_lock(&serial_txx9_mutex);
|
||||
uart_remove_one_port(&serial_txx9_reg, &uart->port);
|
||||
uart->port.flags = 0;
|
||||
uart->port.type = PORT_UNKNOWN;
|
||||
uart->port.iobase = 0;
|
||||
uart->port.mapbase = 0;
|
||||
uart->port.membase = NULL;
|
||||
uart->port.dev = NULL;
|
||||
uart_remove_one_port(&serial_txx9_reg, uart);
|
||||
uart->flags = 0;
|
||||
uart->type = PORT_UNKNOWN;
|
||||
uart->iobase = 0;
|
||||
uart->mapbase = 0;
|
||||
uart->membase = NULL;
|
||||
uart->dev = NULL;
|
||||
mutex_unlock(&serial_txx9_mutex);
|
||||
}
|
||||
|
||||
|
@ -1111,9 +1078,9 @@ static int serial_txx9_remove(struct platform_device *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
struct uart_txx9_port *up = &serial_txx9_ports[i];
|
||||
struct uart_port *up = &serial_txx9_ports[i];
|
||||
|
||||
if (up->port.dev == &dev->dev)
|
||||
if (up->dev == &dev->dev)
|
||||
serial_txx9_unregister_port(i);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1125,10 +1092,10 @@ static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
struct uart_txx9_port *up = &serial_txx9_ports[i];
|
||||
struct uart_port *up = &serial_txx9_ports[i];
|
||||
|
||||
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
|
||||
uart_suspend_port(&serial_txx9_reg, &up->port);
|
||||
if (up->type != PORT_UNKNOWN && up->dev == &dev->dev)
|
||||
uart_suspend_port(&serial_txx9_reg, up);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1139,10 +1106,10 @@ static int serial_txx9_resume(struct platform_device *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
struct uart_txx9_port *up = &serial_txx9_ports[i];
|
||||
struct uart_port *up = &serial_txx9_ports[i];
|
||||
|
||||
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
|
||||
uart_resume_port(&serial_txx9_reg, &up->port);
|
||||
if (up->type != PORT_UNKNOWN && up->dev == &dev->dev)
|
||||
uart_resume_port(&serial_txx9_reg, up);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1198,10 +1165,10 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
|
|||
|
||||
static void pciserial_txx9_remove_one(struct pci_dev *dev)
|
||||
{
|
||||
struct uart_txx9_port *up = pci_get_drvdata(dev);
|
||||
struct uart_port *up = pci_get_drvdata(dev);
|
||||
|
||||
if (up) {
|
||||
serial_txx9_unregister_port(up->port.line);
|
||||
serial_txx9_unregister_port(up->line);
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
}
|
||||
|
@ -1209,10 +1176,10 @@ static void pciserial_txx9_remove_one(struct pci_dev *dev)
|
|||
#ifdef CONFIG_PM
|
||||
static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
|
||||
{
|
||||
struct uart_txx9_port *up = pci_get_drvdata(dev);
|
||||
struct uart_port *up = pci_get_drvdata(dev);
|
||||
|
||||
if (up)
|
||||
uart_suspend_port(&serial_txx9_reg, &up->port);
|
||||
uart_suspend_port(&serial_txx9_reg, up);
|
||||
pci_save_state(dev);
|
||||
pci_set_power_state(dev, pci_choose_state(dev, state));
|
||||
return 0;
|
||||
|
@ -1220,12 +1187,12 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
|
|||
|
||||
static int pciserial_txx9_resume_one(struct pci_dev *dev)
|
||||
{
|
||||
struct uart_txx9_port *up = pci_get_drvdata(dev);
|
||||
struct uart_port *up = pci_get_drvdata(dev);
|
||||
|
||||
pci_set_power_state(dev, PCI_D0);
|
||||
pci_restore_state(dev);
|
||||
if (up)
|
||||
uart_resume_port(&serial_txx9_reg, &up->port);
|
||||
uart_resume_port(&serial_txx9_reg, up);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -1255,8 +1222,6 @@ static int __init serial_txx9_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
|
||||
|
||||
ret = uart_register_driver(&serial_txx9_reg);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -1307,9 +1272,9 @@ static void __exit serial_txx9_exit(void)
|
|||
platform_driver_unregister(&serial_txx9_plat_driver);
|
||||
platform_device_unregister(serial_txx9_plat_devs);
|
||||
for (i = 0; i < UART_NR; i++) {
|
||||
struct uart_txx9_port *up = &serial_txx9_ports[i];
|
||||
if (up->port.iobase || up->port.mapbase)
|
||||
uart_remove_one_port(&serial_txx9_reg, &up->port);
|
||||
struct uart_port *up = &serial_txx9_ports[i];
|
||||
if (up->iobase || up->mapbase)
|
||||
uart_remove_one_port(&serial_txx9_reg, up);
|
||||
}
|
||||
|
||||
uart_unregister_driver(&serial_txx9_reg);
|
||||
|
|
|
@ -2293,7 +2293,7 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
|
|||
for_each_sr(sr, s) {
|
||||
for (c = 0; c <= 3; c++) {
|
||||
/* integerized formulas from HSCIF documentation */
|
||||
prediv = sr * (1 << (2 * c + 1));
|
||||
prediv = sr << (2 * c + 1);
|
||||
|
||||
/*
|
||||
* We need to calculate:
|
||||
|
@ -2960,7 +2960,7 @@ static void sci_cleanup_single(struct sci_port *port)
|
|||
|
||||
#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
|
||||
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
|
||||
static void serial_console_putchar(struct uart_port *port, int ch)
|
||||
static void serial_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
sci_poll_put_char(port, ch);
|
||||
}
|
||||
|
|
|
@ -756,7 +756,7 @@ static void sifive_serial_poll_put_char(struct uart_port *port,
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_SERIAL_EARLYCON
|
||||
static void early_sifive_serial_putc(struct uart_port *port, int c)
|
||||
static void early_sifive_serial_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (__ssp_early_readl(port, SIFIVE_SERIAL_TXDATA_OFFS) &
|
||||
SIFIVE_SERIAL_TXDATA_FULL_MASK)
|
||||
|
@ -800,7 +800,7 @@ OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0",
|
|||
|
||||
static struct sifive_serial_port *sifive_serial_console_ports[SIFIVE_SERIAL_MAX_PORTS];
|
||||
|
||||
static void sifive_serial_console_putchar(struct uart_port *port, int ch)
|
||||
static void sifive_serial_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
|
||||
|
||||
|
|
|
@ -984,7 +984,7 @@ static void wait_for_xmitr(struct uart_port *port)
|
|||
} while (status & SPRD_TX_FIFO_CNT_MASK);
|
||||
}
|
||||
|
||||
static void sprd_console_putchar(struct uart_port *port, int ch)
|
||||
static void sprd_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
serial_out(port, SPRD_TXD, ch);
|
||||
|
@ -1058,7 +1058,7 @@ console_initcall(sprd_serial_console_init);
|
|||
#define SPRD_CONSOLE (&sprd_console)
|
||||
|
||||
/* Support for earlycon */
|
||||
static void sprd_putc(struct uart_port *port, int c)
|
||||
static void sprd_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned int timeout = SPRD_TIMEOUT;
|
||||
|
||||
|
|
|
@ -854,7 +854,7 @@ static int asc_serial_resume(struct device *dev)
|
|||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_SERIAL_ST_ASC_CONSOLE
|
||||
static void asc_console_putchar(struct uart_port *port, int ch)
|
||||
static void asc_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
unsigned int timeout = 1000000;
|
||||
|
||||
|
|
|
@ -1641,7 +1641,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_STM32_CONSOLE
|
||||
static void stm32_usart_console_putchar(struct uart_port *port, int ch)
|
||||
static void stm32_usart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
|
@ -1756,6 +1756,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port,
|
|||
if (enable) {
|
||||
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM);
|
||||
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE);
|
||||
mctrl_gpio_enable_irq_wake(stm32_port->gpios);
|
||||
|
||||
/*
|
||||
* When DMA is used for reception, it must be disabled before
|
||||
|
@ -1782,7 +1783,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port,
|
|||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mctrl_gpio_disable_irq_wake(stm32_port->gpios);
|
||||
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM);
|
||||
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,775 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Sunplus SoC UART driver
|
||||
*
|
||||
* Author: Hammer Hsieh <hammerh0314@gmail.com>
|
||||
*
|
||||
* Note1: This driver is 8250-like uart, but are not register compatible.
|
||||
*
|
||||
* Note2: On some buses, for preventing data incoherence, must do a read
|
||||
* for ensure write made it to hardware. In this driver, function startup
|
||||
* and shutdown did not do a read but only do a write directly. For what?
|
||||
* In Sunplus bus communication between memory bus and peripheral bus with
|
||||
* posted write, it will send a specific command after last write command
|
||||
* to make sure write done. Then memory bus identify the specific command
|
||||
* and send done signal back to master device. After master device received
|
||||
* done signal, then proceed next write command. It is no need to do a read
|
||||
* before write.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
/* Register offsets */
|
||||
#define SUP_UART_DATA 0x00
|
||||
#define SUP_UART_LSR 0x04
|
||||
#define SUP_UART_MSR 0x08
|
||||
#define SUP_UART_LCR 0x0C
|
||||
#define SUP_UART_MCR 0x10
|
||||
#define SUP_UART_DIV_L 0x14
|
||||
#define SUP_UART_DIV_H 0x18
|
||||
#define SUP_UART_ISC 0x1C
|
||||
#define SUP_UART_TX_RESIDUE 0x20
|
||||
#define SUP_UART_RX_RESIDUE 0x24
|
||||
|
||||
/* Line Status Register bits */
|
||||
#define SUP_UART_LSR_BC BIT(5) /* break condition status */
|
||||
#define SUP_UART_LSR_FE BIT(4) /* frame error status */
|
||||
#define SUP_UART_LSR_OE BIT(3) /* overrun error status */
|
||||
#define SUP_UART_LSR_PE BIT(2) /* parity error status */
|
||||
#define SUP_UART_LSR_RX BIT(1) /* 1: receive fifo not empty */
|
||||
#define SUP_UART_LSR_TX BIT(0) /* 1: transmit fifo is not full */
|
||||
#define SUP_UART_LSR_TX_NOT_FULL 1
|
||||
#define SUP_UART_LSR_BRK_ERROR_BITS GENMASK(5, 2)
|
||||
|
||||
/* Line Control Register bits */
|
||||
#define SUP_UART_LCR_SBC BIT(5) /* select break condition */
|
||||
|
||||
/* Modem Control Register bits */
|
||||
#define SUP_UART_MCR_RI BIT(3) /* ring indicator */
|
||||
#define SUP_UART_MCR_DCD BIT(2) /* data carrier detect */
|
||||
|
||||
/* Interrupt Status/Control Register bits */
|
||||
#define SUP_UART_ISC_RXM BIT(5) /* RX interrupt enable */
|
||||
#define SUP_UART_ISC_TXM BIT(4) /* TX interrupt enable */
|
||||
#define SUP_UART_ISC_RX BIT(1) /* RX interrupt status */
|
||||
#define SUP_UART_ISC_TX BIT(0) /* TX interrupt status */
|
||||
|
||||
#define SUP_DUMMY_READ BIT(16) /* drop bytes received on a !CREAD port */
|
||||
#define SUP_UART_NR 5
|
||||
|
||||
struct sunplus_uart_port {
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
struct reset_control *rstc;
|
||||
};
|
||||
|
||||
static void sp_uart_put_char(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
writel(ch, port->membase + SUP_UART_DATA);
|
||||
}
|
||||
|
||||
static u32 sunplus_tx_buf_not_full(struct uart_port *port)
|
||||
{
|
||||
unsigned int lsr = readl(port->membase + SUP_UART_LSR);
|
||||
|
||||
return (lsr & SUP_UART_LSR_TX) ? SUP_UART_LSR_TX_NOT_FULL : 0;
|
||||
}
|
||||
|
||||
static unsigned int sunplus_tx_empty(struct uart_port *port)
|
||||
{
|
||||
unsigned int lsr = readl(port->membase + SUP_UART_LSR);
|
||||
|
||||
return (lsr & UART_LSR_TEMT) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static void sunplus_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
unsigned int mcr = readl(port->membase + SUP_UART_MCR);
|
||||
|
||||
if (mctrl & TIOCM_DTR)
|
||||
mcr |= UART_MCR_DTR;
|
||||
else
|
||||
mcr &= ~UART_MCR_DTR;
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
|
||||
if (mctrl & TIOCM_CAR)
|
||||
mcr |= SUP_UART_MCR_DCD;
|
||||
else
|
||||
mcr &= ~SUP_UART_MCR_DCD;
|
||||
|
||||
if (mctrl & TIOCM_RI)
|
||||
mcr |= SUP_UART_MCR_RI;
|
||||
else
|
||||
mcr &= ~SUP_UART_MCR_RI;
|
||||
|
||||
if (mctrl & TIOCM_LOOP)
|
||||
mcr |= UART_MCR_LOOP;
|
||||
else
|
||||
mcr &= ~UART_MCR_LOOP;
|
||||
|
||||
writel(mcr, port->membase + SUP_UART_MCR);
|
||||
}
|
||||
|
||||
static unsigned int sunplus_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
unsigned int mcr, ret = 0;
|
||||
|
||||
mcr = readl(port->membase + SUP_UART_MCR);
|
||||
|
||||
if (mcr & UART_MCR_DTR)
|
||||
ret |= TIOCM_DTR;
|
||||
|
||||
if (mcr & UART_MCR_RTS)
|
||||
ret |= TIOCM_RTS;
|
||||
|
||||
if (mcr & SUP_UART_MCR_DCD)
|
||||
ret |= TIOCM_CAR;
|
||||
|
||||
if (mcr & SUP_UART_MCR_RI)
|
||||
ret |= TIOCM_RI;
|
||||
|
||||
if (mcr & UART_MCR_LOOP)
|
||||
ret |= TIOCM_LOOP;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sunplus_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int isc;
|
||||
|
||||
isc = readl(port->membase + SUP_UART_ISC);
|
||||
isc &= ~SUP_UART_ISC_TXM;
|
||||
writel(isc, port->membase + SUP_UART_ISC);
|
||||
}
|
||||
|
||||
static void sunplus_start_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int isc;
|
||||
|
||||
isc = readl(port->membase + SUP_UART_ISC);
|
||||
isc |= SUP_UART_ISC_TXM;
|
||||
writel(isc, port->membase + SUP_UART_ISC);
|
||||
}
|
||||
|
||||
static void sunplus_stop_rx(struct uart_port *port)
|
||||
{
|
||||
unsigned int isc;
|
||||
|
||||
isc = readl(port->membase + SUP_UART_ISC);
|
||||
isc &= ~SUP_UART_ISC_RXM;
|
||||
writel(isc, port->membase + SUP_UART_ISC);
|
||||
}
|
||||
|
||||
static void sunplus_break_ctl(struct uart_port *port, int ctl)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int lcr;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
lcr = readl(port->membase + SUP_UART_LCR);
|
||||
|
||||
if (ctl)
|
||||
lcr |= SUP_UART_LCR_SBC; /* start break */
|
||||
else
|
||||
lcr &= ~SUP_UART_LCR_SBC; /* stop break */
|
||||
|
||||
writel(lcr, port->membase + SUP_UART_LCR);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
if (port->x_char) {
|
||||
sp_uart_put_char(port, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
sunplus_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
sp_uart_put_char(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
|
||||
port->icount.tx++;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (sunplus_tx_buf_not_full(port));
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
sunplus_stop_tx(port);
|
||||
}
|
||||
|
||||
static void receive_chars(struct uart_port *port)
|
||||
{
|
||||
unsigned int lsr = readl(port->membase + SUP_UART_LSR);
|
||||
unsigned int ch, flag;
|
||||
|
||||
do {
|
||||
ch = readl(port->membase + SUP_UART_DATA);
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
if (unlikely(lsr & SUP_UART_LSR_BRK_ERROR_BITS)) {
|
||||
if (lsr & SUP_UART_LSR_BC) {
|
||||
lsr &= ~(SUP_UART_LSR_FE | SUP_UART_LSR_PE);
|
||||
port->icount.brk++;
|
||||
flag = TTY_BREAK;
|
||||
if (uart_handle_break(port))
|
||||
goto ignore_char;
|
||||
} else if (lsr & SUP_UART_LSR_PE) {
|
||||
port->icount.parity++;
|
||||
flag = TTY_PARITY;
|
||||
} else if (lsr & SUP_UART_LSR_FE) {
|
||||
port->icount.frame++;
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
|
||||
if (lsr & SUP_UART_LSR_OE)
|
||||
port->icount.overrun++;
|
||||
}
|
||||
|
||||
if (port->ignore_status_mask & SUP_DUMMY_READ)
|
||||
goto ignore_char;
|
||||
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
goto ignore_char;
|
||||
|
||||
uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag);
|
||||
|
||||
ignore_char:
|
||||
lsr = readl(port->membase + SUP_UART_LSR);
|
||||
} while (lsr & SUP_UART_LSR_RX);
|
||||
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static irqreturn_t sunplus_uart_irq(int irq, void *args)
|
||||
{
|
||||
struct uart_port *port = args;
|
||||
unsigned int isc;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
isc = readl(port->membase + SUP_UART_ISC);
|
||||
|
||||
if (isc & SUP_UART_ISC_RX)
|
||||
receive_chars(port);
|
||||
|
||||
if (isc & SUP_UART_ISC_TX)
|
||||
transmit_chars(port);
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sunplus_startup(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int isc = 0;
|
||||
int ret;
|
||||
|
||||
ret = request_irq(port->irq, sunplus_uart_irq, 0, "sunplus_uart", port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
/* isc define Bit[7:4] int setting, Bit[3:0] int status
|
||||
* isc register will clean Bit[3:0] int status after read
|
||||
* only do a write to Bit[7:4] int setting
|
||||
*/
|
||||
isc |= SUP_UART_ISC_RXM;
|
||||
writel(isc, port->membase + SUP_UART_ISC);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sunplus_shutdown(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
/* isc define Bit[7:4] int setting, Bit[3:0] int status
|
||||
* isc register will clean Bit[3:0] int status after read
|
||||
* only do a write to Bit[7:4] int setting
|
||||
*/
|
||||
writel(0, port->membase + SUP_UART_ISC); /* disable all interrupt */
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
free_irq(port->irq, port);
|
||||
}
|
||||
|
||||
static void sunplus_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *oldtermios)
|
||||
{
|
||||
u32 ext, div, div_l, div_h, baud, lcr;
|
||||
u32 clk = port->uartclk;
|
||||
unsigned long flags;
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, oldtermios, 0, port->uartclk / 16);
|
||||
|
||||
/* baud rate = uartclk / ((16 * divisor + 1) + divisor_ext) */
|
||||
clk += baud >> 1;
|
||||
div = clk / baud;
|
||||
ext = div & 0x0F;
|
||||
div = (div >> 4) - 1;
|
||||
div_l = (div & 0xFF) | (ext << 12);
|
||||
div_h = div >> 8;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
lcr = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
lcr |= UART_LCR_STOP;
|
||||
|
||||
if (termios->c_cflag & PARENB) {
|
||||
lcr |= UART_LCR_PARITY;
|
||||
|
||||
if (!(termios->c_cflag & PARODD))
|
||||
lcr |= UART_LCR_EPAR;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
port->read_status_mask = 0;
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= SUP_UART_LSR_PE | SUP_UART_LSR_FE;
|
||||
|
||||
if (termios->c_iflag & (BRKINT | PARMRK))
|
||||
port->read_status_mask |= SUP_UART_LSR_BC;
|
||||
|
||||
/* Characters to ignore */
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= SUP_UART_LSR_FE | SUP_UART_LSR_PE;
|
||||
|
||||
if (termios->c_iflag & IGNBRK) {
|
||||
port->ignore_status_mask |= SUP_UART_LSR_BC;
|
||||
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= SUP_UART_LSR_OE;
|
||||
}
|
||||
|
||||
/* Ignore all characters if CREAD is not set */
|
||||
if ((termios->c_cflag & CREAD) == 0) {
|
||||
port->ignore_status_mask |= SUP_DUMMY_READ;
|
||||
/* flush rx data FIFO */
|
||||
writel(0, port->membase + SUP_UART_RX_RESIDUE);
|
||||
}
|
||||
|
||||
/* Settings for baud rate divisor and lcr */
|
||||
writel(div_h, port->membase + SUP_UART_DIV_H);
|
||||
writel(div_l, port->membase + SUP_UART_DIV_L);
|
||||
writel(lcr, port->membase + SUP_UART_LCR);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void sunplus_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
||||
{
|
||||
int new = termios->c_line;
|
||||
|
||||
if (new == N_PPS)
|
||||
port->flags |= UPF_HARDPPS_CD;
|
||||
else
|
||||
port->flags &= ~UPF_HARDPPS_CD;
|
||||
}
|
||||
|
||||
static const char *sunplus_type(struct uart_port *port)
|
||||
{
|
||||
return port->type == PORT_SUNPLUS ? "sunplus_uart" : NULL;
|
||||
}
|
||||
|
||||
static void sunplus_config_port(struct uart_port *port, int type)
|
||||
{
|
||||
if (type & UART_CONFIG_TYPE)
|
||||
port->type = PORT_SUNPLUS;
|
||||
}
|
||||
|
||||
static int sunplus_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
{
|
||||
if (ser->type != PORT_UNKNOWN && ser->type != PORT_SUNPLUS)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SERIAL_SUNPLUS_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
|
||||
static void wait_for_xmitr(struct uart_port *port)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
/* Wait while FIFO is full or timeout */
|
||||
ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val,
|
||||
(val & SUP_UART_LSR_TX), 1, 10000);
|
||||
|
||||
if (ret == -ETIMEDOUT) {
|
||||
dev_err(port->dev, "Timeout waiting while UART TX FULL\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static void sunplus_poll_put_char(struct uart_port *port, unsigned char data)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
sp_uart_put_char(port, data);
|
||||
}
|
||||
|
||||
static int sunplus_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
unsigned int lsr = readl(port->membase + SUP_UART_LSR);
|
||||
|
||||
if (!(lsr & SUP_UART_LSR_RX))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return readl(port->membase + SUP_UART_DATA);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct uart_ops sunplus_uart_ops = {
|
||||
.tx_empty = sunplus_tx_empty,
|
||||
.set_mctrl = sunplus_set_mctrl,
|
||||
.get_mctrl = sunplus_get_mctrl,
|
||||
.stop_tx = sunplus_stop_tx,
|
||||
.start_tx = sunplus_start_tx,
|
||||
.stop_rx = sunplus_stop_rx,
|
||||
.break_ctl = sunplus_break_ctl,
|
||||
.startup = sunplus_startup,
|
||||
.shutdown = sunplus_shutdown,
|
||||
.set_termios = sunplus_set_termios,
|
||||
.set_ldisc = sunplus_set_ldisc,
|
||||
.type = sunplus_type,
|
||||
.config_port = sunplus_config_port,
|
||||
.verify_port = sunplus_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_put_char = sunplus_poll_put_char,
|
||||
.poll_get_char = sunplus_poll_get_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
|
||||
struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR];
|
||||
|
||||
static void sunplus_uart_console_putchar(struct uart_port *port,
|
||||
unsigned char ch)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
sp_uart_put_char(port, ch);
|
||||
}
|
||||
|
||||
static void sunplus_console_write(struct console *co,
|
||||
const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
unsigned long flags;
|
||||
int locked = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (sunplus_console_ports[co->index]->port.sysrq)
|
||||
locked = 0;
|
||||
else if (oops_in_progress)
|
||||
locked = spin_trylock(&sunplus_console_ports[co->index]->port.lock);
|
||||
else
|
||||
spin_lock(&sunplus_console_ports[co->index]->port.lock);
|
||||
|
||||
uart_console_write(&sunplus_console_ports[co->index]->port, s, count,
|
||||
sunplus_uart_console_putchar);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&sunplus_console_ports[co->index]->port.lock);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int __init sunplus_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct sunplus_uart_port *sup;
|
||||
int baud = 115200;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
|
||||
if (co->index < 0 || co->index >= SUP_UART_NR)
|
||||
return -EINVAL;
|
||||
|
||||
sup = sunplus_console_ports[co->index];
|
||||
if (!sup)
|
||||
return -ENODEV;
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
return uart_set_options(&sup->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver sunplus_uart_driver;
|
||||
static struct console sunplus_uart_console = {
|
||||
.name = "ttySUP",
|
||||
.write = sunplus_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = sunplus_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &sunplus_uart_driver
|
||||
};
|
||||
|
||||
#define SERIAL_SUNPLUS_CONSOLE (&sunplus_uart_console)
|
||||
#else
|
||||
#define SERIAL_SUNPLUS_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
static struct uart_driver sunplus_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "sunplus_uart",
|
||||
.dev_name = "ttySUP",
|
||||
.major = TTY_MAJOR,
|
||||
.minor = 64,
|
||||
.nr = SUP_UART_NR,
|
||||
.cons = SERIAL_SUNPLUS_CONSOLE,
|
||||
};
|
||||
|
||||
static void sunplus_uart_disable_unprepare(void *data)
|
||||
{
|
||||
clk_disable_unprepare(data);
|
||||
}
|
||||
|
||||
static void sunplus_uart_reset_control_assert(void *data)
|
||||
{
|
||||
reset_control_assert(data);
|
||||
}
|
||||
|
||||
static int sunplus_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sunplus_uart_port *sup;
|
||||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
int ret, irq;
|
||||
|
||||
pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
|
||||
if (pdev->id < 0 || pdev->id >= SUP_UART_NR)
|
||||
return -EINVAL;
|
||||
|
||||
sup = devm_kzalloc(&pdev->dev, sizeof(*sup), GFP_KERNEL);
|
||||
if (!sup)
|
||||
return -ENOMEM;
|
||||
|
||||
sup->clk = devm_clk_get_optional(&pdev->dev, NULL);
|
||||
if (IS_ERR(sup->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(sup->clk), "clk not found\n");
|
||||
|
||||
ret = clk_prepare_enable(sup->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_disable_unprepare, sup->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sup->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(sup->rstc))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(sup->rstc), "rstc not found\n");
|
||||
|
||||
port = &sup->port;
|
||||
|
||||
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(port->membase))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(port->membase), "membase not found\n");
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
port->mapbase = res->start;
|
||||
port->uartclk = clk_get_rate(sup->clk);
|
||||
port->line = pdev->id;
|
||||
port->irq = irq;
|
||||
port->dev = &pdev->dev;
|
||||
port->iotype = UPIO_MEM;
|
||||
port->ops = &sunplus_uart_ops;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->fifosize = 128;
|
||||
|
||||
ret = reset_control_deassert(sup->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_reset_control_assert, sup->rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
|
||||
sunplus_console_ports[sup->port.line] = sup;
|
||||
#endif
|
||||
|
||||
platform_set_drvdata(pdev, &sup->port);
|
||||
|
||||
ret = uart_add_one_port(&sunplus_uart_driver, &sup->port);
|
||||
#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
|
||||
if (ret)
|
||||
sunplus_console_ports[sup->port.line] = NULL;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sunplus_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sunplus_uart_port *sup = platform_get_drvdata(pdev);
|
||||
|
||||
uart_remove_one_port(&sunplus_uart_driver, &sup->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sunplus_uart_suspend(struct device *dev)
|
||||
{
|
||||
struct sunplus_uart_port *sup = dev_get_drvdata(dev);
|
||||
|
||||
if (!uart_console(&sup->port))
|
||||
uart_suspend_port(&sunplus_uart_driver, &sup->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused sunplus_uart_resume(struct device *dev)
|
||||
{
|
||||
struct sunplus_uart_port *sup = dev_get_drvdata(dev);
|
||||
|
||||
if (!uart_console(&sup->port))
|
||||
uart_resume_port(&sunplus_uart_driver, &sup->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sunplus_uart_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sunplus_uart_suspend, sunplus_uart_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id sp_uart_of_match[] = {
|
||||
{ .compatible = "sunplus,sp7021-uart" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sp_uart_of_match);
|
||||
|
||||
static struct platform_driver sunplus_uart_platform_driver = {
|
||||
.probe = sunplus_uart_probe,
|
||||
.remove = sunplus_uart_remove,
|
||||
.driver = {
|
||||
.name = "sunplus_uart",
|
||||
.of_match_table = sp_uart_of_match,
|
||||
.pm = &sunplus_uart_pm_ops,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init sunplus_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&sunplus_uart_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&sunplus_uart_platform_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&sunplus_uart_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(sunplus_uart_init);
|
||||
|
||||
static void __exit sunplus_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&sunplus_uart_platform_driver);
|
||||
uart_unregister_driver(&sunplus_uart_driver);
|
||||
}
|
||||
module_exit(sunplus_uart_exit);
|
||||
|
||||
#ifdef CONFIG_SERIAL_EARLYCON
|
||||
static void sunplus_uart_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val,
|
||||
(val & UART_LSR_TEMT), 1, 10000);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
writel(c, port->membase + SUP_UART_DATA);
|
||||
}
|
||||
|
||||
static void sunplus_uart_early_write(struct console *con, const char *s, unsigned int n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, sunplus_uart_putc);
|
||||
}
|
||||
|
||||
static int __init
|
||||
sunplus_uart_early_setup(struct earlycon_device *dev, const char *opt)
|
||||
{
|
||||
if (!(dev->port.membase || dev->port.iobase))
|
||||
return -ENODEV;
|
||||
|
||||
dev->con->write = sunplus_uart_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
OF_EARLYCON_DECLARE(sunplus_uart, "sunplus,sp7021-uart", sunplus_uart_early_setup);
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION("Sunplus UART driver");
|
||||
MODULE_AUTHOR("Hammer Hsieh <hammerh0314@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -846,7 +846,7 @@ static struct uart_sunsab_port *sunsab_ports;
|
|||
|
||||
#ifdef CONFIG_SERIAL_SUNSAB_CONSOLE
|
||||
|
||||
static void sunsab_console_putchar(struct uart_port *port, int c)
|
||||
static void sunsab_console_putchar(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
|
|
|
@ -1281,7 +1281,7 @@ static void wait_for_xmitr(struct uart_sunsu_port *up)
|
|||
}
|
||||
}
|
||||
|
||||
static void sunsu_console_putchar(struct uart_port *port, int ch)
|
||||
static void sunsu_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
|
|
|
@ -100,7 +100,7 @@ struct uart_sunzilog_port {
|
|||
#endif
|
||||
};
|
||||
|
||||
static void sunzilog_putchar(struct uart_port *port, int ch);
|
||||
static void sunzilog_putchar(struct uart_port *port, unsigned char ch);
|
||||
|
||||
#define ZILOG_CHANNEL_FROM_PORT(PORT) ((struct zilog_channel __iomem *)((PORT)->membase))
|
||||
#define UART_ZILOG(PORT) ((struct uart_sunzilog_port *)(PORT))
|
||||
|
@ -1125,7 +1125,7 @@ static void sunzilog_free_tables(void)
|
|||
|
||||
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
|
||||
|
||||
static void __maybe_unused sunzilog_putchar(struct uart_port *port, int ch)
|
||||
static void __maybe_unused sunzilog_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
int loops = ZS_PUT_CHAR_MAX_DELAY;
|
||||
|
|
|
@ -482,7 +482,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
|
|||
"timeout waiting for TX buffer empty\n");
|
||||
}
|
||||
|
||||
static void ulite_console_putchar(struct uart_port *port, int ch)
|
||||
static void ulite_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
ulite_console_wait_tx(port);
|
||||
uart_out32(ch, ULITE_TX, port);
|
||||
|
@ -558,7 +558,7 @@ static struct console ulite_console = {
|
|||
.data = &ulite_uart_driver,
|
||||
};
|
||||
|
||||
static void early_uartlite_putc(struct uart_port *port, int c)
|
||||
static void early_uartlite_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
/*
|
||||
* Limit how many times we'll spin waiting for TX FIFO status.
|
||||
|
|
|
@ -504,20 +504,7 @@ static void siu_set_termios(struct uart_port *port, struct ktermios *new,
|
|||
unsigned long flags;
|
||||
|
||||
c_cflag = new->c_cflag;
|
||||
switch (c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr = UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr = UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr = UART_LCR_WLEN7;
|
||||
break;
|
||||
default:
|
||||
lcr = UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
lcr = UART_LCR_WLEN(tty_get_char_size(c_cflag));
|
||||
|
||||
if (c_cflag & CSTOPB)
|
||||
lcr |= UART_LCR_STOP;
|
||||
|
@ -743,7 +730,7 @@ static void wait_for_xmitr(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
static void siu_console_putchar(struct uart_port *port, int ch)
|
||||
static void siu_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
siu_write(port, UART_TX, ch);
|
||||
|
|
|
@ -484,7 +484,7 @@ static void wait_for_xmitr(struct uart_port *port)
|
|||
} while (status & 0x10);
|
||||
}
|
||||
|
||||
static void vt8500_console_putchar(struct uart_port *port, int c)
|
||||
static void vt8500_console_putchar(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
writeb(c, port->membase + VT8500_TXFIFO);
|
||||
|
|
|
@ -1142,7 +1142,7 @@ static struct uart_driver cdns_uart_uart_driver;
|
|||
* @port: Handle to the uart port structure
|
||||
* @ch: Character to be written
|
||||
*/
|
||||
static void cdns_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void cdns_uart_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)
|
||||
cpu_relax();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue