forked from Minki/linux
TTY/Serial driver patches for 3.16-rc1
Here is the big tty / serial driver pull request for 3.16-rc1. A variety of different serial driver fixes and updates and additions, nothing huge, and no real major core tty changes at all. All have been in linux-next for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEABECAAYFAlONXgoACgkQMUfUDdst+ymdSwCgwL0xmWjFYr/UbJ4LslOZ29Q4 BFQAoKyYe9LsfEyodBPabxJjKUtj1htz =ZGSN -----END PGP SIGNATURE----- Merge tag 'tty-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty into next Pull tty/serial driver updates from Greg KH: "Here is the big tty / serial driver pull request for 3.16-rc1. A variety of different serial driver fixes and updates and additions, nothing huge, and no real major core tty changes at all. All have been in linux-next for a while" * tag 'tty-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (84 commits) Revert "serial: imx: remove the DMA wait queue" serial: kgdb_nmi: Improve console integration with KDB I/O serial: kgdb_nmi: Switch from tasklets to real timers serial: kgdb_nmi: Use container_of() to locate private data serial: cpm_uart: No LF conversion in put_poll_char() serial: sirf: Fix compilation failure console: Remove superfluous readonly check console: Use explicit pointer type for vc_uni_pagedir* fields vgacon: Fix & cleanup refcounting ARM: tty: Move HVC DCC assembly to arch/arm tty/hvc/hvc_console: Fix wakeup of HVC thread on hvc_kick() drivers/tty/n_hdlc.c: replace kmalloc/memset by kzalloc vt: emulate 8- and 24-bit colour codes. printk/of_serial: fix serial console cessation part way through boot. serial: 8250_dma: check the result of TX buffer mapping serial: uart: add hw flow control support configuration tty/serial: at91: add interrupts for modem control lines tty/serial: at91: use mctrl_gpio helpers tty/serial: Add GPIOLIB helpers for controlling modem lines ARM: at91: gpio: implement get_direction ...
This commit is contained in:
commit
49eb7b0750
@ -13,8 +13,9 @@ Required properties:
|
||||
Optional properties:
|
||||
- atmel,use-dma-rx: use of PDC or DMA for receiving data
|
||||
- atmel,use-dma-tx: use of PDC or DMA for transmitting data
|
||||
- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral
|
||||
function pin for the USART RTS feature. If unsure, don't specify this property.
|
||||
- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively.
|
||||
It will use specified PIO instead of the peripheral function pin for the USART feature.
|
||||
If unsure, don't specify this property.
|
||||
- add dma bindings for dma transfer:
|
||||
- dmas: DMA specifier, consisting of a phandle to DMA controller node,
|
||||
memory peripheral interface and USART DMA channel ID, FIFO configuration.
|
||||
@ -35,7 +36,12 @@ Example:
|
||||
clock-names = "usart";
|
||||
atmel,use-dma-rx;
|
||||
atmel,use-dma-tx;
|
||||
rts-gpios = <&pioD 15 0>;
|
||||
rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
|
||||
cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
|
||||
dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>;
|
||||
dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
|
||||
dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>;
|
||||
rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
- use DMA:
|
||||
|
33
Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt
Normal file
33
Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt
Normal file
@ -0,0 +1,33 @@
|
||||
* NXP SC16IS7xx advanced Universal Asynchronous Receiver-Transmitter (UART)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
- "nxp,sc16is740" for NXP SC16IS740,
|
||||
- "nxp,sc16is741" for NXP SC16IS741,
|
||||
- "nxp,sc16is750" for NXP SC16IS750,
|
||||
- "nxp,sc16is752" for NXP SC16IS752,
|
||||
- "nxp,sc16is760" for NXP SC16IS760,
|
||||
- "nxp,sc16is762" for NXP SC16IS762.
|
||||
- reg: I2C address of the SC16IS7xx device.
|
||||
- interrupt-parent: The phandle for the interrupt controller that
|
||||
services interrupts for this IC.
|
||||
- interrupts: Should contain the UART interrupt
|
||||
- clocks: Reference to the IC source clock.
|
||||
|
||||
Optional properties:
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be two. The first cell is the GPIO number and
|
||||
the second cell is used to specify the GPIO polarity:
|
||||
0 = active high,
|
||||
1 = active low.
|
||||
|
||||
Example:
|
||||
sc16is750: sc16is750@51 {
|
||||
compatible = "nxp,sc16is750";
|
||||
reg = <0x51>;
|
||||
clocks = <&clk20m>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
@ -37,6 +37,7 @@ Optional properties:
|
||||
- auto-flow-control: one way to enable automatic flow control support. The
|
||||
driver is allowed to detect support for the capability even without this
|
||||
property.
|
||||
- has-hw-flow-control: the hardware has flow control capability.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -4,6 +4,7 @@ Required properties:
|
||||
|
||||
- compatible: Must contain one of the following:
|
||||
|
||||
- "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART.
|
||||
- "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART.
|
||||
- "renesas,scifa-r8a7790" for R8A7790 (R-Car H2) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7790" for R8A7790 (R-Car H2) SCIFB compatible UART.
|
||||
|
@ -883,6 +883,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
which are not unmapped.
|
||||
|
||||
earlycon= [KNL] Output early console device and options.
|
||||
|
||||
uart[8250],io,<addr>[,options]
|
||||
uart[8250],mmio,<addr>[,options]
|
||||
uart[8250],mmio32,<addr>[,options]
|
||||
@ -892,6 +893,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
(mmio) or 32-bit (mmio32).
|
||||
The options are the same as for ttyS, above.
|
||||
|
||||
pl011,<addr>
|
||||
Start an early, polled-mode console on a pl011 serial
|
||||
port at the specified address. The pl011 serial port
|
||||
must already be setup and configured. Options are not
|
||||
yet supported.
|
||||
|
||||
smh Use ARM semihosting calls for early console.
|
||||
|
||||
earlyprintk= [X86,SH,BLACKFIN,ARM,M68k]
|
||||
earlyprintk=vga
|
||||
earlyprintk=efi
|
||||
|
@ -429,3 +429,28 @@ thus:
|
||||
struct uart_port port;
|
||||
int my_stuff;
|
||||
};
|
||||
|
||||
Modem control lines via GPIO
|
||||
----------------------------
|
||||
|
||||
Some helpers are provided in order to set/get modem control lines via GPIO.
|
||||
|
||||
mctrl_gpio_init(dev, idx):
|
||||
This will get the {cts,rts,...}-gpios from device tree if they are
|
||||
present and request them, set direction etc, and return an
|
||||
allocated structure. devm_* functions are used, so there's no need
|
||||
to call mctrl_gpio_free().
|
||||
|
||||
mctrl_gpio_free(dev, gpios):
|
||||
This will free the requested gpios in mctrl_gpio_init().
|
||||
As devm_* function are used, there's generally no need to call
|
||||
this function.
|
||||
|
||||
mctrl_gpio_to_gpiod(gpios, gidx)
|
||||
This returns the gpio structure associated to the modem line index.
|
||||
|
||||
mctrl_gpio_set(gpios, mctrl):
|
||||
This will sets the gpios according to the mctrl state.
|
||||
|
||||
mctrl_gpio_get(gpios, mctrl):
|
||||
This will update mctrl with the gpios values.
|
||||
|
41
arch/arm/include/asm/dcc.h
Normal file
41
arch/arm/include/asm/dcc.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <asm/barrier.h>
|
||||
|
||||
static inline u32 __dcc_getstatus(void)
|
||||
{
|
||||
u32 __ret;
|
||||
asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
|
||||
: "=r" (__ret) : : "cc");
|
||||
|
||||
return __ret;
|
||||
}
|
||||
|
||||
static inline char __dcc_getchar(void)
|
||||
{
|
||||
char __c;
|
||||
|
||||
asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
|
||||
: "=r" (__c));
|
||||
isb();
|
||||
|
||||
return __c;
|
||||
}
|
||||
|
||||
static inline void __dcc_putchar(char c)
|
||||
{
|
||||
asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
|
||||
: /* no output register */
|
||||
: "r" (c));
|
||||
isb();
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c-gpio.h>
|
||||
|
||||
@ -924,7 +925,6 @@ static struct resource dbgu_resources[] = {
|
||||
static struct atmel_uart_data dbgu_data = {
|
||||
.use_dma_tx = 0,
|
||||
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
|
||||
@ -963,7 +963,14 @@ static struct resource uart0_resources[] = {
|
||||
static struct atmel_uart_data uart0_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table uart0_gpios_table = {
|
||||
.dev_id = "atmel_usart",
|
||||
.table = {
|
||||
GPIO_LOOKUP("pioA", 21, "rts", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static u64 uart0_dmamask = DMA_BIT_MASK(32);
|
||||
@ -994,7 +1001,7 @@ static inline void configure_usart0_pins(unsigned pins)
|
||||
* We need to drive the pin manually. The serial driver will driver
|
||||
* this to high when initializing.
|
||||
*/
|
||||
uart0_data.rts_gpio = AT91_PIN_PA21;
|
||||
gpiod_add_lookup_table(&uart0_gpios_table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1014,7 +1021,6 @@ static struct resource uart1_resources[] = {
|
||||
static struct atmel_uart_data uart1_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart1_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1066,7 +1072,6 @@ static struct resource uart2_resources[] = {
|
||||
static struct atmel_uart_data uart2_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart2_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1110,7 +1115,6 @@ static struct resource uart3_resources[] = {
|
||||
static struct atmel_uart_data uart3_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart3_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -819,7 +819,6 @@ static struct resource dbgu_resources[] = {
|
||||
static struct atmel_uart_data dbgu_data = {
|
||||
.use_dma_tx = 0,
|
||||
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
|
||||
@ -858,7 +857,6 @@ static struct resource uart0_resources[] = {
|
||||
static struct atmel_uart_data uart0_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart0_dmamask = DMA_BIT_MASK(32);
|
||||
@ -910,7 +908,6 @@ static struct resource uart1_resources[] = {
|
||||
static struct atmel_uart_data uart1_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart1_dmamask = DMA_BIT_MASK(32);
|
||||
@ -954,7 +951,6 @@ static struct resource uart2_resources[] = {
|
||||
static struct atmel_uart_data uart2_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart2_dmamask = DMA_BIT_MASK(32);
|
||||
@ -998,7 +994,6 @@ static struct resource uart3_resources[] = {
|
||||
static struct atmel_uart_data uart3_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart3_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1042,7 +1037,6 @@ static struct resource uart4_resources[] = {
|
||||
static struct atmel_uart_data uart4_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart4_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1081,7 +1075,6 @@ static struct resource uart5_resources[] = {
|
||||
static struct atmel_uart_data uart5_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart5_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -881,7 +881,6 @@ static struct resource dbgu_resources[] = {
|
||||
static struct atmel_uart_data dbgu_data = {
|
||||
.use_dma_tx = 0,
|
||||
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
|
||||
@ -920,7 +919,6 @@ static struct resource uart0_resources[] = {
|
||||
static struct atmel_uart_data uart0_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart0_dmamask = DMA_BIT_MASK(32);
|
||||
@ -964,7 +962,6 @@ static struct resource uart1_resources[] = {
|
||||
static struct atmel_uart_data uart1_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart1_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1008,7 +1005,6 @@ static struct resource uart2_resources[] = {
|
||||
static struct atmel_uart_data uart2_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart2_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -1326,7 +1326,6 @@ static struct resource dbgu_resources[] = {
|
||||
static struct atmel_uart_data dbgu_data = {
|
||||
.use_dma_tx = 0,
|
||||
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1365,7 +1364,6 @@ static struct resource uart0_resources[] = {
|
||||
static struct atmel_uart_data uart0_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart0_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1409,7 +1407,6 @@ static struct resource uart1_resources[] = {
|
||||
static struct atmel_uart_data uart1_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart1_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1453,7 +1450,6 @@ static struct resource uart2_resources[] = {
|
||||
static struct atmel_uart_data uart2_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart2_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -1528,7 +1528,6 @@ static struct resource dbgu_resources[] = {
|
||||
static struct atmel_uart_data dbgu_data = {
|
||||
.use_dma_tx = 0,
|
||||
.use_dma_rx = 0,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1567,7 +1566,6 @@ static struct resource uart0_resources[] = {
|
||||
static struct atmel_uart_data uart0_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart0_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1611,7 +1609,6 @@ static struct resource uart1_resources[] = {
|
||||
static struct atmel_uart_data uart1_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart1_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1655,7 +1652,6 @@ static struct resource uart2_resources[] = {
|
||||
static struct atmel_uart_data uart2_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart2_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1699,7 +1695,6 @@ static struct resource uart3_resources[] = {
|
||||
static struct atmel_uart_data uart3_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart3_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -993,7 +993,6 @@ static struct resource dbgu_resources[] = {
|
||||
static struct atmel_uart_data dbgu_data = {
|
||||
.use_dma_tx = 0,
|
||||
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 dbgu_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1032,7 +1031,6 @@ static struct resource uart0_resources[] = {
|
||||
static struct atmel_uart_data uart0_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart0_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1084,7 +1082,6 @@ static struct resource uart1_resources[] = {
|
||||
static struct atmel_uart_data uart1_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart1_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1128,7 +1125,6 @@ static struct resource uart2_resources[] = {
|
||||
static struct atmel_uart_data uart2_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart2_dmamask = DMA_BIT_MASK(32);
|
||||
@ -1172,7 +1168,6 @@ static struct resource uart3_resources[] = {
|
||||
static struct atmel_uart_data uart3_data = {
|
||||
.use_dma_tx = 1,
|
||||
.use_dma_rx = 1,
|
||||
.rts_gpio = -EINVAL,
|
||||
};
|
||||
|
||||
static u64 uart3_dmamask = DMA_BIT_MASK(32);
|
||||
|
@ -50,6 +50,7 @@ static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
|
||||
static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
|
||||
static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
|
||||
static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
|
||||
static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset);
|
||||
static int at91_gpiolib_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int val);
|
||||
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
|
||||
@ -61,6 +62,7 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
|
||||
.chip = { \
|
||||
.label = name, \
|
||||
.request = at91_gpiolib_request, \
|
||||
.get_direction = at91_gpiolib_get_direction, \
|
||||
.direction_input = at91_gpiolib_direction_input, \
|
||||
.direction_output = at91_gpiolib_direction_output, \
|
||||
.get = at91_gpiolib_get, \
|
||||
@ -800,6 +802,17 @@ static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
|
||||
void __iomem *pio = at91_gpio->regbase;
|
||||
unsigned mask = 1 << offset;
|
||||
u32 osr;
|
||||
|
||||
osr = __raw_readl(pio + PIO_OSR);
|
||||
return !(osr & mask);
|
||||
}
|
||||
|
||||
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
|
@ -112,6 +112,9 @@ config IOMMU_HELPER
|
||||
config KERNEL_MODE_NEON
|
||||
def_bool y
|
||||
|
||||
config FIX_EARLYCON_MEM
|
||||
def_bool y
|
||||
|
||||
source "init/Kconfig"
|
||||
|
||||
source "kernel/Kconfig.freezer"
|
||||
|
@ -20,15 +20,6 @@ config STRICT_DEVMEM
|
||||
|
||||
If in doubt, say Y.
|
||||
|
||||
config EARLY_PRINTK
|
||||
bool "Early printk support"
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to have an early console using the
|
||||
earlyprintk=<name>[,<addr>][,<options>] kernel parameter. It
|
||||
is assumed that the early console device has been initialised
|
||||
by the boot loader prior to starting the Linux kernel.
|
||||
|
||||
config PID_IN_CONTEXTIDR
|
||||
bool "Write the current PID to the CONTEXTIDR register"
|
||||
help
|
||||
|
@ -18,7 +18,6 @@ arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
|
||||
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
|
||||
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
|
||||
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
|
||||
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
|
||||
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
arm64-obj-$(CONFIG_KGDB) += kgdb.o
|
||||
|
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Earlyprintk support.
|
||||
*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
* Author: Catalin Marinas <catalin.marinas@arm.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/amba/serial.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include <asm/fixmap.h>
|
||||
|
||||
static void __iomem *early_base;
|
||||
static void (*printch)(char ch);
|
||||
|
||||
/*
|
||||
* PL011 single character TX.
|
||||
*/
|
||||
static void pl011_printch(char ch)
|
||||
{
|
||||
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF)
|
||||
;
|
||||
writeb_relaxed(ch, early_base + UART01x_DR);
|
||||
while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Semihosting-based debug console
|
||||
*/
|
||||
static void smh_printch(char ch)
|
||||
{
|
||||
asm volatile("mov x1, %0\n"
|
||||
"mov x0, #3\n"
|
||||
"hlt 0xf000\n"
|
||||
: : "r" (&ch) : "x0", "x1", "memory");
|
||||
}
|
||||
|
||||
/*
|
||||
* 8250/16550 (8-bit aligned registers) single character TX.
|
||||
*/
|
||||
static void uart8250_8bit_printch(char ch)
|
||||
{
|
||||
while (!(readb_relaxed(early_base + UART_LSR) & UART_LSR_THRE))
|
||||
;
|
||||
writeb_relaxed(ch, early_base + UART_TX);
|
||||
}
|
||||
|
||||
/*
|
||||
* 8250/16550 (32-bit aligned registers) single character TX.
|
||||
*/
|
||||
static void uart8250_32bit_printch(char ch)
|
||||
{
|
||||
while (!(readl_relaxed(early_base + (UART_LSR << 2)) & UART_LSR_THRE))
|
||||
;
|
||||
writel_relaxed(ch, early_base + (UART_TX << 2));
|
||||
}
|
||||
|
||||
struct earlycon_match {
|
||||
const char *name;
|
||||
void (*printch)(char ch);
|
||||
};
|
||||
|
||||
static const struct earlycon_match earlycon_match[] __initconst = {
|
||||
{ .name = "pl011", .printch = pl011_printch, },
|
||||
{ .name = "smh", .printch = smh_printch, },
|
||||
{ .name = "uart8250-8bit", .printch = uart8250_8bit_printch, },
|
||||
{ .name = "uart8250-32bit", .printch = uart8250_32bit_printch, },
|
||||
{}
|
||||
};
|
||||
|
||||
static void early_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
||||
while (n-- > 0) {
|
||||
if (*s == '\n')
|
||||
printch('\r');
|
||||
printch(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
static struct console early_console_dev = {
|
||||
.name = "earlycon",
|
||||
.write = early_write,
|
||||
.flags = CON_PRINTBUFFER | CON_BOOT,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse earlyprintk=... parameter in the format:
|
||||
*
|
||||
* <name>[,<addr>][,<options>]
|
||||
*
|
||||
* and register the early console. It is assumed that the UART has been
|
||||
* initialised by the bootloader already.
|
||||
*/
|
||||
static int __init setup_early_printk(char *buf)
|
||||
{
|
||||
const struct earlycon_match *match = earlycon_match;
|
||||
phys_addr_t paddr = 0;
|
||||
|
||||
if (!buf) {
|
||||
pr_warning("No earlyprintk arguments passed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (match->name) {
|
||||
size_t len = strlen(match->name);
|
||||
if (!strncmp(buf, match->name, len)) {
|
||||
buf += len;
|
||||
break;
|
||||
}
|
||||
match++;
|
||||
}
|
||||
if (!match->name) {
|
||||
pr_warning("Unknown earlyprintk arguments: %s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I/O address */
|
||||
if (!strncmp(buf, ",0x", 3)) {
|
||||
char *e;
|
||||
paddr = simple_strtoul(buf + 1, &e, 16);
|
||||
buf = e;
|
||||
}
|
||||
/* no options parsing yet */
|
||||
|
||||
if (paddr)
|
||||
early_base = (void __iomem *)set_fixmap_offset_io(FIX_EARLYCON_MEM_BASE, paddr);
|
||||
|
||||
printch = match->printch;
|
||||
early_console = &early_console_dev;
|
||||
register_console(&early_console_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_param("earlyprintk", setup_early_printk);
|
@ -261,6 +261,9 @@ config ARCH_HWEIGHT_CFLAGS
|
||||
config ARCH_SUPPORTS_UPROBES
|
||||
def_bool y
|
||||
|
||||
config FIX_EARLYCON_MEM
|
||||
def_bool y
|
||||
|
||||
source "init/Kconfig"
|
||||
source "kernel/Kconfig.freezer"
|
||||
|
||||
|
@ -118,10 +118,6 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
|
||||
|
||||
int hci_uart_tx_wakeup(struct hci_uart *hu)
|
||||
{
|
||||
struct tty_struct *tty = hu->tty;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
|
||||
set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
|
||||
return 0;
|
||||
@ -129,6 +125,22 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
schedule_work(&hu->write_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hci_uart_write_work(struct work_struct *work)
|
||||
{
|
||||
struct hci_uart *hu = container_of(work, struct hci_uart, write_work);
|
||||
struct tty_struct *tty = hu->tty;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* REVISIT: should we cope with bad skbs or ->write() returning
|
||||
* and error value ?
|
||||
*/
|
||||
|
||||
restart:
|
||||
clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
|
||||
|
||||
@ -153,7 +165,6 @@ restart:
|
||||
goto restart;
|
||||
|
||||
clear_bit(HCI_UART_SENDING, &hu->tx_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hci_uart_init_work(struct work_struct *work)
|
||||
@ -282,6 +293,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
|
||||
tty->receive_room = 65536;
|
||||
|
||||
INIT_WORK(&hu->init_ready, hci_uart_init_work);
|
||||
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
||||
|
||||
spin_lock_init(&hu->rx_lock);
|
||||
|
||||
@ -319,6 +331,8 @@ static void hci_uart_tty_close(struct tty_struct *tty)
|
||||
if (hdev)
|
||||
hci_uart_close(hdev);
|
||||
|
||||
cancel_work_sync(&hu->write_work);
|
||||
|
||||
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
|
||||
if (hdev) {
|
||||
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||
|
@ -68,6 +68,7 @@ struct hci_uart {
|
||||
unsigned long hdev_flags;
|
||||
|
||||
struct work_struct init_ready;
|
||||
struct work_struct write_work;
|
||||
|
||||
struct hci_uart_proto *proto;
|
||||
void *priv;
|
||||
|
@ -62,6 +62,7 @@ enum parport_pc_pci_cards {
|
||||
timedia_9079a,
|
||||
timedia_9079b,
|
||||
timedia_9079c,
|
||||
wch_ch353_1s1p,
|
||||
wch_ch353_2s1p,
|
||||
sunix_2s1p,
|
||||
};
|
||||
@ -148,6 +149,7 @@ static struct parport_pc_pci cards[] = {
|
||||
/* timedia_9079a */ { 1, { { 2, 3 }, } },
|
||||
/* timedia_9079b */ { 1, { { 2, 3 }, } },
|
||||
/* timedia_9079c */ { 1, { { 2, 3 }, } },
|
||||
/* wch_ch353_1s1p*/ { 1, { { 1, -1}, } },
|
||||
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
|
||||
/* sunix_2s1p */ { 1, { { 3, -1 }, } },
|
||||
};
|
||||
@ -253,6 +255,7 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
|
||||
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
|
||||
|
||||
/* WCH CARDS */
|
||||
{ 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p},
|
||||
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
|
||||
|
||||
/*
|
||||
@ -479,6 +482,12 @@ static struct pciserial_board pci_parport_serial_boards[] = {
|
||||
.base_baud = 921600,
|
||||
.uart_offset = 8,
|
||||
},
|
||||
[wch_ch353_1s1p] = {
|
||||
.flags = FL_BASE0|FL_BASE_BARS,
|
||||
.num_ports = 1,
|
||||
.base_baud = 115200,
|
||||
.uart_offset = 8,
|
||||
},
|
||||
[wch_ch353_2s1p] = {
|
||||
.flags = FL_BASE0|FL_BASE_BARS,
|
||||
.num_ports = 2,
|
||||
|
@ -760,10 +760,17 @@ static int khvcd(void *unused)
|
||||
if (poll_mask == 0)
|
||||
schedule();
|
||||
else {
|
||||
unsigned long j_timeout;
|
||||
|
||||
if (timeout < MAX_TIMEOUT)
|
||||
timeout += (timeout >> 6) + 1;
|
||||
|
||||
msleep_interruptible(timeout);
|
||||
/*
|
||||
* We don't use msleep_interruptible otherwise
|
||||
* "kick" will fail to wake us up
|
||||
*/
|
||||
j_timeout = msecs_to_jiffies(timeout) + 1;
|
||||
schedule_timeout_interruptible(j_timeout);
|
||||
}
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
||||
/* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@ -8,20 +8,11 @@
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/dcc.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#include "hvc_console.h"
|
||||
@ -30,35 +21,6 @@
|
||||
#define DCC_STATUS_RX (1 << 30)
|
||||
#define DCC_STATUS_TX (1 << 29)
|
||||
|
||||
static inline u32 __dcc_getstatus(void)
|
||||
{
|
||||
u32 __ret;
|
||||
asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
|
||||
: "=r" (__ret) : : "cc");
|
||||
|
||||
return __ret;
|
||||
}
|
||||
|
||||
|
||||
static inline char __dcc_getchar(void)
|
||||
{
|
||||
char __c;
|
||||
|
||||
asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
|
||||
: "=r" (__c));
|
||||
isb();
|
||||
|
||||
return __c;
|
||||
}
|
||||
|
||||
static inline void __dcc_putchar(char c)
|
||||
{
|
||||
asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char"
|
||||
: /* no output register */
|
||||
: "r" (c));
|
||||
isb();
|
||||
}
|
||||
|
||||
static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
|
||||
{
|
||||
int i;
|
||||
|
@ -848,13 +848,11 @@ static struct n_hdlc *n_hdlc_alloc(void)
|
||||
{
|
||||
struct n_hdlc_buf *buf;
|
||||
int i;
|
||||
struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
|
||||
struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
|
||||
|
||||
if (!n_hdlc)
|
||||
return NULL;
|
||||
|
||||
memset(n_hdlc, 0, sizeof(*n_hdlc));
|
||||
|
||||
n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
|
||||
n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
|
||||
n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
|
||||
@ -952,8 +950,6 @@ static char hdlc_register_ok[] __initdata =
|
||||
KERN_INFO "N_HDLC line discipline registered.\n";
|
||||
static char hdlc_register_fail[] __initdata =
|
||||
KERN_ERR "error registering line discipline: %d\n";
|
||||
static char hdlc_init_fail[] __initdata =
|
||||
KERN_INFO "N_HDLC: init failure %d\n";
|
||||
|
||||
static int __init n_hdlc_init(void)
|
||||
{
|
||||
@ -973,8 +969,6 @@ static int __init n_hdlc_init(void)
|
||||
else
|
||||
printk(hdlc_register_fail, status);
|
||||
|
||||
if (status)
|
||||
printk(hdlc_init_fail, status);
|
||||
return status;
|
||||
|
||||
} /* end of init_module() */
|
||||
|
@ -1926,13 +1926,8 @@ static void serial8250_put_poll_char(struct uart_port *port,
|
||||
wait_for_xmitr(up, BOTH_EMPTY);
|
||||
/*
|
||||
* Send the character out.
|
||||
* If a LF, also do CR...
|
||||
*/
|
||||
serial_port_out(port, UART_TX, c);
|
||||
if (c == 10) {
|
||||
wait_for_xmitr(up, BOTH_EMPTY);
|
||||
serial_port_out(port, UART_TX, 13);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
@ -2338,9 +2333,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
* the trigger, or the MCR RTS bit is cleared. In the case where
|
||||
* the remote UART is not using CTS auto flow control, we must
|
||||
* have sufficient FIFO entries for the latency of the remote
|
||||
* UART to respond. IOW, at least 32 bytes of FIFO.
|
||||
* UART to respond. IOW, at least 32 bytes of FIFO. Also enable
|
||||
* AFE if hw flow control is supported
|
||||
*/
|
||||
if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
|
||||
if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) ||
|
||||
(port->flags & UPF_HARD_FLOW)) {
|
||||
up->mcr &= ~UART_MCR_AFE;
|
||||
if (termios->c_cflag & CRTSCTS)
|
||||
up->mcr |= UART_MCR_AFE;
|
||||
|
@ -192,21 +192,28 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
|
||||
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||
&dma->rx_addr, GFP_KERNEL);
|
||||
if (!dma->rx_buf) {
|
||||
dma_release_channel(dma->rxchan);
|
||||
dma_release_channel(dma->txchan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!dma->rx_buf)
|
||||
goto err;
|
||||
|
||||
/* TX buffer */
|
||||
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
|
||||
p->port.state->xmit.buf,
|
||||
UART_XMIT_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
|
||||
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||
dma->rx_buf, dma->rx_addr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dma_release_channel(dma->rxchan);
|
||||
dma_release_channel(dma->txchan);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_request_dma);
|
||||
|
||||
|
@ -62,6 +62,70 @@ struct dw8250_data {
|
||||
struct uart_8250_dma dma;
|
||||
};
|
||||
|
||||
struct dw8250_acpi_desc {
|
||||
void (*set_termios)(struct uart_port *p, struct ktermios *termios,
|
||||
struct ktermios *old);
|
||||
};
|
||||
|
||||
#define BYT_PRV_CLK 0x800
|
||||
#define BYT_PRV_CLK_EN (1 << 0)
|
||||
#define BYT_PRV_CLK_M_VAL_SHIFT 1
|
||||
#define BYT_PRV_CLK_N_VAL_SHIFT 16
|
||||
#define BYT_PRV_CLK_UPDATE (1 << 31)
|
||||
|
||||
static void byt_set_termios(struct uart_port *p, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud = tty_termios_baud_rate(termios);
|
||||
unsigned int m, n;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the
|
||||
* dividers must be adjusted.
|
||||
*
|
||||
* uartclk = (m / n) * 100 MHz, where m <= n
|
||||
*/
|
||||
switch (baud) {
|
||||
case 500000:
|
||||
case 1000000:
|
||||
case 2000000:
|
||||
case 4000000:
|
||||
m = 64;
|
||||
n = 100;
|
||||
p->uartclk = 64000000;
|
||||
break;
|
||||
case 3500000:
|
||||
m = 56;
|
||||
n = 100;
|
||||
p->uartclk = 56000000;
|
||||
break;
|
||||
case 1500000:
|
||||
case 3000000:
|
||||
m = 48;
|
||||
n = 100;
|
||||
p->uartclk = 48000000;
|
||||
break;
|
||||
case 2500000:
|
||||
m = 40;
|
||||
n = 100;
|
||||
p->uartclk = 40000000;
|
||||
break;
|
||||
default:
|
||||
m = 2304;
|
||||
n = 3125;
|
||||
p->uartclk = 73728000;
|
||||
}
|
||||
|
||||
/* Reset the clock */
|
||||
reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT);
|
||||
writel(reg, p->membase + BYT_PRV_CLK);
|
||||
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
|
||||
writel(reg, p->membase + BYT_PRV_CLK);
|
||||
|
||||
serial8250_do_set_termios(p, termios, old);
|
||||
}
|
||||
|
||||
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
@ -278,6 +342,7 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
struct uart_port *p = &up->port;
|
||||
struct dw8250_acpi_desc *acpi_desc;
|
||||
|
||||
dw8250_setup_port(up);
|
||||
|
||||
@ -290,14 +355,18 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
p->regshift = 2;
|
||||
|
||||
if (!p->uartclk)
|
||||
p->uartclk = (unsigned int)id->driver_data;
|
||||
|
||||
up->dma = &data->dma;
|
||||
|
||||
up->dma->rxconf.src_maxburst = p->fifosize / 4;
|
||||
up->dma->txconf.dst_maxburst = p->fifosize / 4;
|
||||
|
||||
acpi_desc = (struct dw8250_acpi_desc *)id->driver_data;
|
||||
if (!acpi_desc)
|
||||
return 0;
|
||||
|
||||
if (acpi_desc->set_termios)
|
||||
p->set_termios = acpi_desc->set_termios;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -445,12 +514,16 @@ static const struct of_device_id dw8250_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw8250_of_match);
|
||||
|
||||
static struct dw8250_acpi_desc byt_8250_desc = {
|
||||
.set_termios = byt_set_termios,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id dw8250_acpi_match[] = {
|
||||
{ "INT33C4", 0 },
|
||||
{ "INT33C5", 0 },
|
||||
{ "INT3434", 0 },
|
||||
{ "INT3435", 0 },
|
||||
{ "80860F0A", 0 },
|
||||
{ "80860F0A", (kernel_ulong_t)&byt_8250_desc},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
|
||||
|
@ -35,18 +35,8 @@
|
||||
#include <linux/serial_8250.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/serial.h>
|
||||
#ifdef CONFIG_FIX_EARLYCON_MEM
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/fixmap.h>
|
||||
#endif
|
||||
|
||||
struct early_serial8250_device {
|
||||
struct uart_port port;
|
||||
char options[16]; /* e.g., 115200n8 */
|
||||
unsigned int baud;
|
||||
};
|
||||
|
||||
static struct early_serial8250_device early_device;
|
||||
static struct earlycon_device *early_device;
|
||||
|
||||
unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
|
||||
{
|
||||
@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c)
|
||||
static void __init early_serial8250_write(struct console *console,
|
||||
const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &early_device.port;
|
||||
struct uart_port *port = &early_device->port;
|
||||
unsigned int ier;
|
||||
|
||||
/* Save the IER and disable interrupts */
|
||||
@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port)
|
||||
return (port->uartclk / 16) / quot;
|
||||
}
|
||||
|
||||
static void __init init_port(struct early_serial8250_device *device)
|
||||
static void __init init_port(struct earlycon_device *device)
|
||||
{
|
||||
struct uart_port *port = &device->port;
|
||||
unsigned int divisor;
|
||||
@ -148,128 +138,42 @@ static void __init init_port(struct early_serial8250_device *device)
|
||||
serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
|
||||
}
|
||||
|
||||
static int __init parse_options(struct early_serial8250_device *device,
|
||||
char *options)
|
||||
static int __init early_serial8250_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
struct uart_port *port = &device->port;
|
||||
int mmio, mmio32, length;
|
||||
|
||||
if (!options)
|
||||
return -ENODEV;
|
||||
|
||||
port->uartclk = BASE_BAUD * 16;
|
||||
|
||||
mmio = !strncmp(options, "mmio,", 5);
|
||||
mmio32 = !strncmp(options, "mmio32,", 7);
|
||||
if (mmio || mmio32) {
|
||||
port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
|
||||
port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
|
||||
&options, 0);
|
||||
if (mmio32)
|
||||
port->regshift = 2;
|
||||
#ifdef CONFIG_FIX_EARLYCON_MEM
|
||||
set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
|
||||
port->mapbase & PAGE_MASK);
|
||||
port->membase =
|
||||
(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
|
||||
port->membase += port->mapbase & ~PAGE_MASK;
|
||||
#else
|
||||
port->membase = ioremap_nocache(port->mapbase, 64);
|
||||
if (!port->membase) {
|
||||
printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
|
||||
__func__,
|
||||
(unsigned long long) port->mapbase);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
} else if (!strncmp(options, "io,", 3)) {
|
||||
port->iotype = UPIO_PORT;
|
||||
port->iobase = simple_strtoul(options + 3, &options, 0);
|
||||
mmio = 0;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
options = strchr(options, ',');
|
||||
if (options) {
|
||||
options++;
|
||||
device->baud = simple_strtoul(options, NULL, 0);
|
||||
length = min(strcspn(options, " ") + 1,
|
||||
(size_t)(sizeof(device->options)));
|
||||
strlcpy(device->options, options, length);
|
||||
} else {
|
||||
device->baud = probe_baud(port);
|
||||
snprintf(device->options, sizeof(device->options), "%u",
|
||||
device->baud);
|
||||
}
|
||||
|
||||
if (mmio || mmio32)
|
||||
printk(KERN_INFO
|
||||
"Early serial console at MMIO%s 0x%llx (options '%s')\n",
|
||||
mmio32 ? "32" : "",
|
||||
(unsigned long long)port->mapbase,
|
||||
device->options);
|
||||
else
|
||||
printk(KERN_INFO
|
||||
"Early serial console at I/O port 0x%lx (options '%s')\n",
|
||||
port->iobase,
|
||||
device->options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct console early_serial8250_console __initdata = {
|
||||
.name = "uart",
|
||||
.write = early_serial8250_write,
|
||||
.flags = CON_PRINTBUFFER | CON_BOOT,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
static int __init early_serial8250_setup(char *options)
|
||||
{
|
||||
struct early_serial8250_device *device = &early_device;
|
||||
int err;
|
||||
|
||||
if (device->port.membase || device->port.iobase)
|
||||
if (!(device->port.membase || device->port.iobase))
|
||||
return 0;
|
||||
|
||||
err = parse_options(device, options);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!device->baud)
|
||||
device->baud = probe_baud(&device->port);
|
||||
|
||||
init_port(device);
|
||||
|
||||
early_device = device;
|
||||
device->con->write = early_serial8250_write;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(uart8250, early_serial8250_setup);
|
||||
EARLYCON_DECLARE(uart, early_serial8250_setup);
|
||||
|
||||
int __init setup_early_serial8250_console(char *cmdline)
|
||||
{
|
||||
char *options;
|
||||
int err;
|
||||
char match[] = "uart8250";
|
||||
|
||||
options = strstr(cmdline, "uart8250,");
|
||||
if (!options) {
|
||||
options = strstr(cmdline, "uart,");
|
||||
if (!options)
|
||||
return 0;
|
||||
}
|
||||
if (cmdline && cmdline[4] == ',')
|
||||
match[4] = '\0';
|
||||
|
||||
options = strchr(cmdline, ',') + 1;
|
||||
err = early_serial8250_setup(options);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
register_console(&early_serial8250_console);
|
||||
|
||||
return 0;
|
||||
return setup_earlycon(cmdline, match, early_serial8250_setup);
|
||||
}
|
||||
|
||||
int serial8250_find_port_for_earlycon(void)
|
||||
{
|
||||
struct early_serial8250_device *device = &early_device;
|
||||
struct uart_port *port = &device->port;
|
||||
struct earlycon_device *device = early_device;
|
||||
struct uart_port *port = device ? &device->port : NULL;
|
||||
int line;
|
||||
int ret;
|
||||
|
||||
if (!device->port.membase && !device->port.iobase)
|
||||
if (!port || (!port->membase && !port->iobase))
|
||||
return -ENODEV;
|
||||
|
||||
line = serial8250_find_port(port);
|
||||
@ -284,5 +188,3 @@ int serial8250_find_port_for_earlycon(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
early_param("earlycon", setup_early_serial8250_console);
|
||||
|
@ -1753,6 +1753,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
||||
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
|
||||
#define PCI_DEVICE_ID_INTEL_CE4100_UART 0x2e66
|
||||
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
|
||||
#define PCI_DEVICE_ID_ADVANTECH_PCI3618 0x3618
|
||||
#define PCI_DEVICE_ID_ADVANTECH_PCIf618 0xf618
|
||||
#define PCI_DEVICE_ID_TITAN_200I 0x8028
|
||||
#define PCI_DEVICE_ID_TITAN_400I 0x8048
|
||||
#define PCI_DEVICE_ID_TITAN_800I 0x8088
|
||||
@ -1778,6 +1780,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
||||
#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
|
||||
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
|
||||
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
|
||||
#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
|
||||
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
|
||||
#define PCI_VENDOR_ID_AGESTAR 0x5372
|
||||
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
|
||||
@ -2410,6 +2413,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_omegapci_setup,
|
||||
},
|
||||
/* WCH CH353 1S1P card (16550 clone) */
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_WCH,
|
||||
.device = PCI_DEVICE_ID_WCH_CH353_1S1P,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_wch_ch353_setup,
|
||||
},
|
||||
/* WCH CH353 2S1P card (16550 clone) */
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_WCH,
|
||||
@ -3526,6 +3537,7 @@ static const struct pci_device_id blacklist[] = {
|
||||
|
||||
/* multi-io cards handled by parport_serial */
|
||||
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
|
||||
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -3880,6 +3892,13 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
|
||||
PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
|
||||
pbn_b2_8_921600 },
|
||||
/* Advantech also use 0x3618 and 0xf618 */
|
||||
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
|
||||
PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
|
||||
pbn_b0_4_921600 },
|
||||
{ PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
|
||||
PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
|
||||
pbn_b0_4_921600 },
|
||||
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
|
||||
PCI_SUBVENDOR_ID_CONNECT_TECH,
|
||||
PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
|
||||
|
@ -61,6 +61,7 @@ config SERIAL_8250_CONSOLE
|
||||
bool "Console on 8250/16550 and compatible serial port"
|
||||
depends on SERIAL_8250=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
---help---
|
||||
If you say Y here, it will be possible to use a serial port as the
|
||||
system console (the system console is the device which receives all
|
||||
@ -90,11 +91,6 @@ config SERIAL_8250_CONSOLE
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config FIX_EARLYCON_MEM
|
||||
bool
|
||||
depends on X86
|
||||
default y
|
||||
|
||||
config SERIAL_8250_GSC
|
||||
tristate
|
||||
depends on SERIAL_8250 && GSC
|
||||
|
@ -7,6 +7,13 @@ if TTY
|
||||
menu "Serial drivers"
|
||||
depends on HAS_IOMEM
|
||||
|
||||
config SERIAL_EARLYCON
|
||||
bool
|
||||
help
|
||||
Support for early consoles with the earlycon parameter. This enables
|
||||
the console before standard serial driver is probed. The console is
|
||||
enabled when early_param is processed.
|
||||
|
||||
source "drivers/tty/serial/8250/Kconfig"
|
||||
|
||||
comment "Non-8250 serial port support"
|
||||
@ -53,6 +60,7 @@ config SERIAL_AMBA_PL011_CONSOLE
|
||||
bool "Support for console on AMBA serial port"
|
||||
depends on SERIAL_AMBA_PL011=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
---help---
|
||||
Say Y here if you wish to use an AMBA PrimeCell UART as the system
|
||||
console (the system console is the device which receives all kernel
|
||||
@ -65,6 +73,18 @@ config SERIAL_AMBA_PL011_CONSOLE
|
||||
your boot loader (lilo or loadlin) about how to pass options to the
|
||||
kernel at boot time.)
|
||||
|
||||
config SERIAL_EARLYCON_ARM_SEMIHOST
|
||||
bool "Early console using ARM semihosting"
|
||||
depends on ARM64 || ARM
|
||||
select SERIAL_CORE
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Support for early debug console using ARM semihosting. This enables
|
||||
the console before standard serial driver is probed. This is enabled
|
||||
with "earlycon=smh" on the kernel command line. The console is
|
||||
enabled when early_param is processed.
|
||||
|
||||
config SERIAL_SB1250_DUART
|
||||
tristate "BCM1xxx on-chip DUART serial support"
|
||||
depends on SIBYTE_SB1xxx_SOC=y
|
||||
@ -97,6 +117,7 @@ config SERIAL_ATMEL
|
||||
bool "AT91 / AT32 on-chip serial port support"
|
||||
depends on ARCH_AT91 || AVR32
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO
|
||||
help
|
||||
This enables the driver for the on-chip UARTs of the Atmel
|
||||
AT91 and AT32 processors.
|
||||
@ -1160,6 +1181,16 @@ config SERIAL_SCCNXP_CONSOLE
|
||||
help
|
||||
Support for console on SCCNXP serial ports.
|
||||
|
||||
config SERIAL_SC16IS7XX
|
||||
tristate "SC16IS7xx serial support"
|
||||
depends on I2C
|
||||
select SERIAL_CORE
|
||||
select REGMAP_I2C if I2C
|
||||
help
|
||||
This selects support for SC16IS7xx serial ports.
|
||||
Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
|
||||
SC16IS760 and SC16IS762.
|
||||
|
||||
config SERIAL_BFIN_SPORT
|
||||
tristate "Blackfin SPORT emulate UART"
|
||||
depends on BLACKFIN
|
||||
@ -1323,7 +1354,7 @@ config SERIAL_IFX6X60
|
||||
|
||||
config SERIAL_PCH_UART
|
||||
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
|
||||
depends on PCI
|
||||
depends on PCI && (X86_32 || COMPILE_TEST)
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver is for PCH(Platform controller Hub) UART of Intel EG20T
|
||||
@ -1369,18 +1400,19 @@ config SERIAL_MXS_AUART_CONSOLE
|
||||
Enable a MXS AUART port to be the system console.
|
||||
|
||||
config SERIAL_XILINX_PS_UART
|
||||
tristate "Xilinx PS UART support"
|
||||
tristate "Cadence (Xilinx Zynq) UART support"
|
||||
depends on OF
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver supports the Xilinx PS UART port.
|
||||
This driver supports the Cadence UART. It is found e.g. in Xilinx
|
||||
Zynq.
|
||||
|
||||
config SERIAL_XILINX_PS_UART_CONSOLE
|
||||
bool "Xilinx PS UART console support"
|
||||
bool "Cadence UART console support"
|
||||
depends on SERIAL_XILINX_PS_UART=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
Enable a Xilinx PS UART port to be the system console.
|
||||
Enable a Cadence UART port to be the system console.
|
||||
|
||||
config SERIAL_AR933X
|
||||
tristate "AR933X serial port support"
|
||||
@ -1479,6 +1511,7 @@ config SERIAL_RP2_NR_UARTS
|
||||
|
||||
config SERIAL_FSL_LPUART
|
||||
tristate "Freescale lpuart serial port support"
|
||||
depends on HAS_DMA
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Support for the on-chip lpuart on some Freescale SOCs.
|
||||
@ -1508,6 +1541,20 @@ config SERIAL_ST_ASC_CONSOLE
|
||||
depends on SERIAL_ST_ASC=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
|
||||
config SERIAL_MEN_Z135
|
||||
tristate "MEN 16z135 Support"
|
||||
select SERIAL_CORE
|
||||
depends on MCB
|
||||
help
|
||||
Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core
|
||||
on a MCB carrier.
|
||||
|
||||
This driver can also be build as a module. If so, the module will be called
|
||||
men_z135_uart.ko
|
||||
|
||||
endmenu
|
||||
|
||||
config SERIAL_MCTRL_GPIO
|
||||
tristate
|
||||
|
||||
endif # TTY
|
||||
|
@ -5,6 +5,9 @@
|
||||
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
|
||||
obj-$(CONFIG_SERIAL_21285) += 21285.o
|
||||
|
||||
obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
|
||||
obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
|
||||
|
||||
# These Sparc drivers have to appear before others such as 8250
|
||||
# which share ttySx minor node space. Otherwise console device
|
||||
# names change and other unplesantries.
|
||||
@ -48,6 +51,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
|
||||
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
|
||||
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
|
||||
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
|
||||
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
|
||||
obj-$(CONFIG_SERIAL_JSM) += jsm/
|
||||
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
|
||||
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
|
||||
@ -87,3 +91,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
|
||||
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
|
||||
obj-$(CONFIG_SERIAL_RP2) += rp2.o
|
||||
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
|
||||
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
|
||||
|
||||
# GPIOLIB helpers for modem control lines
|
||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||
|
@ -303,7 +303,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
|
||||
|
||||
/* Optionally make use of an RX channel as well */
|
||||
chan = dma_request_slave_channel(dev, "rx");
|
||||
|
||||
|
||||
if (!chan && plat->dma_rx_param) {
|
||||
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
|
||||
|
||||
@ -2045,6 +2045,34 @@ static struct console amba_console = {
|
||||
};
|
||||
|
||||
#define AMBA_CONSOLE (&amba_console)
|
||||
|
||||
static void pl011_putc(struct uart_port *port, int c)
|
||||
{
|
||||
while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF)
|
||||
;
|
||||
writeb(c, port->membase + UART01x_DR);
|
||||
while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY)
|
||||
;
|
||||
}
|
||||
|
||||
static void pl011_early_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, pl011_putc);
|
||||
}
|
||||
|
||||
static int __init pl011_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = pl011_early_write;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(pl011, pl011_early_console_setup);
|
||||
|
||||
#else
|
||||
#define AMBA_CONSOLE NULL
|
||||
#endif
|
||||
|
@ -43,6 +43,9 @@
|
||||
#include <linux/platform_data/atmel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/ioctls.h>
|
||||
@ -57,6 +60,8 @@
|
||||
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
static void atmel_start_rx(struct uart_port *port);
|
||||
static void atmel_stop_rx(struct uart_port *port);
|
||||
|
||||
@ -162,8 +167,10 @@ struct atmel_uart_port {
|
||||
struct circ_buf rx_ring;
|
||||
|
||||
struct serial_rs485 rs485; /* rs485 settings */
|
||||
int rts_gpio; /* optional RTS GPIO */
|
||||
struct mctrl_gpios *gpios;
|
||||
int gpio_irq[UART_GPIO_MAX];
|
||||
unsigned int tx_done_mask;
|
||||
bool ms_irq_enabled;
|
||||
bool is_usart; /* usart or uart */
|
||||
struct timer_list uart_timer; /* uart timer */
|
||||
int (*prepare_rx)(struct uart_port *port);
|
||||
@ -237,6 +244,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
|
||||
return atmel_port->use_dma_rx;
|
||||
}
|
||||
|
||||
static unsigned int atmel_get_lines_status(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int status, ret = 0;
|
||||
|
||||
status = UART_GET_CSR(port);
|
||||
|
||||
mctrl_gpio_get(atmel_port->gpios, &ret);
|
||||
|
||||
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
|
||||
UART_GPIO_CTS))) {
|
||||
if (ret & TIOCM_CTS)
|
||||
status &= ~ATMEL_US_CTS;
|
||||
else
|
||||
status |= ATMEL_US_CTS;
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
|
||||
UART_GPIO_DSR))) {
|
||||
if (ret & TIOCM_DSR)
|
||||
status &= ~ATMEL_US_DSR;
|
||||
else
|
||||
status |= ATMEL_US_DSR;
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
|
||||
UART_GPIO_RI))) {
|
||||
if (ret & TIOCM_RI)
|
||||
status &= ~ATMEL_US_RI;
|
||||
else
|
||||
status |= ATMEL_US_RI;
|
||||
}
|
||||
|
||||
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
|
||||
UART_GPIO_DCD))) {
|
||||
if (ret & TIOCM_CD)
|
||||
status &= ~ATMEL_US_DCD;
|
||||
else
|
||||
status |= ATMEL_US_DCD;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Enable or disable the rs485 support */
|
||||
void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
||||
{
|
||||
@ -296,17 +347,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
||||
unsigned int mode;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
/*
|
||||
* AT91RM9200 Errata #39: RTS0 is not internally connected
|
||||
* to PA21. We need to drive the pin as a GPIO.
|
||||
*/
|
||||
if (gpio_is_valid(atmel_port->rts_gpio)) {
|
||||
if (mctrl & TIOCM_RTS)
|
||||
gpio_set_value(atmel_port->rts_gpio, 0);
|
||||
else
|
||||
gpio_set_value(atmel_port->rts_gpio, 1);
|
||||
}
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
control |= ATMEL_US_RTSEN;
|
||||
else
|
||||
@ -319,6 +359,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
||||
|
||||
UART_PUT_CR(port, control);
|
||||
|
||||
mctrl_gpio_set(atmel_port->gpios, mctrl);
|
||||
|
||||
/* Local loopback mode? */
|
||||
mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
|
||||
if (mctrl & TIOCM_LOOP)
|
||||
@ -346,7 +388,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
||||
*/
|
||||
static u_int atmel_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
unsigned int status, ret = 0;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int ret = 0, status;
|
||||
|
||||
status = UART_GET_CSR(port);
|
||||
|
||||
@ -362,7 +405,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
|
||||
if (!(status & ATMEL_US_RI))
|
||||
ret |= TIOCM_RI;
|
||||
|
||||
return ret;
|
||||
return mctrl_gpio_get(atmel_port->gpios, &ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -449,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
|
||||
*/
|
||||
static void atmel_enable_ms(struct uart_port *port)
|
||||
{
|
||||
UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
|
||||
| ATMEL_US_DCDIC | ATMEL_US_CTSIC);
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
uint32_t ier = 0;
|
||||
|
||||
/*
|
||||
* Interrupt should not be enabled twice
|
||||
*/
|
||||
if (atmel_port->ms_irq_enabled)
|
||||
return;
|
||||
|
||||
atmel_port->ms_irq_enabled = true;
|
||||
|
||||
if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
|
||||
enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
|
||||
else
|
||||
ier |= ATMEL_US_CTSIC;
|
||||
|
||||
if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
|
||||
enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
|
||||
else
|
||||
ier |= ATMEL_US_DSRIC;
|
||||
|
||||
if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
|
||||
enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
|
||||
else
|
||||
ier |= ATMEL_US_RIIC;
|
||||
|
||||
if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
|
||||
enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
|
||||
else
|
||||
ier |= ATMEL_US_DCDIC;
|
||||
|
||||
UART_PUT_IER(port, ier);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1039,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
|
||||
static irqreturn_t atmel_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int status, pending, pass_counter = 0;
|
||||
bool gpio_handled = false;
|
||||
|
||||
do {
|
||||
status = UART_GET_CSR(port);
|
||||
status = atmel_get_lines_status(port);
|
||||
pending = status & UART_GET_IMR(port);
|
||||
if (!gpio_handled) {
|
||||
/*
|
||||
* Dealing with GPIO interrupt
|
||||
*/
|
||||
if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
|
||||
pending |= ATMEL_US_CTSIC;
|
||||
|
||||
if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
|
||||
pending |= ATMEL_US_DSRIC;
|
||||
|
||||
if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
|
||||
pending |= ATMEL_US_RIIC;
|
||||
|
||||
if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
|
||||
pending |= ATMEL_US_DCDIC;
|
||||
|
||||
gpio_handled = true;
|
||||
}
|
||||
if (!pending)
|
||||
break;
|
||||
|
||||
@ -1523,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
static void atmel_free_gpio_irq(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
if (atmel_port->gpio_irq[i] >= 0)
|
||||
free_irq(atmel_port->gpio_irq[i], port);
|
||||
}
|
||||
|
||||
static int atmel_request_gpio_irq(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
int *irq = atmel_port->gpio_irq;
|
||||
enum mctrl_gpio_idx i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; (i < UART_GPIO_MAX) && !err; i++) {
|
||||
if (irq[i] < 0)
|
||||
continue;
|
||||
|
||||
irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
|
||||
err = request_irq(irq[i], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
|
||||
"atmel_serial", port);
|
||||
if (err)
|
||||
dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
|
||||
irq[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* If something went wrong, rollback.
|
||||
*/
|
||||
while (err && (--i >= 0))
|
||||
if (irq[i] >= 0)
|
||||
free_irq(irq[i], port);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform initialization and enable port for reception
|
||||
*/
|
||||
@ -1539,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
|
||||
* handle an unexpected interrupt
|
||||
*/
|
||||
UART_PUT_IDR(port, -1);
|
||||
atmel_port->ms_irq_enabled = false;
|
||||
|
||||
/*
|
||||
* Allocate the IRQ
|
||||
@ -1550,6 +1683,13 @@ static int atmel_startup(struct uart_port *port)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the GPIO lines IRQ
|
||||
*/
|
||||
retval = atmel_request_gpio_irq(port);
|
||||
if (retval)
|
||||
goto free_irq;
|
||||
|
||||
/*
|
||||
* Initialize DMA (if necessary)
|
||||
*/
|
||||
@ -1568,7 +1708,7 @@ static int atmel_startup(struct uart_port *port)
|
||||
}
|
||||
|
||||
/* Save current CSR for comparison in atmel_tasklet_func() */
|
||||
atmel_port->irq_status_prev = UART_GET_CSR(port);
|
||||
atmel_port->irq_status_prev = atmel_get_lines_status(port);
|
||||
atmel_port->irq_status = atmel_port->irq_status_prev;
|
||||
|
||||
/*
|
||||
@ -1614,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_irq:
|
||||
free_irq(port->irq, port);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1661,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
|
||||
atmel_port->rx_ring.tail = 0;
|
||||
|
||||
/*
|
||||
* Free the interrupt
|
||||
* Free the interrupts
|
||||
*/
|
||||
free_irq(port->irq, port);
|
||||
atmel_free_gpio_irq(port);
|
||||
|
||||
atmel_port->ms_irq_enabled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2324,6 +2472,26 @@ static int atmel_serial_resume(struct platform_device *pdev)
|
||||
#define atmel_serial_resume NULL
|
||||
#endif
|
||||
|
||||
static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
p->gpios = mctrl_gpio_init(dev, 0);
|
||||
if (IS_ERR_OR_NULL(p->gpios))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
|
||||
if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
|
||||
p->gpio_irq[i] = gpiod_to_irq(gpiod);
|
||||
else
|
||||
p->gpio_irq[i] = -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atmel_uart_port *port;
|
||||
@ -2359,25 +2527,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
port = &atmel_ports[ret];
|
||||
port->backup_imr = 0;
|
||||
port->uart.line = ret;
|
||||
port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
|
||||
if (pdata)
|
||||
port->rts_gpio = pdata->rts_gpio;
|
||||
else if (np)
|
||||
port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
|
||||
|
||||
if (gpio_is_valid(port->rts_gpio)) {
|
||||
ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "error requesting RTS GPIO\n");
|
||||
goto err;
|
||||
}
|
||||
/* Default to 1 as RTS is active low */
|
||||
ret = gpio_direction_output(port->rts_gpio, 1);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "error setting up RTS GPIO\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
ret = atmel_init_gpios(port, &pdev->dev);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "%s",
|
||||
"Failed to initialize GPIOs. The serial port may not work as expected");
|
||||
|
||||
ret = atmel_init_port(port, pdev);
|
||||
if (ret)
|
||||
|
@ -971,7 +971,7 @@ static void cpm_uart_config_port(struct uart_port *port, int flags)
|
||||
* Note that this is called with interrupts already disabled
|
||||
*/
|
||||
static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
|
||||
const char *string, u_int count)
|
||||
const char *string, u_int count, bool handle_linefeed)
|
||||
{
|
||||
unsigned int i;
|
||||
cbd_t __iomem *bdp, *bdbase;
|
||||
@ -1013,7 +1013,7 @@ static void cpm_uart_early_write(struct uart_cpm_port *pinfo,
|
||||
bdp++;
|
||||
|
||||
/* if a LF, also do CR... */
|
||||
if (*string == 10) {
|
||||
if (handle_linefeed && *string == 10) {
|
||||
while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
|
||||
;
|
||||
|
||||
@ -1111,7 +1111,7 @@ static void cpm_put_poll_char(struct uart_port *port,
|
||||
static char ch[2];
|
||||
|
||||
ch[0] = (char)c;
|
||||
cpm_uart_early_write(pinfo, ch, 1);
|
||||
cpm_uart_early_write(pinfo, ch, 1, false);
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
@ -1275,7 +1275,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
|
||||
spin_lock_irqsave(&pinfo->port.lock, flags);
|
||||
}
|
||||
|
||||
cpm_uart_early_write(pinfo, s, count);
|
||||
cpm_uart_early_write(pinfo, s, count, true);
|
||||
|
||||
if (unlikely(nolock)) {
|
||||
local_irq_restore(flags);
|
||||
|
61
drivers/tty/serial/earlycon-arm-semihost.c
Normal file
61
drivers/tty/serial/earlycon-arm-semihost.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* Adapted for ARM and earlycon:
|
||||
* Copyright (C) 2014 Linaro Ltd.
|
||||
* Author: Rob Herring <robh@kernel.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
#define SEMIHOST_SWI "0xab"
|
||||
#else
|
||||
#define SEMIHOST_SWI "0x123456"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Semihosting-based debug console
|
||||
*/
|
||||
static void smh_putc(struct uart_port *port, int c)
|
||||
{
|
||||
#ifdef CONFIG_ARM64
|
||||
asm volatile("mov x1, %0\n"
|
||||
"mov x0, #3\n"
|
||||
"hlt 0xf000\n"
|
||||
: : "r" (&c) : "x0", "x1", "memory");
|
||||
#else
|
||||
asm volatile("mov r1, %0\n"
|
||||
"mov r0, #3\n"
|
||||
"svc " SEMIHOST_SWI "\n"
|
||||
: : "r" (&c) : "r0", "r1", "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void smh_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
uart_console_write(&dev->port, s, n, smh_putc);
|
||||
}
|
||||
|
||||
int __init early_smh_setup(struct earlycon_device *device, const char *opt)
|
||||
{
|
||||
device->con->write = smh_write;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(smh, early_smh_setup);
|
144
drivers/tty/serial/earlycon.c
Normal file
144
drivers/tty/serial/earlycon.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Linaro Ltd.
|
||||
* Author: Rob Herring <robh@kernel.org>
|
||||
*
|
||||
* Based on 8250 earlycon:
|
||||
* (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/console.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#ifdef CONFIG_FIX_EARLYCON_MEM
|
||||
#include <asm/fixmap.h>
|
||||
#endif
|
||||
|
||||
#include <asm/serial.h>
|
||||
|
||||
static struct console early_con = {
|
||||
.name = "earlycon",
|
||||
.flags = CON_PRINTBUFFER | CON_BOOT,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
static struct earlycon_device early_console_dev = {
|
||||
.con = &early_con,
|
||||
};
|
||||
|
||||
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
|
||||
{
|
||||
void __iomem *base;
|
||||
#ifdef CONFIG_FIX_EARLYCON_MEM
|
||||
set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
|
||||
base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
|
||||
base += paddr & ~PAGE_MASK;
|
||||
#else
|
||||
base = ioremap(paddr, size);
|
||||
#endif
|
||||
if (!base)
|
||||
pr_err("%s: Couldn't map 0x%llx\n", __func__,
|
||||
(unsigned long long)paddr);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static int __init parse_options(struct earlycon_device *device,
|
||||
char *options)
|
||||
{
|
||||
struct uart_port *port = &device->port;
|
||||
int mmio, mmio32, length;
|
||||
unsigned long addr;
|
||||
|
||||
if (!options)
|
||||
return -ENODEV;
|
||||
|
||||
mmio = !strncmp(options, "mmio,", 5);
|
||||
mmio32 = !strncmp(options, "mmio32,", 7);
|
||||
if (mmio || mmio32) {
|
||||
port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
|
||||
options += mmio ? 5 : 7;
|
||||
addr = simple_strtoul(options, NULL, 0);
|
||||
port->mapbase = addr;
|
||||
if (mmio32)
|
||||
port->regshift = 2;
|
||||
} else if (!strncmp(options, "io,", 3)) {
|
||||
port->iotype = UPIO_PORT;
|
||||
options += 3;
|
||||
addr = simple_strtoul(options, NULL, 0);
|
||||
port->iobase = addr;
|
||||
mmio = 0;
|
||||
} else if (!strncmp(options, "0x", 2)) {
|
||||
port->iotype = UPIO_MEM;
|
||||
addr = simple_strtoul(options, NULL, 0);
|
||||
port->mapbase = addr;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port->uartclk = BASE_BAUD * 16;
|
||||
|
||||
options = strchr(options, ',');
|
||||
if (options) {
|
||||
options++;
|
||||
device->baud = simple_strtoul(options, NULL, 0);
|
||||
length = min(strcspn(options, " ") + 1,
|
||||
(size_t)(sizeof(device->options)));
|
||||
strlcpy(device->options, options, length);
|
||||
}
|
||||
|
||||
if (mmio || mmio32)
|
||||
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
|
||||
mmio32 ? "32" : "",
|
||||
(unsigned long long)port->mapbase,
|
||||
device->options);
|
||||
else
|
||||
pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
|
||||
port->iobase,
|
||||
device->options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init setup_earlycon(char *buf, const char *match,
|
||||
int (*setup)(struct earlycon_device *, const char *))
|
||||
{
|
||||
int err;
|
||||
size_t len;
|
||||
struct uart_port *port = &early_console_dev.port;
|
||||
|
||||
if (!buf || !match || !setup)
|
||||
return 0;
|
||||
|
||||
len = strlen(match);
|
||||
if (strncmp(buf, match, len))
|
||||
return 0;
|
||||
if (buf[len] && (buf[len] != ','))
|
||||
return 0;
|
||||
|
||||
buf += len + 1;
|
||||
|
||||
err = parse_options(&early_console_dev, buf);
|
||||
/* On parsing error, pass the options buf to the setup function */
|
||||
if (!err)
|
||||
buf = NULL;
|
||||
|
||||
if (port->mapbase)
|
||||
port->membase = earlycon_map(port->mapbase, 64);
|
||||
|
||||
early_console_dev.con->data = &early_console_dev;
|
||||
err = setup(&early_console_dev, buf);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (!early_console_dev.con->write)
|
||||
return -ENODEV;
|
||||
|
||||
register_console(early_console_dev.con);
|
||||
return 0;
|
||||
}
|
@ -842,6 +842,7 @@ static void __exit efm32_uart_exit(void)
|
||||
platform_driver_unregister(&efm32_uart_driver);
|
||||
uart_unregister_driver(&efm32_uart_reg);
|
||||
}
|
||||
module_exit(efm32_uart_exit);
|
||||
|
||||
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("EFM32 UART/USART driver");
|
||||
|
@ -116,7 +116,7 @@
|
||||
#define UCR3_DSR (1<<10) /* Data set ready */
|
||||
#define UCR3_DCD (1<<9) /* Data carrier detect */
|
||||
#define UCR3_RI (1<<8) /* Ring indicator */
|
||||
#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
|
||||
#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */
|
||||
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
|
||||
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
|
||||
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
|
||||
@ -444,6 +444,10 @@ static void imx_stop_rx(struct uart_port *port)
|
||||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
|
||||
|
||||
/* disable the `Receiver Ready Interrrupt` */
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1070,7 +1074,7 @@ static void imx_disable_dma(struct imx_port *sport)
|
||||
static int imx_startup(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
int retval;
|
||||
int retval, i;
|
||||
unsigned long flags, temp;
|
||||
|
||||
retval = clk_prepare_enable(sport->clk_per);
|
||||
@ -1098,17 +1102,15 @@ static int imx_startup(struct uart_port *port)
|
||||
|
||||
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
|
||||
|
||||
if (USE_IRDA(sport)) {
|
||||
/* reset fifo's and state machines */
|
||||
int i = 100;
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp &= ~UCR2_SRST;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
|
||||
(--i > 0)) {
|
||||
udelay(1);
|
||||
}
|
||||
}
|
||||
/* Reset fifo's and state machines */
|
||||
i = 100;
|
||||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp &= ~UCR2_SRST;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
|
||||
udelay(1);
|
||||
|
||||
/*
|
||||
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
|
||||
@ -1163,18 +1165,9 @@ static int imx_startup(struct uart_port *port)
|
||||
temp |= UCR2_IRTS;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
if (USE_IRDA(sport)) {
|
||||
/* clear RX-FIFO */
|
||||
int i = 64;
|
||||
while ((--i > 0) &&
|
||||
(readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
|
||||
barrier();
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_imx1_uart(sport)) {
|
||||
temp = readl(sport->port.membase + UCR3);
|
||||
temp |= IMX21_UCR3_RXDMUXSEL;
|
||||
temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
|
||||
writel(temp, sport->port.membase + UCR3);
|
||||
}
|
||||
|
||||
|
@ -44,13 +44,22 @@ MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
|
||||
|
||||
static bool kgdb_nmi_tty_enabled;
|
||||
|
||||
static int kgdb_nmi_console_setup(struct console *co, char *options)
|
||||
{
|
||||
/* The NMI console uses the dbg_io_ops to issue console messages. To
|
||||
* avoid duplicate messages during kdb sessions we must inform kdb's
|
||||
* I/O utilities that messages sent to the console will automatically
|
||||
* be displayed on the dbg_io.
|
||||
*/
|
||||
dbg_io_ops->is_console = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!kgdb_nmi_tty_enabled || atomic_read(&kgdb_active) >= 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
dbg_io_ops->write_char(s[i]);
|
||||
}
|
||||
@ -65,6 +74,7 @@ static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
|
||||
|
||||
static struct console kgdb_nmi_console = {
|
||||
.name = "ttyNMI",
|
||||
.setup = kgdb_nmi_console_setup,
|
||||
.write = kgdb_nmi_console_write,
|
||||
.device = kgdb_nmi_console_device,
|
||||
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED,
|
||||
@ -80,29 +90,10 @@ static struct console kgdb_nmi_console = {
|
||||
|
||||
struct kgdb_nmi_tty_priv {
|
||||
struct tty_port port;
|
||||
struct tasklet_struct tlet;
|
||||
struct timer_list timer;
|
||||
STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
|
||||
};
|
||||
|
||||
static struct kgdb_nmi_tty_priv *kgdb_nmi_port_to_priv(struct tty_port *port)
|
||||
{
|
||||
return container_of(port, struct kgdb_nmi_tty_priv, port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Our debugging console is polled in a tasklet, so we'll check for input
|
||||
* every tick. In HZ-less mode, we should program the next tick. We have
|
||||
* to use the lowlevel stuff as no locks should be grabbed.
|
||||
*/
|
||||
#ifdef CONFIG_HIGH_RES_TIMERS
|
||||
static void kgdb_tty_poke(void)
|
||||
{
|
||||
tick_program_event(ktime_get(), 0);
|
||||
}
|
||||
#else
|
||||
static inline void kgdb_tty_poke(void) {}
|
||||
#endif
|
||||
|
||||
static struct tty_port *kgdb_nmi_port;
|
||||
|
||||
static void kgdb_tty_recv(int ch)
|
||||
@ -113,14 +104,13 @@ static void kgdb_tty_recv(int ch)
|
||||
if (!kgdb_nmi_port || ch < 0)
|
||||
return;
|
||||
/*
|
||||
* Can't use port->tty->driver_data as tty might be not there. Tasklet
|
||||
* Can't use port->tty->driver_data as tty might be not there. Timer
|
||||
* will check for tty and will get the ref, but here we don't have to
|
||||
* do that, and actually, we can't: we're in NMI context, no locks are
|
||||
* possible.
|
||||
*/
|
||||
priv = kgdb_nmi_port_to_priv(kgdb_nmi_port);
|
||||
priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);
|
||||
kfifo_in(&priv->fifo, &c, 1);
|
||||
kgdb_tty_poke();
|
||||
}
|
||||
|
||||
static int kgdb_nmi_poll_one_knock(void)
|
||||
@ -204,7 +194,8 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
|
||||
struct kgdb_nmi_tty_priv *priv = (void *)data;
|
||||
char ch;
|
||||
|
||||
tasklet_schedule(&priv->tlet);
|
||||
priv->timer.expires = jiffies + (HZ/100);
|
||||
add_timer(&priv->timer);
|
||||
|
||||
if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))
|
||||
return;
|
||||
@ -216,18 +207,22 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
|
||||
|
||||
static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
|
||||
struct kgdb_nmi_tty_priv *priv =
|
||||
container_of(port, struct kgdb_nmi_tty_priv, port);
|
||||
|
||||
kgdb_nmi_port = port;
|
||||
tasklet_schedule(&priv->tlet);
|
||||
priv->timer.expires = jiffies + (HZ/100);
|
||||
add_timer(&priv->timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kgdb_nmi_tty_shutdown(struct tty_port *port)
|
||||
{
|
||||
struct kgdb_nmi_tty_priv *priv = port->tty->driver_data;
|
||||
struct kgdb_nmi_tty_priv *priv =
|
||||
container_of(port, struct kgdb_nmi_tty_priv, port);
|
||||
|
||||
tasklet_kill(&priv->tlet);
|
||||
del_timer(&priv->timer);
|
||||
kgdb_nmi_port = NULL;
|
||||
}
|
||||
|
||||
@ -246,7 +241,7 @@ static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_KFIFO(priv->fifo);
|
||||
tasklet_init(&priv->tlet, kgdb_nmi_tty_receiver, (unsigned long)priv);
|
||||
setup_timer(&priv->timer, kgdb_nmi_tty_receiver, (unsigned long)priv);
|
||||
tty_port_init(&priv->port);
|
||||
priv->port.ops = &kgdb_nmi_tty_port_ops;
|
||||
tty->driver_data = priv;
|
||||
|
867
drivers/tty/serial/men_z135_uart.c
Normal file
867
drivers/tty/serial/men_z135_uart.c
Normal file
@ -0,0 +1,867 @@
|
||||
/*
|
||||
* MEN 16z135 High Speed UART
|
||||
*
|
||||
* Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
|
||||
* Author: Johannes Thumshirn <johannes.thumshirn@men.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; version 2 of the License.
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mcb.h>
|
||||
|
||||
#define MEN_Z135_MAX_PORTS 12
|
||||
#define MEN_Z135_BASECLK 29491200
|
||||
#define MEN_Z135_FIFO_SIZE 1024
|
||||
#define MEN_Z135_NUM_MSI_VECTORS 2
|
||||
#define MEN_Z135_FIFO_WATERMARK 1020
|
||||
|
||||
#define MEN_Z135_STAT_REG 0x0
|
||||
#define MEN_Z135_RX_RAM 0x4
|
||||
#define MEN_Z135_TX_RAM 0x400
|
||||
#define MEN_Z135_RX_CTRL 0x800
|
||||
#define MEN_Z135_TX_CTRL 0x804
|
||||
#define MEN_Z135_CONF_REG 0x808
|
||||
#define MEN_Z135_UART_FREQ 0x80c
|
||||
#define MEN_Z135_BAUD_REG 0x810
|
||||
#define MENZ135_TIMEOUT 0x814
|
||||
|
||||
#define MEN_Z135_MEM_SIZE 0x818
|
||||
|
||||
#define IS_IRQ(x) ((x) & 1)
|
||||
#define IRQ_ID(x) (((x) >> 1) & 7)
|
||||
|
||||
#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
|
||||
#define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */
|
||||
#define MEN_Z135_IER_RLSIEN BIT(2) /* Receiver Line Status IRQ */
|
||||
#define MEN_Z135_IER_MSIEN BIT(3) /* Modem Status IRQ */
|
||||
#define MEN_Z135_ALL_IRQS (MEN_Z135_IER_RXCIEN \
|
||||
| MEN_Z135_IER_RLSIEN \
|
||||
| MEN_Z135_IER_MSIEN \
|
||||
| MEN_Z135_IER_TXCIEN)
|
||||
|
||||
#define MEN_Z135_MCR_DTR BIT(24)
|
||||
#define MEN_Z135_MCR_RTS BIT(25)
|
||||
#define MEN_Z135_MCR_OUT1 BIT(26)
|
||||
#define MEN_Z135_MCR_OUT2 BIT(27)
|
||||
#define MEN_Z135_MCR_LOOP BIT(28)
|
||||
#define MEN_Z135_MCR_RCFC BIT(29)
|
||||
|
||||
#define MEN_Z135_MSR_DCTS BIT(0)
|
||||
#define MEN_Z135_MSR_DDSR BIT(1)
|
||||
#define MEN_Z135_MSR_DRI BIT(2)
|
||||
#define MEN_Z135_MSR_DDCD BIT(3)
|
||||
#define MEN_Z135_MSR_CTS BIT(4)
|
||||
#define MEN_Z135_MSR_DSR BIT(5)
|
||||
#define MEN_Z135_MSR_RI BIT(6)
|
||||
#define MEN_Z135_MSR_DCD BIT(7)
|
||||
|
||||
#define MEN_Z135_LCR_SHIFT 8 /* LCR shift mask */
|
||||
|
||||
#define MEN_Z135_WL5 0 /* CS5 */
|
||||
#define MEN_Z135_WL6 1 /* CS6 */
|
||||
#define MEN_Z135_WL7 2 /* CS7 */
|
||||
#define MEN_Z135_WL8 3 /* CS8 */
|
||||
|
||||
#define MEN_Z135_STB_SHIFT 2 /* Stopbits */
|
||||
#define MEN_Z135_NSTB1 0
|
||||
#define MEN_Z135_NSTB2 1
|
||||
|
||||
#define MEN_Z135_PEN_SHIFT 3 /* Parity enable */
|
||||
#define MEN_Z135_PAR_DIS 0
|
||||
#define MEN_Z135_PAR_ENA 1
|
||||
|
||||
#define MEN_Z135_PTY_SHIFT 4 /* Parity type */
|
||||
#define MEN_Z135_PTY_ODD 0
|
||||
#define MEN_Z135_PTY_EVN 1
|
||||
|
||||
#define MEN_Z135_LSR_DR BIT(0)
|
||||
#define MEN_Z135_LSR_OE BIT(1)
|
||||
#define MEN_Z135_LSR_PE BIT(2)
|
||||
#define MEN_Z135_LSR_FE BIT(3)
|
||||
#define MEN_Z135_LSR_BI BIT(4)
|
||||
#define MEN_Z135_LSR_THEP BIT(5)
|
||||
#define MEN_Z135_LSR_TEXP BIT(6)
|
||||
#define MEN_Z135_LSR_RXFIFOERR BIT(7)
|
||||
|
||||
#define MEN_Z135_IRQ_ID_MST 0
|
||||
#define MEN_Z135_IRQ_ID_TSA 1
|
||||
#define MEN_Z135_IRQ_ID_RDA 2
|
||||
#define MEN_Z135_IRQ_ID_RLS 3
|
||||
#define MEN_Z135_IRQ_ID_CTI 6
|
||||
|
||||
#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff)
|
||||
|
||||
#define BYTES_TO_ALIGN(x) ((x) & 0x3)
|
||||
|
||||
static int line;
|
||||
|
||||
static int txlvl = 5;
|
||||
module_param(txlvl, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(txlvl, "TX IRQ trigger level 0-7, default 5 (128 byte)");
|
||||
|
||||
static int rxlvl = 6;
|
||||
module_param(rxlvl, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(rxlvl, "RX IRQ trigger level 0-7, default 6 (256 byte)");
|
||||
|
||||
static int align;
|
||||
module_param(align, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0");
|
||||
|
||||
struct men_z135_port {
|
||||
struct uart_port port;
|
||||
struct mcb_device *mdev;
|
||||
unsigned char *rxbuf;
|
||||
u32 stat_reg;
|
||||
spinlock_t lock;
|
||||
};
|
||||
#define to_men_z135(port) container_of((port), struct men_z135_port, port)
|
||||
|
||||
/**
|
||||
* men_z135_reg_set() - Set value in register
|
||||
* @uart: The UART port
|
||||
* @addr: Register address
|
||||
* @val: value to set
|
||||
*/
|
||||
static inline void men_z135_reg_set(struct men_z135_port *uart,
|
||||
u32 addr, u32 val)
|
||||
{
|
||||
struct uart_port *port = &uart->port;
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&uart->lock, flags);
|
||||
|
||||
reg = ioread32(port->membase + addr);
|
||||
reg |= val;
|
||||
iowrite32(reg, port->membase + addr);
|
||||
|
||||
spin_unlock_irqrestore(&uart->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_reg_clr() - Unset value in register
|
||||
* @uart: The UART port
|
||||
* @addr: Register address
|
||||
* @val: value to clear
|
||||
*/
|
||||
static inline void men_z135_reg_clr(struct men_z135_port *uart,
|
||||
u32 addr, u32 val)
|
||||
{
|
||||
struct uart_port *port = &uart->port;
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&uart->lock, flags);
|
||||
|
||||
reg = ioread32(port->membase + addr);
|
||||
reg &= ~val;
|
||||
iowrite32(reg, port->membase + addr);
|
||||
|
||||
spin_unlock_irqrestore(&uart->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_handle_modem_status() - Handle change of modem status
|
||||
* @port: The UART port
|
||||
*
|
||||
* Handle change of modem status register. This is done by reading the "delta"
|
||||
* versions of DCD (Data Carrier Detect) and CTS (Clear To Send).
|
||||
*/
|
||||
static void men_z135_handle_modem_status(struct men_z135_port *uart)
|
||||
{
|
||||
if (uart->stat_reg & MEN_Z135_MSR_DDCD)
|
||||
uart_handle_dcd_change(&uart->port,
|
||||
uart->stat_reg & ~MEN_Z135_MSR_DCD);
|
||||
if (uart->stat_reg & MEN_Z135_MSR_DCTS)
|
||||
uart_handle_cts_change(&uart->port,
|
||||
uart->stat_reg & ~MEN_Z135_MSR_CTS);
|
||||
}
|
||||
|
||||
static void men_z135_handle_lsr(struct men_z135_port *uart)
|
||||
{
|
||||
struct uart_port *port = &uart->port;
|
||||
u8 lsr;
|
||||
|
||||
lsr = (uart->stat_reg >> 16) & 0xff;
|
||||
|
||||
if (lsr & MEN_Z135_LSR_OE)
|
||||
port->icount.overrun++;
|
||||
if (lsr & MEN_Z135_LSR_PE)
|
||||
port->icount.parity++;
|
||||
if (lsr & MEN_Z135_LSR_FE)
|
||||
port->icount.frame++;
|
||||
if (lsr & MEN_Z135_LSR_BI) {
|
||||
port->icount.brk++;
|
||||
uart_handle_break(port);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_rx_fifo_content() - Get the number of bytes in RX FIFO
|
||||
* @uart: The UART port
|
||||
*
|
||||
* Read RXC register from hardware and return current FIFO fill size.
|
||||
*/
|
||||
static u16 get_rx_fifo_content(struct men_z135_port *uart)
|
||||
{
|
||||
struct uart_port *port = &uart->port;
|
||||
u32 stat_reg;
|
||||
u16 rxc;
|
||||
u8 rxc_lo;
|
||||
u8 rxc_hi;
|
||||
|
||||
stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
|
||||
rxc_lo = stat_reg >> 24;
|
||||
rxc_hi = (stat_reg & 0xC0) >> 6;
|
||||
|
||||
rxc = rxc_lo | (rxc_hi << 8);
|
||||
|
||||
return rxc;
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_handle_rx() - RX tasklet routine
|
||||
* @arg: Pointer to struct men_z135_port
|
||||
*
|
||||
* Copy from RX FIFO and acknowledge number of bytes copied.
|
||||
*/
|
||||
static void men_z135_handle_rx(struct men_z135_port *uart)
|
||||
{
|
||||
struct uart_port *port = &uart->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int copied;
|
||||
u16 size;
|
||||
int room;
|
||||
|
||||
size = get_rx_fifo_content(uart);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
/* Avoid accidently accessing TX FIFO instead of RX FIFO. Last
|
||||
* longword in RX FIFO cannot be read.(0x004-0x3FF)
|
||||
*/
|
||||
if (size > MEN_Z135_FIFO_WATERMARK)
|
||||
size = MEN_Z135_FIFO_WATERMARK;
|
||||
|
||||
room = tty_buffer_request_room(tport, size);
|
||||
if (room != size)
|
||||
dev_warn(&uart->mdev->dev,
|
||||
"Not enough room in flip buffer, truncating to %d\n",
|
||||
room);
|
||||
|
||||
if (room == 0)
|
||||
return;
|
||||
|
||||
memcpy_fromio(uart->rxbuf, port->membase + MEN_Z135_RX_RAM, room);
|
||||
/* Be sure to first copy all data and then acknowledge it */
|
||||
mb();
|
||||
iowrite32(room, port->membase + MEN_Z135_RX_CTRL);
|
||||
|
||||
copied = tty_insert_flip_string(tport, uart->rxbuf, room);
|
||||
if (copied != room)
|
||||
dev_warn(&uart->mdev->dev,
|
||||
"Only copied %d instead of %d bytes\n",
|
||||
copied, room);
|
||||
|
||||
port->icount.rx += copied;
|
||||
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_handle_tx() - TX tasklet routine
|
||||
* @arg: Pointer to struct men_z135_port
|
||||
*
|
||||
*/
|
||||
static void men_z135_handle_tx(struct men_z135_port *uart)
|
||||
{
|
||||
struct uart_port *port = &uart->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
u32 txc;
|
||||
u32 wptr;
|
||||
int qlen;
|
||||
int n;
|
||||
int txfree;
|
||||
int head;
|
||||
int tail;
|
||||
int s;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
goto out;
|
||||
|
||||
if (uart_tx_stopped(port))
|
||||
goto out;
|
||||
|
||||
if (port->x_char)
|
||||
goto out;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
/* calculate bytes to copy */
|
||||
qlen = uart_circ_chars_pending(xmit);
|
||||
if (qlen <= 0)
|
||||
goto out;
|
||||
|
||||
wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
|
||||
txc = (wptr >> 16) & 0x3ff;
|
||||
wptr &= 0x3ff;
|
||||
|
||||
if (txc > MEN_Z135_FIFO_WATERMARK)
|
||||
txc = MEN_Z135_FIFO_WATERMARK;
|
||||
|
||||
txfree = MEN_Z135_FIFO_WATERMARK - txc;
|
||||
if (txfree <= 0) {
|
||||
pr_err("Not enough room in TX FIFO have %d, need %d\n",
|
||||
txfree, qlen);
|
||||
goto irq_en;
|
||||
}
|
||||
|
||||
/* if we're not aligned, it's better to copy only 1 or 2 bytes and
|
||||
* then the rest.
|
||||
*/
|
||||
if (align && qlen >= 3 && BYTES_TO_ALIGN(wptr))
|
||||
n = 4 - BYTES_TO_ALIGN(wptr);
|
||||
else if (qlen > txfree)
|
||||
n = txfree;
|
||||
else
|
||||
n = qlen;
|
||||
|
||||
if (n <= 0)
|
||||
goto irq_en;
|
||||
|
||||
head = xmit->head & (UART_XMIT_SIZE - 1);
|
||||
tail = xmit->tail & (UART_XMIT_SIZE - 1);
|
||||
|
||||
s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
|
||||
n = min(n, s);
|
||||
|
||||
memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
|
||||
xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1);
|
||||
mmiowb();
|
||||
|
||||
iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
|
||||
|
||||
port->icount.tx += n;
|
||||
|
||||
irq_en:
|
||||
if (!uart_circ_empty(xmit))
|
||||
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
|
||||
else
|
||||
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
|
||||
|
||||
out:
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_intr() - Handle legacy IRQs
|
||||
* @irq: The IRQ number
|
||||
* @data: Pointer to UART port
|
||||
*
|
||||
* Check IIR register to see which tasklet to start.
|
||||
*/
|
||||
static irqreturn_t men_z135_intr(int irq, void *data)
|
||||
{
|
||||
struct men_z135_port *uart = (struct men_z135_port *)data;
|
||||
struct uart_port *port = &uart->port;
|
||||
int irq_id;
|
||||
|
||||
uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
|
||||
/* IRQ pending is low active */
|
||||
if (IS_IRQ(uart->stat_reg))
|
||||
return IRQ_NONE;
|
||||
|
||||
irq_id = IRQ_ID(uart->stat_reg);
|
||||
switch (irq_id) {
|
||||
case MEN_Z135_IRQ_ID_MST:
|
||||
men_z135_handle_modem_status(uart);
|
||||
break;
|
||||
case MEN_Z135_IRQ_ID_TSA:
|
||||
men_z135_handle_tx(uart);
|
||||
break;
|
||||
case MEN_Z135_IRQ_ID_CTI:
|
||||
dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
|
||||
/* Fallthrough */
|
||||
case MEN_Z135_IRQ_ID_RDA:
|
||||
/* Reading data clears RX IRQ */
|
||||
men_z135_handle_rx(uart);
|
||||
break;
|
||||
case MEN_Z135_IRQ_ID_RLS:
|
||||
men_z135_handle_lsr(uart);
|
||||
break;
|
||||
default:
|
||||
dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_request_irq() - Request IRQ for 16z135 core
|
||||
* @uart: z135 private uart port structure
|
||||
*
|
||||
* Request an IRQ for 16z135 to use. First try using MSI, if it fails
|
||||
* fall back to using legacy interrupts.
|
||||
*/
|
||||
static int men_z135_request_irq(struct men_z135_port *uart)
|
||||
{
|
||||
struct device *dev = &uart->mdev->dev;
|
||||
struct uart_port *port = &uart->port;
|
||||
int err = 0;
|
||||
|
||||
err = request_irq(port->irq, men_z135_intr, IRQF_SHARED,
|
||||
"men_z135_intr", uart);
|
||||
if (err)
|
||||
dev_err(dev, "Error %d getting interrupt\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_tx_empty() - Handle tx_empty call
|
||||
* @port: The UART port
|
||||
*
|
||||
* This function tests whether the TX FIFO and shifter for the port
|
||||
* described by @port is empty.
|
||||
*/
|
||||
static unsigned int men_z135_tx_empty(struct uart_port *port)
|
||||
{
|
||||
u32 wptr;
|
||||
u16 txc;
|
||||
|
||||
wptr = ioread32(port->membase + MEN_Z135_TX_CTRL);
|
||||
txc = (wptr >> 16) & 0x3ff;
|
||||
|
||||
if (txc == 0)
|
||||
return TIOCSER_TEMT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_set_mctrl() - Set modem control lines
|
||||
* @port: The UART port
|
||||
* @mctrl: The modem control lines
|
||||
*
|
||||
* This function sets the modem control lines for a port described by @port
|
||||
* to the state described by @mctrl
|
||||
*/
|
||||
static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
u32 conf_reg = 0;
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
conf_reg |= MEN_Z135_MCR_RTS;
|
||||
if (mctrl & TIOCM_DTR)
|
||||
conf_reg |= MEN_Z135_MCR_DTR;
|
||||
if (mctrl & TIOCM_OUT1)
|
||||
conf_reg |= MEN_Z135_MCR_OUT1;
|
||||
if (mctrl & TIOCM_OUT2)
|
||||
conf_reg |= MEN_Z135_MCR_OUT2;
|
||||
if (mctrl & TIOCM_LOOP)
|
||||
conf_reg |= MEN_Z135_MCR_LOOP;
|
||||
|
||||
men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_get_mctrl() - Get modem control lines
|
||||
* @port: The UART port
|
||||
*
|
||||
* Retruns the current state of modem control inputs.
|
||||
*/
|
||||
static unsigned int men_z135_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
unsigned int mctrl = 0;
|
||||
u32 stat_reg;
|
||||
u8 msr;
|
||||
|
||||
stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
|
||||
|
||||
msr = ~((stat_reg >> 8) & 0xff);
|
||||
|
||||
if (msr & MEN_Z135_MSR_CTS)
|
||||
mctrl |= TIOCM_CTS;
|
||||
if (msr & MEN_Z135_MSR_DSR)
|
||||
mctrl |= TIOCM_DSR;
|
||||
if (msr & MEN_Z135_MSR_RI)
|
||||
mctrl |= TIOCM_RI;
|
||||
if (msr & MEN_Z135_MSR_DCD)
|
||||
mctrl |= TIOCM_CAR;
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_stop_tx() - Stop transmitting characters
|
||||
* @port: The UART port
|
||||
*
|
||||
* Stop transmitting characters. This might be due to CTS line becomming
|
||||
* inactive or the tty layer indicating we want to stop transmission due to
|
||||
* an XOFF character.
|
||||
*/
|
||||
static void men_z135_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
|
||||
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_start_tx() - Start transmitting characters
|
||||
* @port: The UART port
|
||||
*
|
||||
* Start transmitting character. This actually doesn't transmit anything, but
|
||||
* fires off the TX tasklet.
|
||||
*/
|
||||
static void men_z135_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
|
||||
men_z135_handle_tx(uart);
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_stop_rx() - Stop receiving characters
|
||||
* @port: The UART port
|
||||
*
|
||||
* Stop receiving characters; the port is in the process of being closed.
|
||||
*/
|
||||
static void men_z135_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
|
||||
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_RXCIEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_enable_ms() - Enable Modem Status
|
||||
* port:
|
||||
*
|
||||
* Enable Modem Status IRQ.
|
||||
*/
|
||||
static void men_z135_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
|
||||
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN);
|
||||
}
|
||||
|
||||
static int men_z135_startup(struct uart_port *port)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
int err;
|
||||
u32 conf_reg = 0;
|
||||
|
||||
err = men_z135_request_irq(uart);
|
||||
if (err)
|
||||
return -ENODEV;
|
||||
|
||||
conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
|
||||
|
||||
/* Activate all but TX space available IRQ */
|
||||
conf_reg |= MEN_Z135_ALL_IRQS & ~MEN_Z135_IER_TXCIEN;
|
||||
conf_reg &= ~(0xff << 16);
|
||||
conf_reg |= (txlvl << 16);
|
||||
conf_reg |= (rxlvl << 20);
|
||||
|
||||
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void men_z135_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct men_z135_port *uart = to_men_z135(port);
|
||||
u32 conf_reg = 0;
|
||||
|
||||
conf_reg |= MEN_Z135_ALL_IRQS;
|
||||
|
||||
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, conf_reg);
|
||||
|
||||
free_irq(uart->port.irq, uart);
|
||||
}
|
||||
|
||||
static void men_z135_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud;
|
||||
u32 conf_reg;
|
||||
u32 bd_reg;
|
||||
u32 uart_freq;
|
||||
u8 lcr;
|
||||
|
||||
conf_reg = ioread32(port->membase + MEN_Z135_CONF_REG);
|
||||
lcr = LCR(conf_reg);
|
||||
|
||||
/* byte size */
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr |= MEN_Z135_WL5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr |= MEN_Z135_WL6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr |= MEN_Z135_WL7;
|
||||
break;
|
||||
case CS8:
|
||||
lcr |= MEN_Z135_WL8;
|
||||
break;
|
||||
}
|
||||
|
||||
/* stop bits */
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
lcr |= MEN_Z135_NSTB2 << MEN_Z135_STB_SHIFT;
|
||||
|
||||
/* parity */
|
||||
if (termios->c_cflag & PARENB) {
|
||||
lcr |= MEN_Z135_PAR_ENA << MEN_Z135_PEN_SHIFT;
|
||||
|
||||
if (termios->c_cflag & PARODD)
|
||||
lcr |= MEN_Z135_PTY_ODD << MEN_Z135_PTY_SHIFT;
|
||||
else
|
||||
lcr |= MEN_Z135_PTY_EVN << MEN_Z135_PTY_SHIFT;
|
||||
} else
|
||||
lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT;
|
||||
|
||||
termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
|
||||
|
||||
conf_reg |= lcr << MEN_Z135_LCR_SHIFT;
|
||||
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
|
||||
|
||||
uart_freq = ioread32(port->membase + MEN_Z135_UART_FREQ);
|
||||
if (uart_freq == 0)
|
||||
uart_freq = MEN_Z135_BASECLK;
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16);
|
||||
|
||||
spin_lock(&port->lock);
|
||||
if (tty_termios_baud_rate(termios))
|
||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
|
||||
bd_reg = uart_freq / (4 * baud);
|
||||
iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG);
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
spin_unlock(&port->lock);
|
||||
}
|
||||
|
||||
static const char *men_z135_type(struct uart_port *port)
|
||||
{
|
||||
return KBUILD_MODNAME;
|
||||
}
|
||||
|
||||
static void men_z135_release_port(struct uart_port *port)
|
||||
{
|
||||
iounmap(port->membase);
|
||||
port->membase = NULL;
|
||||
|
||||
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
|
||||
}
|
||||
|
||||
static int men_z135_request_port(struct uart_port *port)
|
||||
{
|
||||
int size = MEN_Z135_MEM_SIZE;
|
||||
|
||||
if (!request_mem_region(port->mapbase, size, "men_z135_port"))
|
||||
return -EBUSY;
|
||||
|
||||
port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE);
|
||||
if (port->membase == NULL) {
|
||||
release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void men_z135_config_port(struct uart_port *port, int type)
|
||||
{
|
||||
port->type = PORT_MEN_Z135;
|
||||
men_z135_request_port(port);
|
||||
}
|
||||
|
||||
static int men_z135_verify_port(struct uart_port *port,
|
||||
struct serial_struct *serinfo)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct uart_ops men_z135_ops = {
|
||||
.tx_empty = men_z135_tx_empty,
|
||||
.set_mctrl = men_z135_set_mctrl,
|
||||
.get_mctrl = men_z135_get_mctrl,
|
||||
.stop_tx = men_z135_stop_tx,
|
||||
.start_tx = men_z135_start_tx,
|
||||
.stop_rx = men_z135_stop_rx,
|
||||
.enable_ms = men_z135_enable_ms,
|
||||
.startup = men_z135_startup,
|
||||
.shutdown = men_z135_shutdown,
|
||||
.set_termios = men_z135_set_termios,
|
||||
.type = men_z135_type,
|
||||
.release_port = men_z135_release_port,
|
||||
.request_port = men_z135_request_port,
|
||||
.config_port = men_z135_config_port,
|
||||
.verify_port = men_z135_verify_port,
|
||||
};
|
||||
|
||||
static struct uart_driver men_z135_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.dev_name = "ttyHSU",
|
||||
.major = 0,
|
||||
.minor = 0,
|
||||
.nr = MEN_Z135_MAX_PORTS,
|
||||
};
|
||||
|
||||
/**
|
||||
* men_z135_probe() - Probe a z135 instance
|
||||
* @mdev: The MCB device
|
||||
* @id: The MCB device ID
|
||||
*
|
||||
* men_z135_probe does the basic setup of hardware resources and registers the
|
||||
* new uart port to the tty layer.
|
||||
*/
|
||||
static int men_z135_probe(struct mcb_device *mdev,
|
||||
const struct mcb_device_id *id)
|
||||
{
|
||||
struct men_z135_port *uart;
|
||||
struct resource *mem;
|
||||
struct device *dev;
|
||||
int err;
|
||||
|
||||
dev = &mdev->dev;
|
||||
|
||||
uart = devm_kzalloc(dev, sizeof(struct men_z135_port), GFP_KERNEL);
|
||||
if (!uart)
|
||||
return -ENOMEM;
|
||||
|
||||
uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
|
||||
if (!uart->rxbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = &mdev->mem;
|
||||
|
||||
mcb_set_drvdata(mdev, uart);
|
||||
|
||||
uart->port.uartclk = MEN_Z135_BASECLK * 16;
|
||||
uart->port.fifosize = MEN_Z135_FIFO_SIZE;
|
||||
uart->port.iotype = UPIO_MEM;
|
||||
uart->port.ops = &men_z135_ops;
|
||||
uart->port.irq = mcb_get_irq(mdev);
|
||||
uart->port.iotype = UPIO_MEM;
|
||||
uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
|
||||
uart->port.line = line++;
|
||||
uart->port.dev = dev;
|
||||
uart->port.type = PORT_MEN_Z135;
|
||||
uart->port.mapbase = mem->start;
|
||||
uart->port.membase = NULL;
|
||||
uart->mdev = mdev;
|
||||
|
||||
spin_lock_init(&uart->port.lock);
|
||||
spin_lock_init(&uart->lock);
|
||||
|
||||
err = uart_add_one_port(&men_z135_driver, &uart->port);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free_page((unsigned long) uart->rxbuf);
|
||||
dev_err(dev, "Failed to add UART: %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* men_z135_remove() - Remove a z135 instance from the system
|
||||
*
|
||||
* @mdev: The MCB device
|
||||
*/
|
||||
static void men_z135_remove(struct mcb_device *mdev)
|
||||
{
|
||||
struct men_z135_port *uart = mcb_get_drvdata(mdev);
|
||||
|
||||
line--;
|
||||
uart_remove_one_port(&men_z135_driver, &uart->port);
|
||||
free_page((unsigned long) uart->rxbuf);
|
||||
}
|
||||
|
||||
static const struct mcb_device_id men_z135_ids[] = {
|
||||
{ .device = 0x87 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(mcb, men_z135_ids);
|
||||
|
||||
static struct mcb_driver mcb_driver = {
|
||||
.driver = {
|
||||
.name = "z135-uart",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = men_z135_probe,
|
||||
.remove = men_z135_remove,
|
||||
.id_table = men_z135_ids,
|
||||
};
|
||||
|
||||
/**
|
||||
* men_z135_init() - Driver Registration Routine
|
||||
*
|
||||
* men_z135_init is the first routine called when the driver is loaded. All it
|
||||
* does is register with the legacy MEN Chameleon subsystem.
|
||||
*/
|
||||
static int __init men_z135_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = uart_register_driver(&men_z135_driver);
|
||||
if (err) {
|
||||
pr_err("Failed to register UART: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mcb_register_driver(&mcb_driver);
|
||||
if (err) {
|
||||
pr_err("Failed to register MCB driver: %d\n", err);
|
||||
uart_unregister_driver(&men_z135_driver);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(men_z135_init);
|
||||
|
||||
/**
|
||||
* men_z135_exit() - Driver Exit Routine
|
||||
*
|
||||
* men_z135_exit is called just before the driver is removed from memory.
|
||||
*/
|
||||
static void __exit men_z135_exit(void)
|
||||
{
|
||||
mcb_unregister_driver(&mcb_driver);
|
||||
uart_unregister_driver(&men_z135_driver);
|
||||
}
|
||||
module_exit(men_z135_exit);
|
||||
|
||||
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("MEN 16z135 High Speed UART");
|
||||
MODULE_ALIAS("mcb:16z135");
|
@ -29,7 +29,7 @@
|
||||
#include <asm/irq.h>
|
||||
#include <asm/parisc-device.h>
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#include <linux/sysrq.h>
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
@ -613,7 +613,7 @@ static void __exit mux_exit(void)
|
||||
{
|
||||
/* Delete the Mux timer. */
|
||||
if(port_cnt > 0) {
|
||||
del_timer(&mux_timer);
|
||||
del_timer_sync(&mux_timer);
|
||||
#ifdef CONFIG_SERIAL_MUX_CONSOLE
|
||||
unregister_console(&mux_console);
|
||||
#endif
|
||||
|
@ -173,6 +173,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct uart_8250_port port8250;
|
||||
memset(&port8250, 0, sizeof(port8250));
|
||||
port.type = port_type;
|
||||
port8250.port = port;
|
||||
|
||||
if (port.fifosize)
|
||||
@ -182,6 +183,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
"auto-flow-control"))
|
||||
port8250.capabilities |= UART_CAP_AFE;
|
||||
|
||||
if (of_property_read_bool(ofdev->dev.of_node,
|
||||
"has-hw-flow-control"))
|
||||
port8250.port.flags |= UPF_HARD_FLOW;
|
||||
|
||||
ret = serial8250_register_8250_port(&port8250);
|
||||
break;
|
||||
}
|
||||
|
@ -163,10 +163,6 @@ struct uart_omap_port {
|
||||
u8 wakeups_enabled;
|
||||
u32 features;
|
||||
|
||||
int DTR_gpio;
|
||||
int DTR_inverted;
|
||||
int DTR_active;
|
||||
|
||||
struct serial_rs485 rs485;
|
||||
int rts_gpio;
|
||||
|
||||
@ -184,8 +180,6 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
|
||||
/* Forward declaration of functions */
|
||||
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);
|
||||
|
||||
static struct workqueue_struct *serial_omap_uart_wq;
|
||||
|
||||
static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
|
||||
{
|
||||
offset <<= up->port.regshift;
|
||||
@ -398,11 +392,8 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
|
||||
spin_unlock(&up->port.lock);
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
spin_lock(&up->port.lock);
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
serial_omap_stop_tx(&up->port);
|
||||
@ -697,16 +688,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
serial_out(up, UART_MCR, up->mcr);
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
pm_runtime_put_autosuspend(up->dev);
|
||||
|
||||
if (gpio_is_valid(up->DTR_gpio) &&
|
||||
!!(mctrl & TIOCM_DTR) != up->DTR_active) {
|
||||
up->DTR_active = !up->DTR_active;
|
||||
if (gpio_cansleep(up->DTR_gpio))
|
||||
schedule_work(&up->qos_work);
|
||||
else
|
||||
gpio_set_value(up->DTR_gpio,
|
||||
up->DTR_active != up->DTR_inverted);
|
||||
}
|
||||
}
|
||||
|
||||
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
|
||||
@ -850,9 +831,6 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
|
||||
qos_work);
|
||||
|
||||
pm_qos_update_request(&up->pm_qos_request, up->latency);
|
||||
if (gpio_is_valid(up->DTR_gpio))
|
||||
gpio_set_value_cansleep(up->DTR_gpio,
|
||||
up->DTR_active != up->DTR_inverted);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1420,7 +1398,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
|
||||
if (copy_from_user(&rs485conf, (void __user *) arg,
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
|
||||
@ -1428,7 +1406,7 @@ serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
|
||||
case TIOCGRS485:
|
||||
if (copy_to_user((struct serial_rs485 *) arg,
|
||||
if (copy_to_user((void __user *) arg,
|
||||
&(to_uart_omap_port(port)->rs485),
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
@ -1614,7 +1592,7 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
|
||||
/* check for tx enable gpio */
|
||||
up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
|
||||
if (gpio_is_valid(up->rts_gpio)) {
|
||||
ret = gpio_request(up->rts_gpio, "omap-serial");
|
||||
ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = gpio_direction_output(up->rts_gpio,
|
||||
@ -1644,10 +1622,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
|
||||
|
||||
static int serial_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_omap_port *up;
|
||||
struct resource *mem, *irq;
|
||||
struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
|
||||
int ret, uartirq = 0, wakeirq = 0;
|
||||
struct uart_omap_port *up;
|
||||
struct resource *mem;
|
||||
void __iomem *base;
|
||||
int uartirq = 0;
|
||||
int wakeirq = 0;
|
||||
int ret;
|
||||
|
||||
/* The optional wakeirq may be specified in the board dts file */
|
||||
if (pdev->dev.of_node) {
|
||||
@ -1658,48 +1639,19 @@ static int serial_omap_probe(struct platform_device *pdev)
|
||||
omap_up_info = of_get_uart_port_info(&pdev->dev);
|
||||
pdev->dev.platform_data = omap_up_info;
|
||||
} else {
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq) {
|
||||
dev_err(&pdev->dev, "no irq resource?\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
uartirq = irq->start;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "no mem resource?\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
|
||||
pdev->dev.driver->name)) {
|
||||
dev_err(&pdev->dev, "memory region already claimed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(omap_up_info->DTR_gpio) &&
|
||||
omap_up_info->DTR_present) {
|
||||
ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = gpio_direction_output(omap_up_info->DTR_gpio,
|
||||
omap_up_info->DTR_inverted);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
uartirq = platform_get_irq(pdev, 0);
|
||||
if (uartirq < 0)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
|
||||
if (!up)
|
||||
return -ENOMEM;
|
||||
|
||||
if (gpio_is_valid(omap_up_info->DTR_gpio) &&
|
||||
omap_up_info->DTR_present) {
|
||||
up->DTR_gpio = omap_up_info->DTR_gpio;
|
||||
up->DTR_inverted = omap_up_info->DTR_inverted;
|
||||
} else
|
||||
up->DTR_gpio = -EINVAL;
|
||||
up->DTR_active = 0;
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
up->dev = &pdev->dev;
|
||||
up->port.dev = &pdev->dev;
|
||||
@ -1733,14 +1685,7 @@ static int serial_omap_probe(struct platform_device *pdev)
|
||||
|
||||
sprintf(up->name, "OMAP UART%d", up->port.line);
|
||||
up->port.mapbase = mem->start;
|
||||
up->port.membase = devm_ioremap(&pdev->dev, mem->start,
|
||||
resource_size(mem));
|
||||
if (!up->port.membase) {
|
||||
dev_err(&pdev->dev, "can't ioremap UART\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
up->port.membase = base;
|
||||
up->port.flags = omap_up_info->flags;
|
||||
up->port.uartclk = omap_up_info->uartclk;
|
||||
if (!up->port.uartclk) {
|
||||
@ -1754,12 +1699,12 @@ static int serial_omap_probe(struct platform_device *pdev)
|
||||
up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
|
||||
pm_qos_add_request(&up->pm_qos_request,
|
||||
PM_QOS_CPU_DMA_LATENCY, up->latency);
|
||||
serial_omap_uart_wq = create_singlethread_workqueue(up->name);
|
||||
INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
|
||||
|
||||
platform_set_drvdata(pdev, up);
|
||||
if (omap_up_info->autosuspend_timeout == 0)
|
||||
omap_up_info->autosuspend_timeout = -1;
|
||||
|
||||
device_init_wakeup(up->dev, true);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev,
|
||||
@ -1786,7 +1731,6 @@ static int serial_omap_probe(struct platform_device *pdev)
|
||||
err_add_port:
|
||||
pm_runtime_put(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err_ioremap:
|
||||
err_rs485:
|
||||
err_port_line:
|
||||
dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
|
||||
|
@ -257,6 +257,8 @@ struct eg20t_port {
|
||||
dma_addr_t rx_buf_dma;
|
||||
|
||||
struct dentry *debugfs;
|
||||
#define IRQ_NAME_SIZE 17
|
||||
char irq_name[IRQ_NAME_SIZE];
|
||||
|
||||
/* protect the eg20t_port private structure and io access to membase */
|
||||
spinlock_t lock;
|
||||
@ -1343,7 +1345,7 @@ static int pch_uart_startup(struct uart_port *port)
|
||||
return ret;
|
||||
|
||||
ret = request_irq(priv->port.irq, pch_uart_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, priv);
|
||||
priv->irq_name, priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -1588,13 +1590,8 @@ static void pch_uart_put_poll_char(struct uart_port *port,
|
||||
wait_for_xmitr(priv, UART_LSR_THRE);
|
||||
/*
|
||||
* Send the character out.
|
||||
* If a LF, also do CR...
|
||||
*/
|
||||
iowrite8(c, priv->membase + PCH_UART_THR);
|
||||
if (c == 10) {
|
||||
wait_for_xmitr(priv, UART_LSR_THRE);
|
||||
iowrite8(13, priv->membase + PCH_UART_THR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
@ -1818,6 +1815,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
|
||||
priv->port.line = board->line_no;
|
||||
priv->trigger = PCH_UART_HAL_TRIGGER_M;
|
||||
|
||||
snprintf(priv->irq_name, IRQ_NAME_SIZE,
|
||||
KBUILD_MODNAME ":" PCH_UART_DRIVER_DEVICE "%d",
|
||||
priv->port.line);
|
||||
|
||||
spin_lock_init(&priv->port.lock);
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
|
@ -711,13 +711,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port,
|
||||
wait_for_xmitr(up);
|
||||
/*
|
||||
* Send the character out.
|
||||
* If a LF, also do CR...
|
||||
*/
|
||||
serial_out(up, UART_TX, c);
|
||||
if (c == 10) {
|
||||
wait_for_xmitr(up);
|
||||
serial_out(up, UART_TX, 13);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
|
@ -53,6 +53,29 @@
|
||||
|
||||
#include "samsung.h"
|
||||
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
|
||||
defined(CONFIG_DEBUG_LL) && \
|
||||
!defined(MODULE)
|
||||
|
||||
extern void printascii(const char *);
|
||||
|
||||
__printf(1, 2)
|
||||
static void dbg(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
char buff[256];
|
||||
|
||||
va_start(va, fmt);
|
||||
vscnprintf(buff, sizeof(buf), fmt, va);
|
||||
va_end(va);
|
||||
|
||||
printascii(buff);
|
||||
}
|
||||
|
||||
#else
|
||||
#define dbg(fmt, ...) do { if (0) no_printk(fmt, ##__VA_ARGS__); } while (0)
|
||||
#endif
|
||||
|
||||
/* UART name and device definitions */
|
||||
|
||||
#define S3C24XX_SERIAL_NAME "ttySAC"
|
||||
@ -468,8 +491,8 @@ static int s3c24xx_serial_startup(struct uart_port *port)
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
int ret;
|
||||
|
||||
dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
|
||||
port->mapbase, port->membase);
|
||||
dbg("s3c24xx_serial_startup: port=%p (%08llx,%p)\n",
|
||||
port, (unsigned long long)port->mapbase, port->membase);
|
||||
|
||||
rx_enabled(port) = 1;
|
||||
|
||||
@ -514,8 +537,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
int ret;
|
||||
|
||||
dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
|
||||
port->mapbase, port->membase);
|
||||
dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
|
||||
port, (unsigned long long)port->mapbase, port->membase);
|
||||
|
||||
wr_regl(port, S3C64XX_UINTM, 0xf);
|
||||
|
||||
@ -1160,7 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
|
||||
dbg("resource %pR)\n", res);
|
||||
|
||||
port->membase = devm_ioremap(port->dev, res->start, resource_size(res));
|
||||
if (!port->membase) {
|
||||
@ -1203,7 +1226,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
wr_regl(port, S3C64XX_UINTSP, 0xf);
|
||||
}
|
||||
|
||||
dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
|
||||
dbg("port: map=%08x, mem=%p, irq=%d (%d,%d), clock=%u\n",
|
||||
port->mapbase, port->membase, port->irq,
|
||||
ourport->rx_irq, ourport->tx_irq, port->uartclk);
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
#ifndef __SAMSUNG_H
|
||||
#define __SAMSUNG_H
|
||||
|
||||
/*
|
||||
* Driver for Samsung SoC onboard UARTs.
|
||||
*
|
||||
@ -77,24 +80,4 @@ struct s3c24xx_uart_port {
|
||||
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
|
||||
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
|
||||
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
|
||||
defined(CONFIG_DEBUG_LL) && \
|
||||
!defined(MODULE)
|
||||
|
||||
extern void printascii(const char *);
|
||||
|
||||
static void dbg(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
char buff[256];
|
||||
|
||||
va_start(va, fmt);
|
||||
vsprintf(buff, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
printascii(buff);
|
||||
}
|
||||
|
||||
#else
|
||||
#define dbg(x...) do { } while (0)
|
||||
#endif
|
||||
|
1277
drivers/tty/serial/sc16is7xx.c
Normal file
1277
drivers/tty/serial/sc16is7xx.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -474,9 +474,7 @@ static void sccnxp_timer(unsigned long data)
|
||||
sccnxp_handle_events(s);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
|
||||
if (!timer_pending(&s->timer))
|
||||
mod_timer(&s->timer, jiffies +
|
||||
usecs_to_jiffies(s->pdata.poll_time_us));
|
||||
mod_timer(&s->timer, jiffies + usecs_to_jiffies(s->pdata.poll_time_us));
|
||||
}
|
||||
|
||||
static irqreturn_t sccnxp_ist(int irq, void *dev_id)
|
||||
@ -674,6 +672,8 @@ static void sccnxp_set_termios(struct uart_port *port,
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNBRK)
|
||||
port->ignore_status_mask |= SR_BRK;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= SR_PE;
|
||||
if (!(termios->c_cflag & CREAD))
|
||||
port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK;
|
||||
|
||||
|
@ -174,8 +174,12 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
|
||||
}
|
||||
|
||||
if (tty_port_cts_enabled(port)) {
|
||||
/*
|
||||
* if hw support flow control without software intervention,
|
||||
* then skip the below check
|
||||
*/
|
||||
if (tty_port_cts_enabled(port) &&
|
||||
!(uport->flags & UPF_HARD_FLOW)) {
|
||||
spin_lock_irq(&uport->lock);
|
||||
if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
|
||||
tty->hw_stopped = 1;
|
||||
@ -2239,6 +2243,9 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
|
||||
return;
|
||||
|
||||
port = state->uart_port;
|
||||
|
||||
if (ch == '\n')
|
||||
port->ops->poll_put_char(port, '\r');
|
||||
port->ops->poll_put_char(port, ch);
|
||||
}
|
||||
#endif
|
||||
@ -2772,7 +2779,9 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
|
||||
|
||||
uport->icount.cts++;
|
||||
|
||||
if (tty_port_cts_enabled(port)) {
|
||||
/* skip below code if the hw flow control is supported */
|
||||
if (tty_port_cts_enabled(port) &&
|
||||
!(uport->flags & UPF_HARD_FLOW)) {
|
||||
if (tty->hw_stopped) {
|
||||
if (status) {
|
||||
tty->hw_stopped = 0;
|
||||
|
143
drivers/tty/serial/serial_mctrl_gpio.c
Normal file
143
drivers/tty/serial/serial_mctrl_gpio.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Helpers for controlling modem lines via GPIO
|
||||
*
|
||||
* Copyright (C) 2014 Paratronic S.A.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <uapi/asm-generic/termios.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
struct mctrl_gpios {
|
||||
struct gpio_desc *gpio[UART_GPIO_MAX];
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
unsigned int mctrl;
|
||||
bool dir_out;
|
||||
} mctrl_gpios_desc[UART_GPIO_MAX] = {
|
||||
{ "cts", TIOCM_CTS, false, },
|
||||
{ "dsr", TIOCM_DSR, false, },
|
||||
{ "dcd", TIOCM_CD, false, },
|
||||
{ "rng", TIOCM_RNG, false, },
|
||||
{ "rts", TIOCM_RTS, true, },
|
||||
{ "dtr", TIOCM_DTR, true, },
|
||||
{ "out1", TIOCM_OUT1, true, },
|
||||
{ "out2", TIOCM_OUT2, true, },
|
||||
};
|
||||
|
||||
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (IS_ERR_OR_NULL(gpios))
|
||||
return;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
|
||||
mctrl_gpios_desc[i].dir_out)
|
||||
gpiod_set_value(gpios->gpio[i],
|
||||
!!(mctrl & mctrl_gpios_desc[i].mctrl));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
|
||||
|
||||
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
enum mctrl_gpio_idx gidx)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
|
||||
return gpios->gpio[gidx];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
|
||||
|
||||
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
/*
|
||||
* return it unchanged if the structure is not allocated
|
||||
*/
|
||||
if (IS_ERR_OR_NULL(gpios))
|
||||
return *mctrl;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
|
||||
!mctrl_gpios_desc[i].dir_out) {
|
||||
if (gpiod_get_value(gpios->gpio[i]))
|
||||
*mctrl |= mctrl_gpios_desc[i].mctrl;
|
||||
else
|
||||
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
|
||||
}
|
||||
}
|
||||
|
||||
return *mctrl;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_get);
|
||||
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
|
||||
{
|
||||
struct mctrl_gpios *gpios;
|
||||
enum mctrl_gpio_idx i;
|
||||
int err;
|
||||
|
||||
gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
|
||||
if (!gpios)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
gpios->gpio[i] = devm_gpiod_get_index(dev,
|
||||
mctrl_gpios_desc[i].name,
|
||||
idx);
|
||||
|
||||
/*
|
||||
* The GPIOs are maybe not all filled,
|
||||
* this is not an error.
|
||||
*/
|
||||
if (IS_ERR_OR_NULL(gpios->gpio[i]))
|
||||
continue;
|
||||
|
||||
if (mctrl_gpios_desc[i].dir_out)
|
||||
err = gpiod_direction_output(gpios->gpio[i], 0);
|
||||
else
|
||||
err = gpiod_direction_input(gpios->gpio[i]);
|
||||
if (err) {
|
||||
dev_dbg(dev, "Unable to set direction for %s GPIO",
|
||||
mctrl_gpios_desc[i].name);
|
||||
devm_gpiod_put(dev, gpios->gpio[i]);
|
||||
gpios->gpio[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return gpios;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
|
||||
|
||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
if (IS_ERR_OR_NULL(gpios))
|
||||
return;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
if (!IS_ERR_OR_NULL(gpios->gpio[i]))
|
||||
devm_gpiod_put(dev, gpios->gpio[i]);
|
||||
devm_kfree(dev, gpios);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_free);
|
110
drivers/tty/serial/serial_mctrl_gpio.h
Normal file
110
drivers/tty/serial/serial_mctrl_gpio.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Helpers for controlling modem lines via GPIO
|
||||
*
|
||||
* Copyright (C) 2014 Paratronic S.A.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SERIAL_MCTRL_GPIO__
|
||||
#define __SERIAL_MCTRL_GPIO__
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
enum mctrl_gpio_idx {
|
||||
UART_GPIO_CTS,
|
||||
UART_GPIO_DSR,
|
||||
UART_GPIO_DCD,
|
||||
UART_GPIO_RNG,
|
||||
UART_GPIO_RI = UART_GPIO_RNG,
|
||||
UART_GPIO_RTS,
|
||||
UART_GPIO_DTR,
|
||||
UART_GPIO_OUT1,
|
||||
UART_GPIO_OUT2,
|
||||
UART_GPIO_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* Opaque descriptor for modem lines controlled by GPIOs
|
||||
*/
|
||||
struct mctrl_gpios;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
|
||||
/*
|
||||
* Set state of the modem control output lines via GPIOs.
|
||||
*/
|
||||
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
|
||||
|
||||
/*
|
||||
* Get state of the modem control output lines from GPIOs.
|
||||
* The mctrl flags are updated and returned.
|
||||
*/
|
||||
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
|
||||
|
||||
/*
|
||||
* Returns the associated struct gpio_desc to the modem line gidx
|
||||
*/
|
||||
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
enum mctrl_gpio_idx gidx);
|
||||
|
||||
/*
|
||||
* Request and set direction of modem control lines GPIOs.
|
||||
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
|
||||
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
||||
* allocation error.
|
||||
*/
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
|
||||
|
||||
/*
|
||||
* Free the mctrl_gpios structure.
|
||||
* Normally, this function will not be called, as the GPIOs will
|
||||
* be disposed of by the resource management code.
|
||||
*/
|
||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
|
||||
|
||||
#else /* GPIOLIB */
|
||||
|
||||
static inline
|
||||
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
{
|
||||
return *mctrl;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
enum mctrl_gpio_idx gidx)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline
|
||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* GPIOLIB */
|
||||
|
||||
#endif
|
@ -535,13 +535,8 @@ static void serial_txx9_put_poll_char(struct uart_port *port, unsigned char c)
|
||||
wait_for_xmitr(up);
|
||||
/*
|
||||
* Send the character out.
|
||||
* If a LF, also do CR...
|
||||
*/
|
||||
sio_out(up, TXX9_SITFIFO, c);
|
||||
if (c == 10) {
|
||||
wait_for_xmitr(up);
|
||||
sio_out(up, TXX9_SITFIFO, 13);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
|
@ -358,9 +358,11 @@ static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
|
||||
struct uart_port *port = &sirfport->port;
|
||||
spin_lock(&port->lock);
|
||||
if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
|
||||
uart_handle_cts_change(port,
|
||||
!gpio_get_value(sirfport->cts_gpio));
|
||||
spin_unlock(&port->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -428,10 +430,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
|
||||
sirfport->rx_io_count += rx_count;
|
||||
port->icount.rx += rx_count;
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
spin_lock(&port->lock);
|
||||
|
||||
return rx_count;
|
||||
}
|
||||
|
||||
@ -465,6 +463,7 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
xmit->tail = (xmit->tail + sirfport->transfer_size) &
|
||||
(UART_XMIT_SIZE - 1);
|
||||
port->icount.tx += sirfport->transfer_size;
|
||||
@ -473,10 +472,9 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
|
||||
if (sirfport->tx_dma_addr)
|
||||
dma_unmap_single(port->dev, sirfport->tx_dma_addr,
|
||||
sirfport->transfer_size, DMA_TO_DEVICE);
|
||||
spin_lock_irqsave(&sirfport->tx_lock, flags);
|
||||
sirfport->tx_dma_state = TX_DMA_IDLE;
|
||||
sirfsoc_uart_tx_with_dma(sirfport);
|
||||
spin_unlock_irqrestore(&sirfport->tx_lock, flags);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_insert_rx_buf_to_tty(
|
||||
@ -489,7 +487,6 @@ static void sirfsoc_uart_insert_rx_buf_to_tty(
|
||||
inserted = tty_insert_flip_string(tport,
|
||||
sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
|
||||
port->icount.rx += inserted;
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
|
||||
@ -525,7 +522,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
|
||||
unsigned long flags;
|
||||
struct dma_tx_state tx_state;
|
||||
|
||||
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
|
||||
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
|
||||
@ -541,12 +538,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
|
||||
SIRFUART_IO_MODE);
|
||||
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
||||
spin_lock(&port->lock);
|
||||
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
|
||||
spin_unlock(&port->lock);
|
||||
if (sirfport->rx_io_count == 4) {
|
||||
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
||||
sirfport->rx_io_count = 0;
|
||||
wr_regl(port, ureg->sirfsoc_int_st_reg,
|
||||
uint_st->sirfsoc_rx_done);
|
||||
@ -557,11 +550,8 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
||||
|
||||
sirfsoc_uart_start_next_rx_dma(port);
|
||||
} else {
|
||||
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
||||
wr_regl(port, ureg->sirfsoc_int_st_reg,
|
||||
uint_st->sirfsoc_rx_done);
|
||||
if (!sirfport->is_marco)
|
||||
@ -571,8 +561,9 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
|
||||
@ -581,8 +572,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
struct dma_tx_state tx_state;
|
||||
spin_lock(&sirfport->rx_lock);
|
||||
|
||||
dmaengine_tx_status(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
|
||||
dmaengine_terminate_all(sirfport->rx_dma_chan);
|
||||
@ -595,7 +584,6 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
uint_en->sirfsoc_rx_timeout_en);
|
||||
spin_unlock(&sirfport->rx_lock);
|
||||
tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
|
||||
}
|
||||
|
||||
@ -659,7 +647,6 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
|
||||
intr_status &= port->read_status_mask;
|
||||
uart_insert_char(port, intr_status,
|
||||
uint_en->sirfsoc_rx_oflow_en, 0, flag);
|
||||
tty_flip_buffer_push(&state->port);
|
||||
}
|
||||
recv_char:
|
||||
if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
|
||||
@ -684,6 +671,9 @@ recv_char:
|
||||
sirfsoc_uart_pio_rx_chars(port,
|
||||
SIRFSOC_UART_IO_RX_MAX_CNT);
|
||||
}
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(&state->port);
|
||||
spin_lock(&port->lock);
|
||||
if (intr_status & uint_st->sirfsoc_txfifo_empty) {
|
||||
if (sirfport->tx_dma_chan)
|
||||
sirfsoc_uart_tx_with_dma(sirfport);
|
||||
@ -702,6 +692,7 @@ recv_char:
|
||||
}
|
||||
}
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -713,7 +704,7 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
unsigned long flags;
|
||||
struct dma_tx_state tx_state;
|
||||
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
|
||||
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
|
||||
@ -726,17 +717,20 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
|
||||
sirfport->rx_completed++;
|
||||
sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
|
||||
}
|
||||
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_rx_dma_complete_callback(void *param)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
|
||||
spin_lock(&sirfport->rx_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sirfport->port.lock, flags);
|
||||
sirfport->rx_issued++;
|
||||
sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
|
||||
spin_unlock(&sirfport->rx_lock);
|
||||
tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
|
||||
spin_unlock_irqrestore(&sirfport->port.lock, flags);
|
||||
}
|
||||
|
||||
/* submit rx dma task into dmaengine */
|
||||
@ -745,18 +739,14 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
||||
sirfport->rx_io_count = 0;
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
|
||||
~SIRFUART_IO_MODE);
|
||||
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
||||
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
|
||||
sirfsoc_rx_submit_one_dma_desc(port, i);
|
||||
sirfport->rx_completed = sirfport->rx_issued = 0;
|
||||
spin_lock_irqsave(&sirfport->rx_lock, flags);
|
||||
if (!sirfport->is_marco)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) |
|
||||
@ -764,7 +754,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
SIRFUART_RX_DMA_INT_EN(port, uint_en));
|
||||
spin_unlock_irqrestore(&sirfport->rx_lock, flags);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_start_rx(struct uart_port *port)
|
||||
@ -1228,7 +1217,7 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
|
||||
while (rd_regl(port,
|
||||
ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
|
||||
cpu_relax();
|
||||
wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_console_write(struct console *co, const char *s,
|
||||
@ -1369,8 +1358,6 @@ usp_no_flow_control:
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
spin_lock_init(&sirfport->rx_lock);
|
||||
spin_lock_init(&sirfport->tx_lock);
|
||||
tasklet_init(&sirfport->rx_dma_complete_tasklet,
|
||||
sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
|
||||
tasklet_init(&sirfport->rx_tmo_process_tasklet,
|
||||
|
@ -424,8 +424,6 @@ struct sirfsoc_uart_port {
|
||||
struct dma_chan *tx_dma_chan;
|
||||
dma_addr_t tx_dma_addr;
|
||||
struct dma_async_tx_descriptor *tx_dma_desc;
|
||||
spinlock_t rx_lock;
|
||||
spinlock_t tx_lock;
|
||||
struct tasklet_struct rx_dma_complete_tasklet;
|
||||
struct tasklet_struct rx_tmo_process_tasklet;
|
||||
unsigned int rx_io_count;
|
||||
@ -441,9 +439,7 @@ struct sirfsoc_uart_port {
|
||||
|
||||
/* Register Access Control */
|
||||
#define portaddr(port, reg) ((port)->membase + (reg))
|
||||
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
|
||||
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
|
||||
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
|
||||
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
|
||||
|
||||
/* UART Port Mask */
|
||||
|
@ -194,9 +194,9 @@ static inline u32 asc_txfifo_is_empty(struct uart_port *port)
|
||||
return asc_in(port, ASC_STA) & ASC_STA_TE;
|
||||
}
|
||||
|
||||
static inline int asc_txfifo_is_full(struct uart_port *port)
|
||||
static inline u32 asc_txfifo_is_half_empty(struct uart_port *port)
|
||||
{
|
||||
return asc_in(port, ASC_STA) & ASC_STA_TF;
|
||||
return asc_in(port, ASC_STA) & ASC_STA_THE;
|
||||
}
|
||||
|
||||
static inline const char *asc_port_name(struct uart_port *port)
|
||||
@ -628,7 +628,7 @@ static int asc_get_poll_char(struct uart_port *port)
|
||||
|
||||
static void asc_put_poll_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
while (asc_txfifo_is_full(port))
|
||||
while (!asc_txfifo_is_half_empty(port))
|
||||
cpu_relax();
|
||||
asc_out(port, ASC_TXBUF, c);
|
||||
}
|
||||
@ -783,7 +783,7 @@ static void asc_console_putchar(struct uart_port *port, int ch)
|
||||
unsigned int timeout = 1000000;
|
||||
|
||||
/* Wait for upto 1 second in case flow control is stopping us. */
|
||||
while (--timeout && asc_txfifo_is_full(port))
|
||||
while (--timeout && !asc_txfifo_is_half_empty(port))
|
||||
udelay(1);
|
||||
|
||||
asc_out(port, ASC_TXBUF, ch);
|
||||
|
@ -418,14 +418,23 @@ static struct uart_ops ulite_ops = {
|
||||
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
|
||||
static void ulite_console_wait_tx(struct uart_port *port)
|
||||
{
|
||||
int i;
|
||||
u8 val;
|
||||
unsigned long timeout;
|
||||
|
||||
/* Spin waiting for TX fifo to have space available */
|
||||
for (i = 0; i < 100000; i++) {
|
||||
/*
|
||||
* Spin waiting for TX fifo to have space available.
|
||||
* When using the Microblaze Debug Module this can take up to 1s
|
||||
*/
|
||||
timeout = jiffies + msecs_to_jiffies(1000);
|
||||
while (1) {
|
||||
val = uart_in32(ULITE_STATUS, port);
|
||||
if ((val & ULITE_STATUS_TXFULL) == 0)
|
||||
break;
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_warn(port->dev,
|
||||
"timeout waiting for TX buffer empty\n");
|
||||
break;
|
||||
}
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -179,7 +179,6 @@ struct uni_pagedir {
|
||||
unsigned long sum;
|
||||
unsigned char *inverse_translations[4];
|
||||
u16 *inverse_trans_unicode;
|
||||
int readonly;
|
||||
};
|
||||
|
||||
static struct uni_pagedir *dflt;
|
||||
@ -262,7 +261,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
|
||||
int m;
|
||||
if (glyph < 0 || glyph >= MAX_GLYPH)
|
||||
return 0;
|
||||
else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
|
||||
else if (!(p = *conp->vc_uni_pagedir_loc))
|
||||
return glyph;
|
||||
else if (use_unicode) {
|
||||
if (!p->inverse_trans_unicode)
|
||||
@ -287,7 +286,7 @@ static void update_user_maps(void)
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (!vc_cons_allocated(i))
|
||||
continue;
|
||||
p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
|
||||
p = *vc_cons[i].d->vc_uni_pagedir_loc;
|
||||
if (p && p != q) {
|
||||
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
|
||||
set_inverse_trans_unicode(vc_cons[i].d, p);
|
||||
@ -418,10 +417,10 @@ void con_free_unimap(struct vc_data *vc)
|
||||
{
|
||||
struct uni_pagedir *p;
|
||||
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
if (!p)
|
||||
return;
|
||||
*vc->vc_uni_pagedir_loc = 0;
|
||||
*vc->vc_uni_pagedir_loc = NULL;
|
||||
if (--p->refcount)
|
||||
return;
|
||||
con_release_unimap(p);
|
||||
@ -436,7 +435,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (!vc_cons_allocated(i))
|
||||
continue;
|
||||
q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
|
||||
q = *vc_cons[i].d->vc_uni_pagedir_loc;
|
||||
if (!q || q == p || q->sum != p->sum)
|
||||
continue;
|
||||
for (j = 0; j < 32; j++) {
|
||||
@ -459,7 +458,7 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
|
||||
}
|
||||
if (j == 32) {
|
||||
q->refcount++;
|
||||
*conp->vc_uni_pagedir_loc = (unsigned long)q;
|
||||
*conp->vc_uni_pagedir_loc = q;
|
||||
con_release_unimap(p);
|
||||
kfree(p);
|
||||
return 1;
|
||||
@ -500,10 +499,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
{
|
||||
struct uni_pagedir *p, *q;
|
||||
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
if (p && p->readonly)
|
||||
return -EIO;
|
||||
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
if (!p || --p->refcount) {
|
||||
q = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!q) {
|
||||
@ -512,7 +508,7 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
return -ENOMEM;
|
||||
}
|
||||
q->refcount=1;
|
||||
*vc->vc_uni_pagedir_loc = (unsigned long)q;
|
||||
*vc->vc_uni_pagedir_loc = q;
|
||||
} else {
|
||||
if (p == dflt) dflt = NULL;
|
||||
p->refcount++;
|
||||
@ -536,19 +532,13 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
int err = 0, err1, i;
|
||||
struct uni_pagedir *p, *q;
|
||||
|
||||
if (!ct)
|
||||
return 0;
|
||||
|
||||
console_lock();
|
||||
|
||||
/* Save original vc_unipagdir_loc in case we allocate a new one */
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
if (p->readonly) {
|
||||
console_unlock();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!ct) {
|
||||
console_unlock();
|
||||
return 0;
|
||||
}
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
|
||||
if (p->refcount > 1) {
|
||||
int j, k;
|
||||
@ -564,7 +554,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
* Since refcount was > 1, con_clear_unimap() allocated a
|
||||
* a new uni_pagedir for this vc. Re: p != q
|
||||
*/
|
||||
q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
q = *vc->vc_uni_pagedir_loc;
|
||||
|
||||
/*
|
||||
* uni_pgdir is a 32*32*64 table with rows allocated
|
||||
@ -586,7 +576,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
err1 = con_insert_unipair(q, l, p2[k]);
|
||||
if (err1) {
|
||||
p->refcount++;
|
||||
*vc->vc_uni_pagedir_loc = (unsigned long)p;
|
||||
*vc->vc_uni_pagedir_loc = p;
|
||||
con_release_unimap(q);
|
||||
kfree(q);
|
||||
console_unlock();
|
||||
@ -655,12 +645,12 @@ int con_set_default_unimap(struct vc_data *vc)
|
||||
struct uni_pagedir *p;
|
||||
|
||||
if (dflt) {
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
if (p == dflt)
|
||||
return 0;
|
||||
|
||||
dflt->refcount++;
|
||||
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
|
||||
*vc->vc_uni_pagedir_loc = dflt;
|
||||
if (p && !--p->refcount) {
|
||||
con_release_unimap(p);
|
||||
kfree(p);
|
||||
@ -674,7 +664,7 @@ int con_set_default_unimap(struct vc_data *vc)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
q = dfont_unitable;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
@ -685,7 +675,7 @@ int con_set_default_unimap(struct vc_data *vc)
|
||||
}
|
||||
|
||||
if (con_unify_unimap(vc, p)) {
|
||||
dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
dflt = *vc->vc_uni_pagedir_loc;
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -713,9 +703,9 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
|
||||
if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
|
||||
return 0;
|
||||
con_free_unimap(dst_vc);
|
||||
q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
|
||||
q = *src_vc->vc_uni_pagedir_loc;
|
||||
q->refcount++;
|
||||
*dst_vc->vc_uni_pagedir_loc = (long)q;
|
||||
*dst_vc->vc_uni_pagedir_loc = q;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(con_copy_unimap);
|
||||
@ -737,7 +727,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
||||
|
||||
ect = 0;
|
||||
if (*vc->vc_uni_pagedir_loc) {
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
for (i = 0; i < 32; i++)
|
||||
if ((p1 = p->uni_pgdir[i]))
|
||||
for (j = 0; j < 32; j++)
|
||||
@ -810,7 +800,7 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
|
||||
if (!*conp->vc_uni_pagedir_loc)
|
||||
return -3;
|
||||
|
||||
p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
|
||||
p = *conp->vc_uni_pagedir_loc;
|
||||
if ((p1 = p->uni_pgdir[ucs >> 11]) &&
|
||||
(p2 = p1[(ucs >> 6) & 0x1f]) &&
|
||||
(h = p2[ucs & 0x3f]) < MAX_GLYPH)
|
||||
|
@ -735,7 +735,7 @@ static void visual_init(struct vc_data *vc, int num, int init)
|
||||
vc->vc_num = num;
|
||||
vc->vc_display_fg = &master_display_fg;
|
||||
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
|
||||
vc->vc_uni_pagedir = 0;
|
||||
vc->vc_uni_pagedir = NULL;
|
||||
vc->vc_hi_font_mask = 0;
|
||||
vc->vc_complement_mask = 0;
|
||||
vc->vc_can_do_color = 0;
|
||||
@ -1231,6 +1231,52 @@ static void default_attr(struct vc_data *vc)
|
||||
vc->vc_color = vc->vc_def_color;
|
||||
}
|
||||
|
||||
struct rgb { u8 r; u8 g; u8 b; };
|
||||
|
||||
struct rgb rgb_from_256(int i)
|
||||
{
|
||||
struct rgb c;
|
||||
if (i < 8) { /* Standard colours. */
|
||||
c.r = i&1 ? 0xaa : 0x00;
|
||||
c.g = i&2 ? 0xaa : 0x00;
|
||||
c.b = i&4 ? 0xaa : 0x00;
|
||||
} else if (i < 16) {
|
||||
c.r = i&1 ? 0xff : 0x55;
|
||||
c.g = i&2 ? 0xff : 0x55;
|
||||
c.b = i&4 ? 0xff : 0x55;
|
||||
} else if (i < 232) { /* 6x6x6 colour cube. */
|
||||
c.r = (i - 16) / 36 * 85 / 2;
|
||||
c.g = (i - 16) / 6 % 6 * 85 / 2;
|
||||
c.b = (i - 16) % 6 * 85 / 2;
|
||||
} else /* Grayscale ramp. */
|
||||
c.r = c.g = c.b = i * 10 - 2312;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void rgb_foreground(struct vc_data *vc, struct rgb c)
|
||||
{
|
||||
u8 hue, max = c.r;
|
||||
if (c.g > max)
|
||||
max = c.g;
|
||||
if (c.b > max)
|
||||
max = c.b;
|
||||
hue = (c.r > max/2 ? 4 : 0)
|
||||
| (c.g > max/2 ? 2 : 0)
|
||||
| (c.b > max/2 ? 1 : 0);
|
||||
if (hue == 7 && max <= 0x55)
|
||||
hue = 0, vc->vc_intensity = 2;
|
||||
else
|
||||
vc->vc_intensity = (max > 0xaa) + 1;
|
||||
vc->vc_color = (vc->vc_color & 0xf0) | hue;
|
||||
}
|
||||
|
||||
static void rgb_background(struct vc_data *vc, struct rgb c)
|
||||
{
|
||||
/* For backgrounds, err on the dark side. */
|
||||
vc->vc_color = (vc->vc_color & 0x0f)
|
||||
| (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3;
|
||||
}
|
||||
|
||||
/* console_lock is held */
|
||||
static void csi_m(struct vc_data *vc)
|
||||
{
|
||||
@ -1302,8 +1348,7 @@ static void csi_m(struct vc_data *vc)
|
||||
case 27:
|
||||
vc->vc_reverse = 0;
|
||||
break;
|
||||
case 38:
|
||||
case 48: /* ITU T.416
|
||||
case 38: /* ITU T.416
|
||||
* Higher colour modes.
|
||||
* They break the usual properties of SGR codes
|
||||
* and thus need to be detected and ignored by
|
||||
@ -1315,15 +1360,41 @@ static void csi_m(struct vc_data *vc)
|
||||
i++;
|
||||
if (i > vc->vc_npar)
|
||||
break;
|
||||
if (vc->vc_par[i] == 5) /* 256 colours */
|
||||
i++; /* ubiquitous */
|
||||
else if (vc->vc_par[i] == 2) /* 24 bit colours */
|
||||
i += 3; /* extremely rare */
|
||||
if (vc->vc_par[i] == 5 && /* 256 colours */
|
||||
i < vc->vc_npar) { /* ubiquitous */
|
||||
i++;
|
||||
rgb_foreground(vc,
|
||||
rgb_from_256(vc->vc_par[i]));
|
||||
} else if (vc->vc_par[i] == 2 && /* 24 bit */
|
||||
i <= vc->vc_npar + 3) {/* extremely rare */
|
||||
struct rgb c = {r:vc->vc_par[i+1],
|
||||
g:vc->vc_par[i+2],
|
||||
b:vc->vc_par[i+3]};
|
||||
rgb_foreground(vc, c);
|
||||
i += 3;
|
||||
}
|
||||
/* Subcommands 3 (CMY) and 4 (CMYK) are so insane
|
||||
* that detecting them is not worth the few extra
|
||||
* bytes of kernel's size.
|
||||
* there's no point in supporting them.
|
||||
*/
|
||||
break;
|
||||
case 48:
|
||||
i++;
|
||||
if (i > vc->vc_npar)
|
||||
break;
|
||||
if (vc->vc_par[i] == 5 && /* 256 colours */
|
||||
i < vc->vc_npar) {
|
||||
i++;
|
||||
rgb_background(vc,
|
||||
rgb_from_256(vc->vc_par[i]));
|
||||
} else if (vc->vc_par[i] == 2 && /* 24 bit */
|
||||
i <= vc->vc_npar + 3) {
|
||||
struct rgb c = {r:vc->vc_par[i+1],
|
||||
g:vc->vc_par[i+2],
|
||||
b:vc->vc_par[i+3]};
|
||||
rgb_background(vc, c);
|
||||
i += 3;
|
||||
}
|
||||
break;
|
||||
case 39:
|
||||
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
|
||||
break;
|
||||
|
@ -87,7 +87,8 @@ static void vgacon_save_screen(struct vc_data *c);
|
||||
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
|
||||
int lines);
|
||||
static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
|
||||
static unsigned long vgacon_uni_pagedir[2];
|
||||
static struct uni_pagedir *vgacon_uni_pagedir;
|
||||
static int vgacon_refcount;
|
||||
|
||||
/* Description of the hardware situation */
|
||||
static int vga_init_done __read_mostly;
|
||||
@ -553,7 +554,7 @@ static const char *vgacon_startup(void)
|
||||
|
||||
static void vgacon_init(struct vc_data *c, int init)
|
||||
{
|
||||
unsigned long p;
|
||||
struct uni_pagedir *p;
|
||||
|
||||
/*
|
||||
* We cannot be loaded as a module, therefore init is always 1,
|
||||
@ -575,12 +576,12 @@ static void vgacon_init(struct vc_data *c, int init)
|
||||
if (vga_512_chars)
|
||||
c->vc_hi_font_mask = 0x0800;
|
||||
p = *c->vc_uni_pagedir_loc;
|
||||
if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
|
||||
!--c->vc_uni_pagedir_loc[1])
|
||||
if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
|
||||
con_free_unimap(c);
|
||||
c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
|
||||
vgacon_uni_pagedir[1]++;
|
||||
if (!vgacon_uni_pagedir[0] && p)
|
||||
c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
|
||||
vgacon_refcount++;
|
||||
}
|
||||
if (!vgacon_uni_pagedir && p)
|
||||
con_set_default_unimap(c);
|
||||
|
||||
/* Only set the default if the user didn't deliberately override it */
|
||||
@ -597,7 +598,7 @@ static void vgacon_deinit(struct vc_data *c)
|
||||
vga_set_mem_top(c);
|
||||
}
|
||||
|
||||
if (!--vgacon_uni_pagedir[1])
|
||||
if (!--vgacon_refcount)
|
||||
con_free_unimap(c);
|
||||
c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
|
||||
con_set_default_unimap(c);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct vt_struct;
|
||||
struct uni_pagedir;
|
||||
|
||||
#define NPAR 16
|
||||
|
||||
@ -104,8 +105,8 @@ struct vc_data {
|
||||
unsigned int vc_bell_pitch; /* Console bell pitch */
|
||||
unsigned int vc_bell_duration; /* Console bell duration */
|
||||
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
|
||||
unsigned long vc_uni_pagedir;
|
||||
unsigned long *vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
|
||||
struct uni_pagedir *vc_uni_pagedir;
|
||||
struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
|
||||
bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
|
||||
/* additional information is in vt_kern.h */
|
||||
};
|
||||
|
@ -84,7 +84,6 @@ struct atmel_uart_data {
|
||||
short use_dma_rx; /* use receive DMA? */
|
||||
void __iomem *regs; /* virt. base address, if any */
|
||||
struct serial_rs485 rs485; /* rs485 settings */
|
||||
int rts_gpio; /* optional RTS GPIO */
|
||||
};
|
||||
|
||||
/* CAN */
|
||||
|
@ -285,6 +285,22 @@ static inline int uart_poll_timeout(struct uart_port *port)
|
||||
/*
|
||||
* Console helpers.
|
||||
*/
|
||||
struct earlycon_device {
|
||||
struct console *con;
|
||||
struct uart_port port;
|
||||
char options[16]; /* e.g., 115200n8 */
|
||||
unsigned int baud;
|
||||
};
|
||||
int setup_earlycon(char *buf, const char *match,
|
||||
int (*setup)(struct earlycon_device *, const char *));
|
||||
|
||||
#define EARLYCON_DECLARE(name, func) \
|
||||
static int __init name ## _setup_earlycon(char *buf) \
|
||||
{ \
|
||||
return setup_earlycon(buf, __stringify(name), func); \
|
||||
} \
|
||||
early_param("earlycon", name ## _setup_earlycon);
|
||||
|
||||
struct uart_port *uart_get_console(struct uart_port *ports, int nr,
|
||||
struct console *c);
|
||||
void uart_parse_options(char *options, int *baud, int *parity, int *bits,
|
||||
|
@ -92,7 +92,10 @@
|
||||
* This function is called by the low-level tty driver to signal
|
||||
* that line discpline should try to send more characters to the
|
||||
* low-level driver for transmission. If the line discpline does
|
||||
* not have any more data to send, it can just return.
|
||||
* not have any more data to send, it can just return. If the line
|
||||
* discipline does have some data to send, please arise a tasklet
|
||||
* or workqueue to do the real data transfer. Do not send data in
|
||||
* this hook, it may leads to a deadlock.
|
||||
*
|
||||
* int (*hangup)(struct tty_struct *)
|
||||
*
|
||||
|
@ -211,7 +211,7 @@
|
||||
/* VIA VT8500 SoC */
|
||||
#define PORT_VT8500 97
|
||||
|
||||
/* Xilinx PSS UART */
|
||||
/* Cadence (Xilinx Zynq) UART */
|
||||
#define PORT_XUARTPS 98
|
||||
|
||||
/* Atheros AR933X SoC */
|
||||
@ -238,4 +238,10 @@
|
||||
/* Tilera TILE-Gx UART */
|
||||
#define PORT_TILEGX 106
|
||||
|
||||
/* MEN 16z135 UART */
|
||||
#define PORT_MEN_Z135 107
|
||||
|
||||
/* SC16IS74xx */
|
||||
#define PORT_SC16IS7XX 108
|
||||
|
||||
#endif /* _UAPILINUX_SERIAL_CORE_H */
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
#define UART_IIR 2 /* In: Interrupt ID Register */
|
||||
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
|
||||
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
|
||||
#define UART_IIR_ID 0x0e /* Mask for the interrupt ID */
|
||||
#define UART_IIR_MSI 0x00 /* Modem status interrupt */
|
||||
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
|
||||
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
|
||||
|
@ -2413,6 +2413,7 @@ int unregister_console(struct console *console)
|
||||
if (console_drivers != NULL && console->flags & CON_CONSDEV)
|
||||
console_drivers->flags |= CON_CONSDEV;
|
||||
|
||||
console->flags &= ~CON_ENABLED;
|
||||
console_unlock();
|
||||
console_sysfs_notify();
|
||||
return res;
|
||||
|
Loading…
Reference in New Issue
Block a user