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

Pull tty / serial driver updates from Greg KH:
 "Here is the "big" set of tty and serial driver updates for 7.4-rc1.

  It's not really all that big, it's been kind of quiet in this area of
  the tree this development cycle in relation to other parts of the
  tree. But still, included in here are:

   - 8250 port updates and fixes

   - 8250 driver cleanups by Jiri

   - deletion of the obsolete moxa driver (making this pull request
     remove more lines than added!)

   - different serial driver updates for dma and other reported issues

  All of these have been in linux-next with no reported problems"

* tag 'tty-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (91 commits)
  tty: hvc: dcc: Detect JTAG connection only on CPU core 0
  serial: earlycon: Use isdigit() in earlycon_init()
  serial: core: Use isdigit() in uart_parse_options()
  dt-bindings: serial: snps-dw-apb-uart: Add Synaptics sl2610 uart
  serial: amba-pl011: drive the bus during break in RS485 mode
  serial: mcf: update author email address
  serial: pmac_zilog: report received breaks
  serial: pmac_zilog: push received data to the port that received it
  serial: amba-pl011: keep transmitter enabled when disabling RS485
  serial: ma35d1: Do not force-enable an unselected console
  serial: amba-pl011: honour delay_rts_before_send for every write
  Revert "serial: 8250_port: Drop duplicate NULL check"
  serial: 8250: make port operations work on struct uart_8250_port
  serial: 8250_omap: set priv->line before enabling the IRQ
  serial: 8250_lpss: do not touch uninitialized line in ehl_serial_exit()
  serial: 8250_exar: store the GPIO platform device in struct exar8250
  serial: 8250_exar: remove useless void * casts
  serial: 8250: drop err label from serial8250_register_8250_port()
  serial: core: fix TIOCSSERIAL and TIOCSERCONFIG on uninitialised ports
  serial: max310x: don't transmit while an RS485 reconfigure is pending
  ...
This commit is contained in:
Linus Torvalds committed 2026-10-24 15:25:54 -10:00
commit cb8fef4b07
92 files changed
+1862 -2999

No files matched your search

+2 -11
View File
@@ -2388,18 +2388,9 @@
171 char Reserved for IEEE 1394 (Firewire)
172 char Moxa Intellio serial card
0 = /dev/ttyMX0 First Moxa port
1 = /dev/ttyMX1 Second Moxa port
...
127 = /dev/ttyMX127 128th Moxa port
128 = /dev/moxactl Moxa control port
172 char
173 char Moxa Intellio serial card - alternate devices
0 = /dev/cumx0 Callout device for ttyMX0
1 = /dev/cumx1 Callout device for ttyMX1
...
127 = /dev/cumx127 Callout device for ttyMX127
173 char
174 char SmartIO serial card
0 = /dev/ttySI0 First SmartIO port
@@ -100,19 +100,25 @@ allOf:
properties:
compatible:
oneOf:
- const: ns8250
- const: ns16450
- const: ns16550
- const: ns16550a
- const: ns16850
- const: aspeed,ast2400-vuart
- const: aspeed,ast2500-vuart
- const: intel,xscale-uart
- const: mrvl,pxa-uart
- const: nuvoton,wpcm450-uart
- const: nuvoton,npcm750-uart
- const: nvidia,tegra20-uart
- const: nxp,lpc3220-uart
- enum:
- ns8250
- ns16450
- ns16550
- ns16550a
- ns16850
- airoha,an7581-hsuart
- airoha,en7523-uart
- aspeed,ast2400-vuart
- aspeed,ast2500-vuart
- intel,xscale-uart
- mrvl,pxa-uart
- nuvoton,npcm750-uart
- nuvoton,wpcm450-uart
- nvidia,tegra20-uart
- nxp,lpc3220-uart
- items:
- const: airoha,an7581-uart
- const: airoha,en7523-uart
- items:
- enum:
- exar,xr16l2552
@@ -19,6 +19,7 @@ properties:
- items:
- enum:
- axiado,ax3000-uart
- axiado,ax3005-uart
- xlnx,zynqmp-uart
- const: cdns,uart-r1p12
@@ -97,14 +97,14 @@ properties:
dmas:
minItems: 2
maxItems: 4
maxItems: 6
description:
Must contain a list of pairs of references to DMA specifiers, one for
transmission, and one for reception.
dma-names:
minItems: 2
maxItems: 4
maxItems: 6
items:
enum:
- tx
@@ -145,14 +145,14 @@ properties:
dmas:
minItems: 2
maxItems: 4
maxItems: 6
description:
Must contain a list of pairs of references to DMA specifiers, one for
transmission, and one for reception.
dma-names:
minItems: 2
maxItems: 4
maxItems: 6
items:
enum:
- tx
@@ -34,7 +34,16 @@ allOf:
properties:
resets:
minItems: 2
else:
- if:
not:
properties:
compatible:
contains:
enum:
- starfive,jh7110-uart
- syna,sl2610-uart
then:
properties:
resets:
maxItems: 1
@@ -80,6 +89,8 @@ properties:
- starfive,jh7100-hsuart
- starfive,jh7100-uart
- starfive,jh7110-uart
- syna,sl2610-uart
- ti,tda54-uart
- ultrarisc,dp1000-uart
- const: snps,dw-apb-uart
- const: snps,dw-apb-uart
+1 -1
View File
@@ -70,7 +70,7 @@ Other functions
.. kernel-doc:: drivers/tty/serial/serial_core.c
:identifiers: uart_update_timeout uart_get_baud_rate uart_get_divisor
uart_match_port uart_write_wakeup uart_register_driver
uart_write_wakeup uart_register_driver
uart_unregister_driver uart_suspend_port uart_resume_port
uart_add_one_port uart_remove_one_port uart_console_write
uart_parse_earlycon uart_parse_options uart_set_options
+1 -1
View File
@@ -18604,7 +18604,7 @@ F: Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml
F: drivers/net/dsa/motorcomm/
F: net/dsa/tag_yt921x.c
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
MOXA SMARTIO/INDUSTIO SERIAL CARD
M: Jiri Slaby <jirislaby@kernel.org>
S: Maintained
F: Documentation/driver-api/tty/moxa-smartio.rst
+1
View File
@@ -256,6 +256,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
{ "AMDI0015", APD_ADDR(wt_i3c_desc) },
{ "AMDI0019", APD_ADDR(wt_i2c_desc) },
{ "AMDI0020", APD_ADDR(cz_uart_desc) },
{ "AMDI0021", APD_ADDR(cz_uart_desc) },
{ "AMDI0022", APD_ADDR(cz_uart_desc) },
{ "HYGO0010", APD_ADDR(wt_i2c_desc) },
#endif
-7
View File
@@ -64,13 +64,6 @@ config MMC_BLOCK_MINORS
If unsure, say 8 here.
config SDIO_UART
tristate "SDIO UART/GPS class support"
depends on TTY
help
SDIO function driver for SDIO cards that implements the UART
class, as well as the GPS class which appears like a UART.
config MMC_TEST
tristate "MMC host test driver"
help
-1
View File
@@ -17,5 +17,4 @@ mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
obj-$(CONFIG_MMC_TEST) += mmc_test.o
obj-$(CONFIG_SDIO_UART) += sdio_uart.o
mmc_core-$(CONFIG_MMC_CRYPTO) += crypto.o
+19 -17
View File
@@ -344,7 +344,7 @@ struct ptp_ocp_signal {
};
struct ptp_ocp_serial_port {
int line;
struct uart_8250_port *uport;
int baud;
};
@@ -2629,7 +2629,7 @@ out:
return err;
}
static int
static struct uart_8250_port *
ptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r)
{
struct pci_dev *pdev = bp->pdev;
@@ -2657,9 +2657,11 @@ ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r)
struct ptp_ocp_serial_port *p = (struct ptp_ocp_serial_port *)r->extra;
struct ptp_ocp_serial_port port = {};
port.line = ptp_ocp_serial_line(bp, r);
if (port.line < 0)
return port.line;
struct uart_8250_port *uport = ptp_ocp_serial_line(bp, r);
if (IS_ERR(uport))
return PTR_ERR(uport);
port.uport = uport;
if (p)
port.baud = p->baud;
@@ -3804,7 +3806,7 @@ ptp_ocp_tty_show(struct device *dev, struct device_attribute *attr, char *buf)
* as a device path (e.g., "/dev/ttyS4"), and adding a newline would
* break those applications. Do not add a newline to this output.
*/
return sysfs_emit(buf, "ttyS%d", bp->port[(uintptr_t)ea->var].line);
return sysfs_emit(buf, "ttyS%d", bp->port[(uintptr_t)ea->var].uport->port.line);
}
static umode_t
@@ -3821,7 +3823,7 @@ ptp_ocp_timecard_tty_is_visible(struct kobject *kobj, struct attribute *attr, in
dattr = container_of(attr, struct device_attribute, attr);
ea = container_of(dattr, struct dev_ext_attribute, attr);
port = &bp->port[(uintptr_t)ea->var];
return port->line == -1 ? 0 : 0444;
return port->uport ? 0444 : 0;
}
#define EXT_TTY_ATTR_RO(_name, _val) \
@@ -5287,9 +5289,9 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp));
for (i = 0; i < __PORT_COUNT; i++) {
if (bp->port[i].line != -1)
if (bp->port[i].uport)
seq_printf(s, "%7s: /dev/ttyS%d\n", ptp_ocp_tty_port_name(i),
bp->port[i].line);
bp->port[i].uport->port.line);
}
memset(sma_val, 0xff, sizeof(sma_val));
@@ -5613,7 +5615,7 @@ ptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev)
spin_lock_init(&bp->lock);
for (i = 0; i < __PORT_COUNT; i++)
bp->port[i].line = -1;
bp->port[i].uport = NULL;
bp->pdev = pdev;
@@ -5702,10 +5704,10 @@ ptp_ocp_phc_info(struct ptp_ocp *bp)
}
static void
ptp_ocp_serial_info(struct device *dev, const char *name, int port, int baud)
ptp_ocp_serial_info(struct device *dev, const char *name, struct uart_8250_port *port, int baud)
{
if (port != -1)
dev_info(dev, "%5s: /dev/ttyS%-2d @ %6d\n", name, port, baud);
if (port)
dev_info(dev, "%5s: /dev/ttyS%-2d @ %6d\n", name, port->port.line, baud);
}
static void
@@ -5723,14 +5725,14 @@ ptp_ocp_info(struct ptp_ocp *bp)
ptp_ocp_phc_info(bp);
for (i = 0; i < __PORT_COUNT; i++) {
if (i == PORT_NMEA && bp->nmea_out && bp->port[PORT_NMEA].line != -1) {
if (i == PORT_NMEA && bp->nmea_out && bp->port[PORT_NMEA].uport) {
bp->port[PORT_NMEA].baud = -1;
reg = ioread32(&bp->nmea_out->uart_baud);
if (reg < ARRAY_SIZE(nmea_baud))
bp->port[PORT_NMEA].baud = nmea_baud[reg];
}
ptp_ocp_serial_info(dev, ptp_ocp_tty_port_name(i), bp->port[i].line,
ptp_ocp_serial_info(dev, ptp_ocp_tty_port_name(i), bp->port[i].uport,
bp->port[i].baud);
}
}
@@ -5778,8 +5780,8 @@ ptp_ocp_detach(struct ptp_ocp *bp)
for (i = 0; i < 4; i++)
ptp_ocp_unregister_ext(bp->signal_out[i]);
for (i = 0; i < __PORT_COUNT; i++)
if (bp->port[i].line != -1)
serial8250_unregister_port(bp->port[i].line);
if (bp->port[i].uport)
serial8250_unregister_port(bp->port[i].uport);
platform_device_unregister(bp->spi_flash);
platform_device_unregister(bp->i2c_ctrl);
if (bp->i2c_clk)
-10
View File
@@ -208,16 +208,6 @@ config SERIAL_NONSTANDARD
Most people can say N here.
config MOXA_INTELLIO
tristate "Moxa Intellio support"
depends on SERIAL_NONSTANDARD && PCI
select FW_LOADER
help
Say Y here if you have a Moxa Intellio multiport serial card.
To compile this driver as a module, choose M here: the
module will be called moxa.
config MOXA_SMARTIO
tristate "Moxa SmartIO support v. 2.0"
depends on SERIAL_NONSTANDARD && PCI && HAS_IOPORT
-1
View File
@@ -17,7 +17,6 @@ obj-$(CONFIG_SERIAL_DEV_BUS) += serdev/
# tty drivers
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
obj-$(CONFIG_NOZOMI) += nozomi.o
obj-$(CONFIG_NULL_TTY) += ttynull.o
+8 -22
View File
@@ -29,6 +29,9 @@ static DEFINE_SPINLOCK(dcc_lock);
static DEFINE_KFIFO(inbuf, u8, DCC_INBUF_SIZE);
static DEFINE_KFIFO(outbuf, u8, DCC_OUTBUF_SIZE);
/* Cached result of hvc_dcc_check() on core 0 */
static bool dcc_core0_available;
static void dcc_uart_console_putchar(struct uart_port *port, u8 ch)
{
while (__dcc_getstatus() & DCC_STATUS_TX)
@@ -90,36 +93,18 @@ static ssize_t hvc_dcc_get_chars(uint32_t vt, u8 *buf, size_t count)
}
/*
* Check if the DCC is enabled. If CONFIG_HVC_DCC_SERIALIZE_SMP is enabled,
* then we assume then this function will be called first on core0. That way,
* dcc_core0_available will be true only if it's available on core0.
* Check if the DCC is enabled. This function will be called once on core 0.
*/
static bool hvc_dcc_check(void)
{
unsigned long time = jiffies + (HZ / 10);
static bool dcc_core0_available;
/*
* If we're not on core 0, but we previously confirmed that DCC is
* active, then just return true.
*/
int cpu = get_cpu();
if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP) && cpu && dcc_core0_available) {
put_cpu();
return true;
}
put_cpu();
/* Write a test character to check if it is handled */
__dcc_putchar('\n');
while (time_is_after_jiffies(time)) {
if (!(__dcc_getstatus() & DCC_STATUS_TX)) {
dcc_core0_available = true;
if (!(__dcc_getstatus() & DCC_STATUS_TX))
return true;
}
}
return false;
@@ -265,7 +250,8 @@ static int __init hvc_dcc_console_init(void)
{
int ret;
if (!hvc_dcc_check())
dcc_core0_available = hvc_dcc_check();
if (!dcc_core0_available)
return -ENODEV;
/* Returns -1 if error */
@@ -279,7 +265,7 @@ static int __init hvc_dcc_init(void)
{
struct hvc_struct *p;
if (!hvc_dcc_check())
if (!dcc_core0_available)
return -ENODEV;
if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP)) {
+7 -4
View File
@@ -13,7 +13,6 @@
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/export.h>
#include <linux/interrupt.h>
@@ -157,8 +156,9 @@ static int hvc_opal_probe(struct platform_device *dev)
struct hvc_struct *hp;
struct hvc_opal_priv *pv;
hv_protocol_t proto;
unsigned int termno, irq, boot = 0;
unsigned int termno, boot = 0;
const __be32 *reg;
int irq;
if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) {
proto = HV_PROTOCOL_RAW;
@@ -176,6 +176,10 @@ static int hvc_opal_probe(struct platform_device *dev)
reg = of_get_property(dev->dev.of_node, "reg", NULL);
termno = reg ? be32_to_cpup(reg) : 0;
irq = platform_get_irq_optional(dev, 0);
if (irq == -EPROBE_DEFER)
return irq;
/* Is it our boot one ? */
if (hvc_opal_privs[termno] == &hvc_opal_boot_priv) {
pv = hvc_opal_privs[termno];
@@ -209,8 +213,7 @@ static int hvc_opal_probe(struct platform_device *dev)
dev->dev.of_node,
boot ? " (boot console)" : "");
irq = irq_of_parse_and_map(dev->dev.of_node, 0);
if (!irq) {
if (irq < 0) {
pr_info("hvc%d: No interrupts property, using OPAL event\n",
termno);
irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT));
+3 -3
View File
@@ -1470,7 +1470,7 @@ static int hvcs_initialize(void)
goto register_fail;
}
hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL);
hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!hvcs_pi_buff) {
rc = -ENOMEM;
goto buff_alloc_fail;
@@ -1486,7 +1486,7 @@ static int hvcs_initialize(void)
return 0;
kthread_fail:
free_page((unsigned long)hvcs_pi_buff);
kfree(hvcs_pi_buff);
buff_alloc_fail:
tty_unregister_driver(hvcs_tty_driver);
register_fail:
@@ -1528,7 +1528,7 @@ static void __exit hvcs_module_exit(void)
kthread_stop(hvcs_task);
spin_lock(&hvcs_pi_lock);
free_page((unsigned long)hvcs_pi_buff);
kfree(hvcs_pi_buff);
hvcs_pi_buff = NULL;
spin_unlock(&hvcs_pi_lock);
-2136
View File
File diff suppressed because it is too large. Load diff
+1 -4
View File
@@ -138,10 +138,7 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg)
if (get_user(val, arg))
return -EFAULT;
if (val)
set_bit(TTY_PTY_LOCK, &tty->flags);
else
clear_bit(TTY_PTY_LOCK, &tty->flags);
assign_bit(TTY_PTY_LOCK, &tty->flags, val);
return 0;
}
+2
View File
@@ -137,6 +137,7 @@ err_close:
err_unlock:
tty_unlock(tty);
tty_release_struct(tty, serport->tty_idx);
serport->tty = NULL;
return ret;
}
@@ -154,6 +155,7 @@ static void ttyport_close(struct serdev_controller *ctrl)
tty_unlock(tty);
tty_release_struct(tty, serport->tty_idx);
serport->tty = NULL;
}
static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed)
+16 -1
View File
@@ -73,6 +73,12 @@ struct serial8250_config {
unsigned int flags;
};
enum uart_port_type {
/* Internal 8250 only */
UART_PORT_AIROHA = 124,
UART_PORT_AIROHA_HS = 125,
};
#define UART_CAP_FIFO BIT(8) /* UART has FIFO */
#define UART_CAP_EFR BIT(9) /* UART has EFR */
#define UART_CAP_SLEEP BIT(10) /* UART has IER sleep */
@@ -180,6 +186,7 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
unsigned int count);
void serial8250_wait_for_xmitr(struct uart_8250_port *up, int bits);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
@@ -316,6 +323,14 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { }
#endif
#ifdef CONFIG_SERIAL_8250_HUB6
int serial8250_hub6_init(void);
void serial8250_hub6_exit(void);
#else
static inline int serial8250_hub6_init(void) { return 0; }
static inline void serial8250_hub6_exit(void) { }
#endif
#ifdef CONFIG_SERIAL_8250_RSA
void univ8250_rsa_support(struct uart_ops *ops, const struct uart_ops *core_ops);
void rsa_enable(struct uart_8250_port *up);
@@ -336,7 +351,7 @@ int fintek_8250_probe(struct uart_8250_port *uart);
static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; }
#endif
#if IS_REACHABLE(CONFIG_SERIAL_8250_HUB6)
#if IS_ENABLED(CONFIG_SERIAL_8250_HUB6)
bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2);
#else
static inline bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2)
+3 -2
View File
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
@@ -31,7 +32,7 @@ struct serial_card_type {
struct serial_card_info {
unsigned int num_ports;
int ports[MAX_PORTS];
struct uart_8250_port *ports[MAX_PORTS];
void __iomem *vaddr;
};
@@ -85,7 +86,7 @@ static void serial_card_remove(struct expansion_card *ec)
ecard_set_drvdata(ec, NULL);
for (i = 0; i < info->num_ports; i++)
if (info->ports[i] > 0)
if (!IS_ERR_OR_NULL(info->ports[i]))
serial8250_unregister_port(info->ports[i]);
kfree(info);
+178
View File
@@ -0,0 +1,178 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Airoha UART driver
*
* Copyright (c) 2025 Genexis Sweden AB
* Author: Benjamin Larsson <benjamin.larsson@genexis.eu>
* Christian Marangi <ansuelsmth@gmail.com>
*/
#include <linux/array_size.h>
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/types.h>
#include <linux/units.h>
#include "8250.h"
#define UART_AIROHA_XINCLKDR 10
#define UART_AIROHA_XYD 11
#define UART_AIROHA_XYD_X GENMASK(31, 16)
#define UART_AIROHA_XYD_Y GENMASK(15, 0)
#define UART_BRD_20M 0x0001
#define XINDIV_CLOCK (20 * HZ_PER_MHZ)
#define XYD_Y 65000
static const unsigned int airoha_clk_divs[] = { 2, 4, 10 };
static unsigned int airoha_get_divisor(struct uart_port *port,
unsigned int baud,
unsigned int *frac)
{
/* Hardware always uses BRDIV = 1. */
*frac = 0;
return UART_BRD_20M;
}
/*
* Airoha UART baud rate calculation logic
*
* crystal_clock = 20 MHz (fixed frequency)
* xindiv_clock = crystal_clock / clock_div
* (x/y) = XYD, 32 bit register with 16 bits of x and then 16 bits of y
* clock_div = XINCLK_DIVCNT (default set to 10 (0x4)),
* - 3 bit register [ 1, 2, 4, 8, 10, 12, 16, 20 ]
*
* baud_rate = ((xindiv_clock) * (x/y)) / ([BRDH,BRDL] * 16)
*
* Selecting divider needs to fulfill
* 1.8432 MHz <= xindiv_clk <= APB clock / 2
* The clocks are unknown but a divider of value 1 did not result in a valid
* waveform.
*
* XYD_y seems to need to be larger then XYD_x for proper waveform generation.
* Setting [BRDH,BRDL] to [0,1] and XYD_y to 65000 gives even values
* for usual baud rates.
*/
static void airoha_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
struct uart_8250_port *up = up_to_u8250p(port);
u32 xindiv_clk;
u64 xyd_x, nom;
int div_bit;
/* Set baud rate calculation defaults (BRDIV [BRDH,BRDL] to 1) */
serial8250_do_set_divisor(port, baud, UART_BRD_20M);
/*
* Calculate XYD_x and XINCLKDR register by searching
* through a table of crystal_clock divisors.
*/
nom = (u64)baud * XYD_Y;
for (div_bit = ARRAY_SIZE(airoha_clk_divs) - 1; div_bit >= 0; div_bit--) {
unsigned int div = airoha_clk_divs[div_bit];
xindiv_clk = XINDIV_CLOCK / div;
xyd_x = div_u64(nom * 16, xindiv_clk);
/* For the HSUART xyd_x needs to be scaled by a factor of 2 */
if (port->type == UART_PORT_AIROHA_HS)
xyd_x /= 2;
if (xyd_x < XYD_Y)
break;
}
/* Couldn't find a valid xyd_x */
if (div_bit < 0) {
dev_err(port->dev, "failed to find suitable clock divisor for baud %u\n",
baud);
return;
}
serial_port_out(port, UART_AIROHA_XINCLKDR, BIT(div_bit));
serial_port_out(port, UART_AIROHA_XYD,
FIELD_PREP(UART_AIROHA_XYD_X, xyd_x) |
FIELD_PREP(UART_AIROHA_XYD_Y, XYD_Y));
/* Restore normal register access. */
serial_port_out(port, UART_LCR, up->lcr);
}
static int airoha_8250_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = { };
struct device *dev = &pdev->dev;
struct resource *res;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return dev_err_probe(dev, -EINVAL, "invalid address\n");
uart.port.dev = dev;
if (device_is_compatible(dev, "airoha,an7581-hsuart"))
uart.port.type = UART_PORT_AIROHA_HS;
else
uart.port.type = UART_PORT_AIROHA;
uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
UPF_FIXED_TYPE | UPF_IOREMAP;
uart.port.set_divisor = airoha_set_divisor;
uart.port.get_divisor = airoha_get_divisor;
uart.port.mapbase = res->start;
uart.port.mapsize = resource_size(res);
ret = uart_read_and_validate_port_properties(&uart.port);
if (ret)
return ret;
struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
if (IS_ERR(uport))
return PTR_ERR(uport);
platform_set_drvdata(pdev, uport);
return 0;
}
static void airoha_8250_remove(struct platform_device *ofdev)
{
struct uart_8250_port *uport = platform_get_drvdata(ofdev);
serial8250_unregister_port(uport);
}
static const struct of_device_id airoha_8250_dt_ids[] = {
{ .compatible = "airoha,en7523-uart" },
{ .compatible = "airoha,an7581-hsuart" },
{ }
};
MODULE_DEVICE_TABLE(of, airoha_8250_dt_ids);
static struct platform_driver airoha_8250_driver = {
.driver = {
.name = "8250_airoha",
.of_match_table = airoha_8250_dt_ids,
},
.probe = airoha_8250_probe,
.remove = airoha_8250_remove,
};
module_platform_driver(airoha_8250_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Airoha UART driver");
MODULE_AUTHOR("Benjamin Larsson <benjamin.larsson@genexis.eu>");
MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+7 -6
View File
@@ -6,6 +6,7 @@
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -34,7 +35,6 @@
struct aspeed_vuart {
struct device *dev;
int line;
struct timer_list unthrottle_timer;
struct uart_8250_port *port;
};
@@ -484,12 +484,13 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
if (of_property_read_bool(np, "auto-flow-control"))
port.capabilities |= UART_CAP_AFE;
rc = serial8250_register_8250_port(&port);
if (rc < 0)
struct uart_8250_port *uport = serial8250_register_8250_port(&port);
if (IS_ERR(uport)) {
rc = PTR_ERR(uport);
goto err_sysfs_remove;
}
vuart->line = rc;
vuart->port = serial8250_get_port(vuart->line);
vuart->port = uport;
rc = of_parse_phandle_with_fixed_args(
np, "aspeed,sirq-polarity-sense", 2, 0,
@@ -553,7 +554,7 @@ static void aspeed_vuart_remove(struct platform_device *pdev)
timer_delete_sync(&vuart->unthrottle_timer);
aspeed_vuart_set_enabled(vuart, false);
serial8250_unregister_port(vuart->line);
serial8250_unregister_port(vuart->port);
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
}
+173 -14
View File
@@ -7,18 +7,20 @@
* Based on 8250_lpc18xx.c:
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
*
* The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
* take advantage of it yet. When adding support, be sure not to enable it
* simultaneously to rs485.
* The bcm2835aux's RTS/CTS auto flow-control is enabled for ports declaring
* the "uart-has-rtscts" property, but never simultaneously to rs485, which
* repurposes RTS as the transceiver direction control.
*/
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/tty.h>
#include "8250.h"
@@ -34,18 +36,170 @@
#define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */
#define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */
/*
* Set auto RTS to de-assert with 4 FIFO slots left (RTS4).
*
* The RTSINV/CTSINV bits select the auto flow assert level, which out of
* reset is active-high. Set them to get the conventional active-low RTS/CTS.
*/
#define BCM2835_AUX_UART_CNTL_AUTORTS_MASK \
(BCM2835_AUX_UART_CNTL_AUTORTS | BCM2835_AUX_UART_CNTL_RTS4 | \
BCM2835_AUX_UART_CNTL_RTSINV)
#define BCM2835_AUX_UART_CNTL_AUTOCTS_MASK \
(BCM2835_AUX_UART_CNTL_AUTOCTS | BCM2835_AUX_UART_CNTL_CTSINV)
/**
* struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
* @clk: clock producer of the port's uartclk
* @line: index of the port's serial8250_ports[] entry
* @uport: the underlying uart_8250_port
* @cntl: cached copy of CNTL register
*/
struct bcm2835aux_data {
struct clk *clk;
int line;
struct uart_8250_port *uport;
u32 cntl;
};
static bool bcm2835aux_tty_throttled(struct uart_port *port)
{
if (!port->state)
return false;
scoped_guard(tty_port_tty, &port->state->port)
return tty_throttled(scoped_tty());
return false;
}
/* Program the CNTL auto flow bits from port->status and mctrl */
static void bcm2835aux_update_flow(struct uart_port *port, unsigned int mctrl)
{
struct bcm2835aux_data *data = dev_get_drvdata(port->dev);
struct uart_8250_port *up = up_to_u8250p(port);
data->cntl &= ~(BCM2835_AUX_UART_CNTL_AUTORTS_MASK |
BCM2835_AUX_UART_CNTL_AUTOCTS_MASK);
if ((port->status & UPSTAT_AUTORTS) && (mctrl & TIOCM_RTS))
data->cntl |= BCM2835_AUX_UART_CNTL_AUTORTS_MASK;
if (port->status & UPSTAT_AUTOCTS)
data->cntl |= BCM2835_AUX_UART_CNTL_AUTOCTS_MASK;
serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
}
static void bcm2835aux_enable_rx_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
}
static void bcm2835aux_set_autoflow(struct uart_port *port, tcflag_t cflag,
bool rs485_enabled)
{
bool was_enabled = port->status & UPSTAT_AUTORTS;
bool enable;
/*
* rs485 uses RTS as the transceiver direction control, which is
* mutually exclusive with the auto flow-control of the pin.
*/
enable = (cflag & CRTSCTS) && (port->flags & UPF_HARD_FLOW) &&
!rs485_enabled;
if (enable) {
port->status |= UPSTAT_AUTORTS | UPSTAT_AUTOCTS;
/* Restore the throttle state lost in startup/resume/rs485 paths */
if (bcm2835aux_tty_throttled(port)) {
/* let the FIFO fill up and de-assert RTS in hardware */
port->ops->stop_rx(port);
/* reclaim an RTS lowered by software flow control */
if ((cflag & CBAUD) != B0)
port->mctrl |= TIOCM_RTS;
}
} else {
port->status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
/* unthrottle() will no longer be called after leaving auto-RTS mode */
if (was_enabled)
bcm2835aux_enable_rx_irq(port);
}
bcm2835aux_update_flow(port, port->mctrl);
}
static void bcm2835aux_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
serial8250_do_set_mctrl(port, mctrl);
bcm2835aux_update_flow(port, mctrl);
}
static void bcm2835aux_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
bool hw_flow = (port->flags & UPF_HARD_FLOW) &&
!(port->rs485.flags & SER_RS485_ENABLED);
/*
* Strip CRTSCTS when the hardware auto flow-control cannot be
* used, as the serial core's software CTS fallback cannot work
* without a modem status interrupt. A CTS GPIO provides one.
*/
if (!hw_flow && !mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_CTS))
termios->c_cflag &= ~CRTSCTS;
serial8250_do_set_termios(port, termios, old);
guard(uart_port_lock_irqsave)(port);
bcm2835aux_set_autoflow(port, termios->c_cflag,
port->rs485.flags & SER_RS485_ENABLED);
}
static void bcm2835aux_throttle(struct uart_port *port)
{
guard(uart_port_lock_irqsave)(port);
port->ops->stop_rx(port);
}
static void bcm2835aux_unthrottle(struct uart_port *port)
{
guard(uart_port_lock_irqsave)(port);
bcm2835aux_enable_rx_irq(port);
}
static int bcm2835aux_rs485_config(struct uart_port *port,
struct ktermios *termios,
struct serial_rs485 *rs485)
{
tcflag_t cflag = termios ? termios->c_cflag : 0;
bool rs485_enabled;
int ret;
ret = serial8250_em485_config(port, termios, rs485);
if (ret)
return ret;
rs485_enabled = rs485->flags & SER_RS485_ENABLED;
if (!rs485_enabled) {
struct bcm2835aux_data *data = dev_get_drvdata(port->dev);
data->cntl |= BCM2835_AUX_UART_CNTL_RXEN;
}
/*
* termios is NULL when rs485 is set up from firmware properties at
* port registration, before the port has been opened.
*/
bcm2835aux_set_autoflow(port, cflag, rs485_enabled);
return 0;
}
static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up, bool toggle_ier)
{
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
@@ -99,7 +253,11 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
up.port.dev = &pdev->dev;
up.port.type = PORT_16550;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_IOREMAP;
up.port.rs485_config = serial8250_em485_config;
up.port.set_termios = bcm2835aux_set_termios;
up.port.set_mctrl = bcm2835aux_set_mctrl;
up.port.throttle = bcm2835aux_throttle;
up.port.unthrottle = bcm2835aux_unthrottle;
up.port.rs485_config = bcm2835aux_rs485_config;
up.port.rs485_supported = serial8250_em485_supported;
up.rs485_start_tx = bcm2835aux_rs485_start_tx;
up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
@@ -134,6 +292,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
ret = uart_read_port_properties(&up.port);
if (ret)
goto rm_swnode;
if (device_property_read_bool(&pdev->dev, "uart-has-rtscts"))
up.port.flags |= UPF_HARD_FLOW;
up.port.regshift = 2;
up.port.fifosize = 8;
@@ -157,12 +317,12 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
up.port.uartclk *= 2;
/* register the port */
ret = serial8250_register_8250_port(&up);
if (ret < 0) {
data->uport = serial8250_register_8250_port(&up);
if (IS_ERR(data->uport)) {
ret = PTR_ERR(data->uport);
dev_err_probe(&pdev->dev, ret, "unable to register 8250 port\n");
goto dis_clk;
}
data->line = ret;
return 0;
@@ -177,7 +337,7 @@ static void bcm2835aux_serial_remove(struct platform_device *pdev)
{
struct bcm2835aux_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(data->uport);
clk_disable_unprepare(data->clk);
device_remove_software_node(&pdev->dev);
}
@@ -217,12 +377,11 @@ MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
static bool bcm2835aux_can_disable_clock(struct device *dev)
{
struct bcm2835aux_data *data = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(data->line);
if (device_may_wakeup(dev))
return false;
if (uart_console(&up->port) && !console_suspend_enabled)
if (uart_console(&data->uport->port) && !console_suspend_enabled)
return false;
return true;
@@ -232,7 +391,7 @@ static int bcm2835aux_suspend(struct device *dev)
{
struct bcm2835aux_data *data = dev_get_drvdata(dev);
serial8250_suspend_port(data->line);
serial8250_suspend_port(data->uport);
if (!bcm2835aux_can_disable_clock(dev))
return 0;
@@ -252,7 +411,7 @@ static int bcm2835aux_resume(struct device *dev)
return ret;
}
serial8250_resume_port(data->line);
serial8250_resume_port(data->uport);
return 0;
}
+15 -18
View File
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/tty.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -204,13 +205,12 @@ static const u32 brcmstb_rate_table_7278[] = {
};
struct brcmuart_priv {
int line;
struct clk *baud_mux_clk;
unsigned long default_mux_rate;
u32 real_rates[ARRAY_SIZE(brcmstb_rate_table)];
const u32 *rate_table;
ktime_t char_wait;
struct uart_port *up;
struct uart_8250_port *uport;
struct hrtimer hrt;
bool shutdown;
bool dma_enabled;
@@ -839,8 +839,8 @@ static int brcmuart_handle_irq(struct uart_port *p)
static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t)
{
struct brcmuart_priv *priv = container_of(t, struct brcmuart_priv, hrt);
struct uart_port *p = priv->up;
struct uart_8250_port *up = up_to_u8250p(p);
struct uart_8250_port *up = priv->uport;
struct uart_port *p = &up->port;
unsigned int status;
unsigned long flags;
@@ -953,7 +953,6 @@ static int brcmuart_probe(struct platform_device *pdev)
{
struct resource *regs;
const struct of_device_id *of_id = NULL;
struct uart_8250_port *new_port;
struct device *dev = &pdev->dev;
struct brcmuart_priv *priv;
struct clk *baud_mux_clk;
@@ -1083,14 +1082,12 @@ static int brcmuart_probe(struct platform_device *pdev)
}
}
ret = serial8250_register_8250_port(&up);
if (ret < 0) {
priv->uport = serial8250_register_8250_port(&up);
if (IS_ERR(priv->uport)) {
ret = PTR_ERR(priv->uport);
dev_err_probe(dev, ret, "unable to register 8250 port\n");
goto err;
}
priv->line = ret;
new_port = serial8250_get_port(ret);
priv->up = &new_port->port;
if (priv->dma_enabled) {
dma_irq = platform_get_irq_byname(pdev, "dma");
if (dma_irq < 0) {
@@ -1098,7 +1095,7 @@ static int brcmuart_probe(struct platform_device *pdev)
goto err1;
}
ret = devm_request_irq(dev, dma_irq, brcmuart_isr,
IRQF_SHARED, "uart DMA irq", &new_port->port);
IRQF_SHARED, "uart DMA irq", &priv->uport->port);
if (ret)
goto err1;
}
@@ -1107,7 +1104,7 @@ static int brcmuart_probe(struct platform_device *pdev)
return 0;
err1:
serial8250_unregister_port(priv->line);
serial8250_unregister_port(priv->uport);
err:
brcmuart_free_bufs(dev, priv);
release_dma:
@@ -1121,7 +1118,7 @@ static void brcmuart_remove(struct platform_device *pdev)
struct brcmuart_priv *priv = platform_get_drvdata(pdev);
debugfs_remove_recursive(priv->debugfs_dir);
serial8250_unregister_port(priv->line);
serial8250_unregister_port(priv->uport);
hrtimer_cancel(&priv->hrt);
brcmuart_free_bufs(&pdev->dev, priv);
if (priv->dma_enabled)
@@ -1131,7 +1128,7 @@ static void brcmuart_remove(struct platform_device *pdev)
static int __maybe_unused brcmuart_suspend(struct device *dev)
{
struct brcmuart_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
struct uart_port *port = &up->port;
unsigned long flags;
@@ -1144,7 +1141,7 @@ static int __maybe_unused brcmuart_suspend(struct device *dev)
port->mctrl &= ~TIOCM_RTS;
uart_port_unlock_irqrestore(port, flags);
serial8250_suspend_port(priv->line);
serial8250_suspend_port(up);
clk_disable_unprepare(priv->baud_mux_clk);
return 0;
@@ -1153,7 +1150,7 @@ static int __maybe_unused brcmuart_suspend(struct device *dev)
static int __maybe_unused brcmuart_resume(struct device *dev)
{
struct brcmuart_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
struct uart_port *port = &up->port;
unsigned long flags;
int ret;
@@ -1175,9 +1172,9 @@ static int __maybe_unused brcmuart_resume(struct device *dev)
return(-EBUSY);
}
brcmuart_init_dma_hardware(priv);
start_rx_dma(serial8250_get_port(priv->line));
start_rx_dma(up);
}
serial8250_resume_port(priv->line);
serial8250_resume_port(up);
if (priv->saved_mctrl & TIOCM_RTS) {
/* Restore RTS */
+88 -65
View File
@@ -16,6 +16,7 @@
#include <linux/hashtable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/err.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
@@ -333,7 +334,6 @@ struct uart_8250_port *serial8250_get_port(int line)
{
return &serial8250_ports[line];
}
EXPORT_SYMBOL_GPL(serial8250_get_port);
static inline void serial8250_apply_quirks(struct uart_8250_port *up)
{
@@ -600,13 +600,12 @@ int __init early_serial_setup(struct uart_port *port)
/**
* serial8250_suspend_port - suspend one serial port
* @line: serial line number
* @up: serial port
*
* Suspend one serial port.
*/
void serial8250_suspend_port(int line)
void serial8250_suspend_port(struct uart_8250_port *up)
{
struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
if (uart_console(port)) {
@@ -630,13 +629,12 @@ EXPORT_SYMBOL(serial8250_suspend_port);
/**
* serial8250_resume_port - resume one serial port
* @line: serial line number
* @up: serial port
*
* Resume one serial port.
*/
void serial8250_resume_port(int line)
void serial8250_resume_port(struct uart_8250_port *up)
{
struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
up->canary = 0;
@@ -673,6 +671,29 @@ EXPORT_SYMBOL(serial8250_resume_port);
*/
static DEFINE_MUTEX(serial_mutex);
/**
* serial8250_match_port - are the two ports equivalent?
* @port1: first port
* @port2: second port
*
* This utility function can be used to determine whether two uart_port
* structures describe the same port.
*/
static bool serial8250_match_port(const struct uart_port *port1,
const struct uart_port *port2)
{
if (port1->iotype != port2->iotype)
return false;
else if (port1->iotype == UPIO_PORT)
return port1->iobase == port2->iobase;
else if (port1->iotype == UPIO_HUB6)
return hub6_match_port(port1, port2);
else if (uart_iotype_mmio(port1->iotype))
return port1->mapbase == port2->mapbase;
else
return false;
}
static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_port *port)
{
int i;
@@ -681,7 +702,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_
* First, find a port entry which matches.
*/
for (i = 0; i < nr_uarts; i++)
if (uart_match_port(&serial8250_ports[i].port, port))
if (serial8250_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
/* try line number first if still available */
@@ -720,46 +741,12 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
serial_out(up, UART_IER, up->ier);
}
/**
* serial8250_register_8250_port - register a serial port
* @up: serial port template
*
* Configure the serial port specified by the request. If the
* port exists and is in use, it is hung up and unregistered
* first.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int serial8250_register_8250_port(const struct uart_8250_port *up)
static int __serial8250_register_8250_port(struct uart_8250_port *uart,
const struct uart_8250_port *up)
{
struct uart_8250_port *uart;
bool cons_flow;
int ret;
if (up->port.uartclk == 0)
return -EINVAL;
guard(mutex)(&serial_mutex);
uart = serial8250_find_match_or_unused(&up->port);
if (!uart) {
/*
* If the port is past the initial isa ports, initialize a new
* port and increment nr_uarts accordingly.
*/
uart = serial8250_setup_port(nr_uarts);
if (!uart)
return -ENOSPC;
nr_uarts++;
}
/* Check if it is CIR already. We check this below again, see there why. */
if (uart->port.type == PORT_8250_CIR)
return -ENODEV;
/* Preserve specified console flow control. */
cons_flow = uart_cons_flow_enabled(&uart->port);
@@ -803,7 +790,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->port.dev = up->port.dev;
ret = uart_get_rs485_mode(&uart->port);
if (ret)
goto err;
return ret;
}
if (up->port.flags & UPF_FIXED_TYPE)
@@ -815,12 +802,10 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
*/
if (uart->port.dev && !has_acpi_companion(uart->port.dev)) {
struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0);
if (IS_ERR(gpios)) {
ret = PTR_ERR(gpios);
goto err;
} else {
uart->gpios = gpios;
}
if (IS_ERR(gpios))
return PTR_ERR(gpios);
uart->gpios = gpios;
}
serial8250_set_defaults(uart);
@@ -877,17 +862,13 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
ret = uart_add_one_port(&serial8250_reg,
&uart->port);
if (ret)
goto err;
ret = uart->port.line;
return ret;
} else {
dev_info(uart->port.dev,
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
uart->port.iobase,
(unsigned long long)uart->port.mapbase,
uart->port.irq);
ret = 0;
}
if (!uart->lsr_save_mask)
@@ -903,25 +884,67 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->overrun_backoff_time_ms = 0;
}
return ret;
return 0;
}
err:
uart->port.dev = NULL;
return ret;
/**
* serial8250_register_8250_port - register a serial port
* @up: serial port template
*
* Configure the serial port specified by the request. If the
* port exists and is in use, it is hung up and unregistered
* first.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
struct uart_8250_port *serial8250_register_8250_port(const struct uart_8250_port *up)
{
struct uart_8250_port *uart;
int ret;
if (up->port.uartclk == 0)
return ERR_PTR(-EINVAL);
guard(mutex)(&serial_mutex);
uart = serial8250_find_match_or_unused(&up->port);
if (!uart) {
/*
* If the port is past the initial isa ports, initialize a new
* port and increment nr_uarts accordingly.
*/
uart = serial8250_setup_port(nr_uarts);
if (!uart)
return ERR_PTR(-ENOSPC);
nr_uarts++;
}
/* Check if it is CIR already. We check this below again, see there why. */
if (uart->port.type == PORT_8250_CIR)
return ERR_PTR(-ENODEV);
ret = __serial8250_register_8250_port(uart, up);
if (ret < 0) {
uart->port.dev = NULL;
return ERR_PTR(ret);
}
return uart;
}
EXPORT_SYMBOL(serial8250_register_8250_port);
/**
* serial8250_unregister_port - remove a 16x50 serial port at runtime
* @line: serial line number
* @uart: port
*
* Remove one serial port. This may not be called from interrupt
* context. We hand the port back to the our control.
*/
void serial8250_unregister_port(int line)
void serial8250_unregister_port(struct uart_8250_port *uart)
{
struct uart_8250_port *uart = &serial8250_ports[line];
guard(mutex)(&serial_mutex);
if (uart->em485) {
@@ -934,7 +957,7 @@ void serial8250_unregister_port(int line)
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
uart->port.type = PORT_UNKNOWN;
uart->port.dev = &serial8250_isa_devs->dev;
uart->port.port_id = line;
uart->port.port_id = uart->port.line;
uart->capabilities = 0;
serial8250_init_port(uart);
serial8250_apply_quirks(uart);
+7 -15
View File
@@ -12,6 +12,7 @@
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/dfl.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/module.h>
@@ -27,10 +28,6 @@
#define DFHv1_PARAM_REG_LAYOUT_WIDTH GENMASK_ULL(63, 32)
#define DFHv1_PARAM_REG_LAYOUT_SHIFT GENMASK_ULL(31, 0)
struct dfl_uart {
int line;
};
static int dfh_get_u64_param_val(struct dfl_device *dfl_dev, int param_id, u64 *pval)
{
size_t psize;
@@ -109,7 +106,6 @@ static int dfl_uart_probe(struct dfl_device *dfl_dev)
{
struct device *dev = &dfl_dev->dev;
struct uart_8250_port uart = { };
struct dfl_uart *dfluart;
int ret;
uart.port.flags = UPF_IOREMAP;
@@ -123,24 +119,20 @@ static int dfl_uart_probe(struct dfl_device *dfl_dev)
if (dfl_dev->num_irqs == 1)
uart.port.irq = dfl_dev->irqs[0];
dfluart = devm_kzalloc(dev, sizeof(*dfluart), GFP_KERNEL);
if (!dfluart)
return -ENOMEM;
struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
if (IS_ERR(uport))
return dev_err_probe(dev, PTR_ERR(uport), "unable to register 8250 port.\n");
dfluart->line = serial8250_register_8250_port(&uart);
if (dfluart->line < 0)
return dev_err_probe(dev, dfluart->line, "unable to register 8250 port.\n");
dev_set_drvdata(dev, dfluart);
dev_set_drvdata(dev, uport);
return 0;
}
static void dfl_uart_remove(struct dfl_device *dfl_dev)
{
struct dfl_uart *dfluart = dev_get_drvdata(&dfl_dev->dev);
struct uart_8250_port *uport = dev_get_drvdata(&dfl_dev->dev);
serial8250_unregister_port(dfluart->line);
serial8250_unregister_port(uport);
}
#define FME_FEATURE_ID_UART 0x24
+16 -13
View File
@@ -19,7 +19,7 @@ static void __dma_tx_complete(void *param)
unsigned long flags;
int ret;
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
uart_port_lock_irqsave(&p->port, &flags);
@@ -136,7 +136,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
dma->tx_cookie = dmaengine_submit(desc);
dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
dma_sync_single_for_device(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_async_issue_pending(dma->txchan);
@@ -223,6 +223,8 @@ EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
int serial8250_request_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
struct device *rx_dev;
struct device *tx_dev;
phys_addr_t rx_dma_addr = dma->rx_dma_addr ?
dma->rx_dma_addr : p->port.mapbase;
phys_addr_t tx_dma_addr = dma->tx_dma_addr ?
@@ -282,24 +284,25 @@ int serial8250_request_dma(struct uart_8250_port *p)
dmaengine_slave_config(dma->txchan, &dma->txconf);
rx_dev = dmaengine_get_dma_device(dma->rxchan);
tx_dev = dmaengine_get_dma_device(dma->txchan);
/* RX buffer */
if (!dma->rx_size)
dma->rx_size = PAGE_SIZE;
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
&dma->rx_addr, GFP_KERNEL);
dma->rx_buf = dma_alloc_coherent(rx_dev, dma->rx_size, &dma->rx_addr,
GFP_KERNEL);
if (!dma->rx_buf) {
ret = -ENOMEM;
goto err;
}
/* TX buffer */
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
p->port.state->port.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->tx_addr = dma_map_single(tx_dev, p->port.state->port.xmit_buf,
UART_XMIT_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(tx_dev, dma->tx_addr)) {
dma_free_coherent(rx_dev, dma->rx_size,
dma->rx_buf, dma->rx_addr);
ret = -ENOMEM;
goto err;
@@ -326,14 +329,14 @@ void serial8250_release_dma(struct uart_8250_port *p)
/* Release RX resources */
dmaengine_terminate_sync(dma->rxchan);
dma->rx_running = 0;
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
dma->rx_addr);
dma_free_coherent(dmaengine_get_dma_device(dma->rxchan), dma->rx_size,
dma->rx_buf, dma->rx_addr);
dma_release_channel(dma->rxchan);
dma->rxchan = NULL;
/* Release TX resources */
dmaengine_terminate_sync(dma->txchan);
dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
dma_unmap_single(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->txchan);
dma->txchan = NULL;
+24 -8
View File
@@ -15,6 +15,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/lockdep.h>
#include <linux/module.h>
@@ -51,6 +52,7 @@
#define DW_UART_QUIRK_APMC0D08 BIT(4)
#define DW_UART_QUIRK_CPR_VALUE BIT(5)
#define DW_UART_QUIRK_IER_KICK BIT(6)
#define DW_UART_QUIRK_SKIP_EMPTY_FIFO_READ BIT(7)
/*
* Number of consecutive IIR_NO_INT interrupts required to trigger interrupt
@@ -436,11 +438,18 @@ static int dw8250_handle_irq(struct uart_port *p)
* This problem has only been observed so far when not in DMA mode
* so we limit the workaround only to non-DMA mode.
*/
if (!up->dma && rx_timeout) {
if (!(quirks & DW_UART_QUIRK_SKIP_EMPTY_FIFO_READ) && !up->dma && rx_timeout) {
status = serial_lsr_in(up);
/*
* Do the bogus read from Shadow RBR (SRBR) if provided.
* Both RBR and SRBR are supported ways to workaround
* this problem. But read RBR can cause hardware error
* (PSLVERR) if hardware choose to implement in this way
* (implement REG_TIMEOUT_WIDTH to 0), whereas SRBR won't.
*/
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
serial_port_in(p, UART_RX);
serial_port_in(p, d->data.srbr);
}
/* Manually stop the Rx DMA transfer when acting as flow controller */
@@ -766,9 +775,9 @@ static int dw8250_probe(struct platform_device *pdev)
up->dma = &data->data.dma;
}
data->data.line = serial8250_register_8250_port(up);
if (data->data.line < 0)
return data->data.line;
data->data.uport = serial8250_register_8250_port(up);
if (IS_ERR(data->data.uport))
return PTR_ERR(data->data.uport);
platform_set_drvdata(pdev, data);
@@ -784,7 +793,7 @@ static void dw8250_remove(struct platform_device *pdev)
pm_runtime_get_sync(dev);
serial8250_unregister_port(data->data.line);
serial8250_unregister_port(data->data.uport);
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
@@ -794,7 +803,7 @@ static int dw8250_suspend(struct device *dev)
{
struct dw8250_data *data = dev_get_drvdata(dev);
serial8250_suspend_port(data->data.line);
serial8250_suspend_port(data->data.uport);
return 0;
}
@@ -803,7 +812,7 @@ static int dw8250_resume(struct device *dev)
{
struct dw8250_data *data = dev_get_drvdata(dev);
serial8250_resume_port(data->data.line);
serial8250_resume_port(data->data.uport);
return 0;
}
@@ -888,6 +897,11 @@ static const struct dw8250_platform_data dw8250_ultrarisc_dp1000_data = {
.quirks = DW_UART_QUIRK_CPR_VALUE,
};
static const struct dw8250_platform_data dw8250_tda54 = {
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_SKIP_EMPTY_FIFO_READ,
};
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
@@ -895,6 +909,7 @@ static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
{ .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data },
{ .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data },
{ .compatible = "ti,tda54-uart", .data = &dw8250_tda54 },
{ .compatible = "ultrarisc,dp1000-uart", .data = &dw8250_ultrarisc_dp1000_data },
{ /* Sentinel */ }
};
@@ -910,6 +925,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0021", (kernel_ulong_t)&dw8250_dw_apb },
{ "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
{ "APMC0D08", (kernel_ulong_t)&dw8250_apmc0d08 },
{ "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
+5
View File
@@ -247,5 +247,10 @@ void dw8250_setup_port(struct uart_port *p)
if (reg & DW_UART_CPR_SIR_MODE)
up->capabilities |= UART_CAP_IRDA;
if (reg & DW_UART_CPR_SHADOW)
pd->srbr = DW_UART_SRBR_0;
else
pd->srbr = UART_RX;
}
EXPORT_SYMBOL_GPL(dw8250_setup_port);
+6 -1
View File
@@ -13,6 +13,7 @@
#include "8250.h"
/* Offsets for the DesignWare specific registers */
#define DW_UART_SRBR_0 0x0c /* Shadow Receive Buffer Register */
#define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_DMASA 0xa8 /* DMA Software Ack */
#define DW_UART_TCR 0xac /* Transceiver Control Register (RS485) */
@@ -79,7 +80,7 @@
struct dw8250_port_data {
/* Port properties */
int line;
struct uart_8250_port *uport;
/* DMA operations */
struct uart_8250_dma dma;
@@ -90,6 +91,10 @@ struct dw8250_port_data {
/* RS485 variables */
bool hw_rs485_support;
/* Register offsets */
/* Shadow RBR (if not defined RBR will be used) */
int srbr;
};
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old);
+1
View File
@@ -175,6 +175,7 @@ EARLYCON_DECLARE(uart8250, early_serial8250_setup);
EARLYCON_DECLARE(uart, early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "marvell,armada-38x-uart", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
+8 -18
View File
@@ -6,6 +6,7 @@
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
@@ -28,10 +29,6 @@
#define UART_HCR0_EM_SW_RESET BIT(7) /* SW Reset */
struct serial8250_em_priv {
int line;
};
static void serial8250_em_serial_out_helper(struct uart_port *p, int offset,
int value)
{
@@ -151,12 +148,11 @@ static void serial8250_em_serial_dl_write(struct uart_8250_port *up, u32 value)
static int serial8250_em_probe(struct platform_device *pdev)
{
struct serial8250_em_priv *priv;
struct device *dev = &pdev->dev;
struct uart_8250_port up;
struct resource *regs;
struct clk *sclk;
int irq, ret;
int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -166,10 +162,6 @@ static int serial8250_em_probe(struct platform_device *pdev)
if (!regs)
return dev_err_probe(dev, -EINVAL, "missing registers\n");
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
sclk = devm_clk_get_enabled(dev, "sclk");
if (IS_ERR(sclk))
return dev_err_probe(dev, PTR_ERR(sclk), "unable to get clock\n");
@@ -180,7 +172,6 @@ static int serial8250_em_probe(struct platform_device *pdev)
up.port.type = PORT_16750;
up.port.flags = UPF_FIXED_PORT | UPF_IOREMAP | UPF_FIXED_TYPE;
up.port.dev = dev;
up.port.private_data = priv;
up.port.uartclk = clk_get_rate(sclk);
@@ -190,20 +181,19 @@ static int serial8250_em_probe(struct platform_device *pdev)
up.dl_read = serial8250_em_serial_dl_read;
up.dl_write = serial8250_em_serial_dl_write;
ret = serial8250_register_8250_port(&up);
if (ret < 0)
return dev_err_probe(dev, ret, "unable to register 8250 port\n");
struct uart_8250_port *uport = serial8250_register_8250_port(&up);
if (IS_ERR(uport))
return dev_err_probe(dev, PTR_ERR(uport), "unable to register 8250 port\n");
priv->line = ret;
platform_set_drvdata(pdev, priv);
platform_set_drvdata(pdev, uport);
return 0;
}
static void serial8250_em_remove(struct platform_device *pdev)
{
struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
struct uart_8250_port *up = platform_get_drvdata(pdev);
serial8250_unregister_port(priv->line);
serial8250_unregister_port(up);
}
static const struct of_device_id serial8250_em_dt_ids[] = {
+29 -30
View File
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/eeprom_93cx6.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/math.h>
@@ -231,8 +232,9 @@ struct exar8250_platform {
int (*rs485_config)(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
const struct serial_rs485 *rs485_supported;
int (*register_gpio)(struct pci_dev *pcidev, struct uart_8250_port *port);
void (*unregister_gpio)(struct uart_8250_port *port);
int (*register_gpio)(struct exar8250 *priv, struct pci_dev *pcidev,
struct uart_8250_port *port);
void (*unregister_gpio)(struct exar8250 *priv);
};
/**
@@ -256,7 +258,8 @@ struct exar8250 {
struct exar8250_board *board;
struct eeprom_93cx6 eeprom;
void __iomem *virt;
int line[];
struct platform_device *gpio;
struct uart_8250_port *uport[];
};
static inline void exar_write_reg(struct exar8250 *priv,
@@ -799,7 +802,7 @@ static int cti_rs485_config_mpio_tristate(struct uart_port *port,
struct ktermios *termios,
struct serial_rs485 *rs485)
{
struct exar8250 *priv = (struct exar8250 *)port->private_data;
struct exar8250 *priv = port->private_data;
int ret;
ret = generic_rs485_config(port, termios, rs485);
@@ -837,7 +840,7 @@ static int cti_port_setup_common(struct exar8250 *priv,
if (ret)
return ret;
port->port.private_data = (void *)priv;
port->port.private_data = priv;
port->port.pm = exar_pm;
port->port.shutdown = exar_shutdown;
@@ -1167,22 +1170,21 @@ static const struct software_node exar_gpio_node = {
.properties = exar_gpio_properties,
};
static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port)
static int xr17v35x_register_gpio(struct exar8250 *priv, struct pci_dev *pcidev,
struct uart_8250_port *port)
{
if (pcidev->vendor == PCI_VENDOR_ID_EXAR)
port->port.private_data =
__xr17v35x_register_gpio(pcidev, &exar_gpio_node);
priv->gpio = __xr17v35x_register_gpio(pcidev, &exar_gpio_node);
return 0;
}
static void xr17v35x_unregister_gpio(struct uart_8250_port *port)
static void xr17v35x_unregister_gpio(struct exar8250 *priv)
{
if (!port->port.private_data)
return;
__xr17v35x_unregister_gpio(port->port.private_data);
port->port.private_data = NULL;
if (priv->gpio) {
__xr17v35x_unregister_gpio(priv->gpio);
priv->gpio = NULL;
}
}
static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termios,
@@ -1279,8 +1281,9 @@ static const struct software_node iot2040_gpio_node = {
.properties = iot2040_gpio_properties,
};
static int iot2040_register_gpio(struct pci_dev *pcidev,
struct uart_8250_port *port)
static int iot2040_register_gpio(struct exar8250 *priv,
struct pci_dev *pcidev,
struct uart_8250_port *port)
{
u8 __iomem *p = port->port.membase;
@@ -1289,8 +1292,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev,
writeb(IOT2040_UARTS_ENABLE, p + UART_EXAR_MPIOLVL_15_8);
writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8);
port->port.private_data =
__xr17v35x_register_gpio(pcidev, &iot2040_gpio_node);
priv->gpio = __xr17v35x_register_gpio(pcidev, &iot2040_gpio_node);
return 0;
}
@@ -1367,7 +1369,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
/* Setup Multipurpose Input/Output pins. */
setup_gpio(pcidev, p);
ret = platform->register_gpio(pcidev, port);
ret = platform->register_gpio(priv, pcidev, port);
}
return ret;
@@ -1377,9 +1379,8 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev)
{
const struct exar8250_platform *platform = exar_get_platform();
struct exar8250 *priv = pci_get_drvdata(pcidev);
struct uart_8250_port *port = serial8250_get_port(priv->line[0]);
platform->unregister_gpio(port);
platform->unregister_gpio(priv);
}
static inline void exar_misc_clear(struct exar8250 *priv)
@@ -1460,7 +1461,7 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
if (nr_ports == 0)
return dev_err_probe(&pcidev->dev, -ENODEV, "failed to get number of ports\n");
priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
priv = devm_kzalloc(&pcidev->dev, struct_size(priv, uport, nr_ports), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1500,9 +1501,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
dev_dbg(&pcidev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype);
priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
dev_err_probe(&pcidev->dev, priv->line[i],
priv->uport[i] = serial8250_register_8250_port(&uart);
if (IS_ERR(priv->uport[i])) {
dev_err_probe(&pcidev->dev, PTR_ERR(priv->uport[i]),
"Couldn't register serial port %lx, type %d, irq %d\n",
uart.port.iobase, uart.port.iotype, uart.port.irq);
break;
@@ -1519,7 +1520,7 @@ static void exar_pci_remove(struct pci_dev *pcidev)
unsigned int i;
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
serial8250_unregister_port(priv->uport[i]);
/* Ensure that every init quirk is properly torn down */
if (priv->board->exit)
@@ -1532,8 +1533,7 @@ static int exar_suspend(struct device *dev)
unsigned int i;
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]);
serial8250_suspend_port(priv->uport[i]);
return 0;
}
@@ -1546,8 +1546,7 @@ static int exar_resume(struct device *dev)
exar_misc_clear(priv);
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_resume_port(priv->line[i]);
serial8250_resume_port(priv->uport[i]);
return 0;
}
+8 -16
View File
@@ -18,6 +18,7 @@
*/
#include <linux/acpi.h>
#include <linux/err.h>
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>
@@ -99,14 +100,9 @@ int fsl8250_handle_irq(struct uart_port *port)
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
#ifdef CONFIG_ACPI
struct fsl8250_data {
int line;
};
static int fsl8250_acpi_probe(struct platform_device *pdev)
{
struct fsl8250_data *data;
struct uart_8250_port port8250;
struct uart_8250_port *uport, port8250;
struct device *dev = &pdev->dev;
struct resource *regs;
@@ -148,23 +144,19 @@ static int fsl8250_acpi_probe(struct platform_device *pdev)
if (!port8250.port.membase)
return -ENOMEM;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
uport = serial8250_register_8250_port(&port8250);
if (IS_ERR(uport))
return PTR_ERR(uport);
data->line = serial8250_register_8250_port(&port8250);
if (data->line < 0)
return data->line;
platform_set_drvdata(pdev, data);
platform_set_drvdata(pdev, uport);
return 0;
}
static void fsl8250_acpi_remove(struct platform_device *pdev)
{
struct fsl8250_data *data = platform_get_drvdata(pdev);
struct uart_8250_port *uport = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(uport);
}
static const struct acpi_device_id fsl_8250_acpi_id[] = {
+11 -16
View File
@@ -7,6 +7,7 @@
* by Kars de Jong <jongk@linux-m68k.org>, May 2004.
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -27,7 +28,7 @@
#ifdef CONFIG_HPAPCI
struct hp300_port {
struct hp300_port *next; /* next port */
int line; /* line (tty) number */
struct uart_8250_port *uport;
};
static struct hp300_port *hp300_ports;
@@ -157,8 +158,7 @@ int __init hp300_setup_serial_console(void)
static int hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent)
{
struct uart_8250_port uart;
int line;
struct uart_8250_port *uport, uart;
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (hp300_uart_scode == d->scode) {
@@ -177,9 +177,8 @@ static int hpdca_init_one(struct dio_dev *d,
uart.port.membase = (char *)(uart.port.mapbase + DIO_VIRADDRBASE);
uart.port.regshift = 1;
uart.port.dev = &d->dev;
line = serial8250_register_8250_port(&uart);
if (line < 0) {
uport = serial8250_register_8250_port(&uart);
if (IS_ERR(uport)) {
dev_notice(&d->dev,
"8250_hp300: register_serial() DCA scode %d irq %d failed\n",
d->scode, uart.port.irq);
@@ -188,7 +187,7 @@ static int hpdca_init_one(struct dio_dev *d,
/* Enable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
dio_set_drvdata(d, (void *)line);
dio_set_drvdata(d, uport);
/* Reset the DCA */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
@@ -204,7 +203,6 @@ static int __init hp300_8250_init(void)
{
static int called;
#ifdef CONFIG_HPAPCI
int line;
unsigned long base;
struct uart_8250_port uart;
struct hp300_port *port;
@@ -259,9 +257,8 @@ static int __init hp300_8250_init(void)
uart.port.membase = (char *)(base + DIO_VIRADDRBASE);
uart.port.regshift = 2;
line = serial8250_register_8250_port(&uart);
if (line < 0) {
port->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(port->uport)) {
dev_notice(uart.port.dev,
"8250_hp300: register_serial() APCI %d irq %d failed\n",
i, uart.port.irq);
@@ -269,7 +266,6 @@ static int __init hp300_8250_init(void)
continue;
}
port->line = line;
port->next = hp300_ports;
hp300_ports = port;
@@ -287,14 +283,13 @@ static int __init hp300_8250_init(void)
#ifdef CONFIG_HPDCA
static void hpdca_remove_one(struct dio_dev *d)
{
int line;
struct uart_8250_port *uport = dio_get_drvdata(d);
line = (int) dio_get_drvdata(d);
if (d->resource.start) {
/* Disable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
}
serial8250_unregister_port(line);
serial8250_unregister_port(uport);
}
#endif
@@ -304,7 +299,7 @@ static void __exit hp300_8250_exit(void)
struct hp300_port *port, *to_free;
for (port = hp300_ports; port; ) {
serial8250_unregister_port(port->line);
serial8250_unregister_port(port->uport);
to_free = port;
port = port->next;
kfree(to_free);
+5 -6
View File
@@ -49,13 +49,12 @@ bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port
}
EXPORT_SYMBOL_GPL(hub6_match_port);
static int __init hub6_init(void)
int __init serial8250_hub6_init(void)
{
return platform_device_register(&hub6_device);
}
module_init(hub6_init);
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
MODULE_LICENSE("GPL");
void serial8250_hub6_exit(void)
{
platform_device_unregister(&hub6_device);
}
+6 -5
View File
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/libfdt.h>
#include <linux/module.h>
@@ -29,7 +30,7 @@ struct ingenic_uart_config {
struct ingenic_uart_data {
struct clk *clk_module;
struct clk *clk_baud;
int line;
struct uart_8250_port *uport;
};
static const struct of_device_id of_match[];
@@ -297,9 +298,9 @@ static int ingenic_uart_probe(struct platform_device *pdev)
}
uart.port.uartclk = clk_get_rate(data->clk_baud);
data->line = serial8250_register_8250_port(&uart);
if (data->line < 0) {
err = data->line;
data->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(data->uport)) {
err = PTR_ERR(data->uport);
goto out_disable_baudclk;
}
@@ -318,7 +319,7 @@ static void ingenic_uart_remove(struct platform_device *pdev)
{
struct ingenic_uart_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(data->uport);
clk_disable_unprepare(data->clk_module);
clk_disable_unprepare(data->clk_baud);
}
+9 -17
View File
@@ -9,6 +9,7 @@
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/platform_device.h>
@@ -17,10 +18,6 @@
#define IOC3_UARTCLK (22000000 / 3)
struct ioc3_8250_data {
int line;
};
static u32 ioc3_serial_in(struct uart_port *p, unsigned int offset)
{
return readb(p->membase + (offset ^ 3));
@@ -33,20 +30,15 @@ static void ioc3_serial_out(struct uart_port *p, unsigned int offset, u32 value)
static int serial8250_ioc3_probe(struct platform_device *pdev)
{
struct ioc3_8250_data *data;
struct uart_8250_port up;
struct uart_8250_port *uport, up;
struct resource *r;
void __iomem *membase;
int irq, line;
int irq;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
membase = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (!membase)
return -ENOMEM;
@@ -67,19 +59,19 @@ static int serial8250_ioc3_probe(struct platform_device *pdev)
up.port.mapbase = r->start;
up.port.serial_in = ioc3_serial_in;
up.port.serial_out = ioc3_serial_out;
line = serial8250_register_8250_port(&up);
if (line < 0)
return line;
uport = serial8250_register_8250_port(&up);
if (IS_ERR(uport))
return PTR_ERR(uport);
platform_set_drvdata(pdev, data);
platform_set_drvdata(pdev, uport);
return 0;
}
static void serial8250_ioc3_remove(struct platform_device *pdev)
{
struct ioc3_8250_data *data = platform_get_drvdata(pdev);
struct uart_8250_port *uport = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(uport);
}
static struct platform_driver serial8250_ioc3_driver = {
+5 -8
View File
@@ -62,7 +62,7 @@ enum kuart_mode {
struct kuart {
struct keba_uart_auxdev *auxdev;
void __iomem *base;
unsigned int line;
struct uart_8250_port *uport;
unsigned int flags;
u8 capability;
@@ -174,7 +174,6 @@ static int kuart_probe(struct auxiliary_device *auxdev,
struct uart_8250_port uart = {};
struct resource res;
struct kuart *kuart;
int retval;
kuart = devm_kzalloc(dev, sizeof(*kuart), GFP_KERNEL);
if (!kuart)
@@ -250,12 +249,10 @@ static int kuart_probe(struct auxiliary_device *auxdev,
}
}
retval = serial8250_register_8250_port(&uart);
if (retval < 0)
return dev_err_probe(&auxdev->dev, retval,
kuart->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(kuart->uport))
return dev_err_probe(&auxdev->dev, PTR_ERR(kuart->uport),
"UART registration failed!\n");
kuart->line = retval;
return 0;
}
@@ -266,7 +263,7 @@ static void kuart_remove(struct auxiliary_device *auxdev)
if (kuart->flags & KUART_USE_CAPABILITY)
kuart_set_phy_mode(kuart, KUART_MODE_NONE);
serial8250_unregister_port(kuart->line);
serial8250_unregister_port(kuart->uport);
}
static const struct auxiliary_device_id kuart_devtype_aux[] = {
+10 -10
View File
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/property.h>
#include <linux/math.h>
@@ -43,7 +44,7 @@ static const struct loongson_uart_ddata ls2k1500_uart_data = {
};
struct loongson_uart_priv {
int line;
struct uart_8250_port *uport;
struct clk *clk;
struct resource *res;
struct reset_control *rst;
@@ -160,13 +161,12 @@ static int loongson_uart_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = serial8250_register_8250_port(&uart);
if (ret < 0) {
priv->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(priv->uport)) {
reset_control_assert(priv->rst);
return ret;
return PTR_ERR(priv->uport);
}
priv->line = ret;
platform_set_drvdata(pdev, priv);
return 0;
@@ -176,16 +176,16 @@ static void loongson_uart_remove(struct platform_device *pdev)
{
struct loongson_uart_priv *priv = platform_get_drvdata(pdev);
serial8250_unregister_port(priv->line);
serial8250_unregister_port(priv->uport);
reset_control_assert(priv->rst);
}
static int loongson_uart_suspend(struct device *dev)
{
struct loongson_uart_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
serial8250_suspend_port(priv->line);
serial8250_suspend_port(up);
if (!uart_console(&up->port) || console_suspend_enabled)
clk_disable_unprepare(priv->clk);
@@ -196,7 +196,7 @@ static int loongson_uart_suspend(struct device *dev)
static int loongson_uart_resume(struct device *dev)
{
struct loongson_uart_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
int ret;
if (!uart_console(&up->port) || console_suspend_enabled) {
@@ -205,7 +205,7 @@ static int loongson_uart_resume(struct device *dev)
return ret;
}
serial8250_resume_port(priv->line);
serial8250_resume_port(up);
return 0;
}
+6 -5
View File
@@ -10,6 +10,7 @@
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -29,7 +30,7 @@ struct lpc18xx_uart_data {
struct uart_8250_dma dma;
struct clk *clk_uart;
struct clk *clk_reg;
int line;
struct uart_8250_port *uport;
};
static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios,
@@ -160,13 +161,13 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
uart.dma->rxconf.src_maxburst = 1;
uart.dma->txconf.dst_maxburst = 1;
ret = serial8250_register_8250_port(&uart);
if (ret < 0) {
data->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(data->uport)) {
ret = PTR_ERR(data->uport);
dev_err(&pdev->dev, "unable to register 8250 port\n");
goto dis_uart_clk;
}
data->line = ret;
platform_set_drvdata(pdev, data);
return 0;
@@ -182,7 +183,7 @@ static void lpc18xx_serial_remove(struct platform_device *pdev)
{
struct lpc18xx_uart_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(data->uport);
clk_disable_unprepare(data->clk_uart);
clk_disable_unprepare(data->clk_reg);
}
+9 -8
View File
@@ -7,6 +7,7 @@
*/
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/rational.h>
@@ -183,9 +184,8 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
static void ehl_serial_exit(struct lpss8250 *lpss)
{
struct uart_8250_port *up = serial8250_get_port(lpss->data.line);
up->dma = NULL;
if (lpss->data.uport)
lpss->data.uport->dma = NULL;
}
#ifdef CONFIG_SERIAL_8250_DMA
@@ -356,11 +356,12 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err_exit;
ret = serial8250_register_8250_port(&uart);
if (ret < 0)
struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
if (IS_ERR(uport)) {
ret = PTR_ERR(uport);
goto err_exit;
lpss->data.line = ret;
}
lpss->data.uport = uport;
pci_set_drvdata(pdev, lpss);
return 0;
@@ -375,7 +376,7 @@ static void lpss8250_remove(struct pci_dev *pdev)
{
struct lpss8250 *lpss = pci_get_drvdata(pdev);
serial8250_unregister_port(lpss->data.line);
serial8250_unregister_port(lpss->data.uport);
lpss->board->exit(lpss);
pci_free_irq_vectors(pdev);
+7 -7
View File
@@ -2,6 +2,7 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mcb.h>
#include <linux/serial.h>
@@ -42,7 +43,7 @@
struct serial_8250_men_mcb_data {
int num_ports;
int line[MEN_Z025_MAX_UARTS];
struct uart_8250_port *uport[MEN_Z025_MAX_UARTS];
unsigned int offset[MEN_Z025_MAX_UARTS];
};
@@ -218,14 +219,13 @@ static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
+ data->offset[i];
/* ok, register the port */
res = serial8250_register_8250_port(&uart);
if (res < 0) {
data->uport[i] = serial8250_register_8250_port(&uart);
if (IS_ERR(data->uport[i])) {
dev_err(&mdev->dev, "unable to register UART port\n");
return res;
return PTR_ERR(data->uport[i]);
}
data->line[i] = res;
dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data->line[i]);
dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data->uport[i]->port.line);
}
return 0;
@@ -240,7 +240,7 @@ static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
return;
for (i = 0; i < data->num_ports; i++)
serial8250_unregister_port(data->line[i]);
serial8250_unregister_port(data->uport[i]);
}
static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
+19 -10
View File
@@ -7,6 +7,8 @@
*/
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/rational.h>
@@ -40,7 +42,7 @@ struct mid8250_board {
};
struct mid8250 {
int line;
struct uart_8250_port *uport;
int dma_index;
struct pci_dev *dma_dev;
struct uart_8250_dma dma;
@@ -209,6 +211,7 @@ static void mid8250_set_termios(struct uart_port *p, struct ktermios *termios,
const struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
struct uart_8250_port *up = up_to_u8250p(p);
struct mid8250 *mid = p->private_data;
unsigned short ps = 16;
unsigned long fuart = baud * ps;
@@ -231,11 +234,16 @@ static void mid8250_set_termios(struct uart_port *p, struct ktermios *termios,
}
rational_best_approximation(fuart, mid->board->freq, w, w, &mul, &div);
p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */
writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
writel(div, p->membase + INTEL_MID_UART_DIV);
scoped_guard(spinlock_irq, &p->lock) {
p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */
serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */
writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */
writel(div, p->membase + INTEL_MID_UART_DIV);
}
serial8250_do_set_termios(p, termios, old);
}
@@ -328,11 +336,11 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err;
ret = serial8250_register_8250_port(&uart);
if (ret < 0)
mid->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(mid->uport)) {
ret = PTR_ERR(mid->uport);
goto err;
mid->line = ret;
}
pci_set_drvdata(pdev, mid);
return 0;
@@ -347,7 +355,7 @@ static void mid8250_remove(struct pci_dev *pdev)
{
struct mid8250 *mid = pci_get_drvdata(pdev);
serial8250_unregister_port(mid->line);
serial8250_unregister_port(mid->uport);
if (mid->board->exit)
mid->board->exit(mid);
@@ -408,3 +416,4 @@ module_pci_driver(mid8250_pci_driver);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel MID UART driver");
MODULE_IMPORT_NS("SERIAL_8250");
+10 -9
View File
@@ -6,6 +6,7 @@
* Author: Matthias Brugger <matthias.bgg@gmail.com>
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -68,7 +69,7 @@ enum dma_rx_status {
#endif
struct mtk8250_data {
int line;
struct uart_8250_port *uport;
unsigned int rx_pos;
unsigned int clk_count;
struct clk *uart_clk;
@@ -431,7 +432,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
{
struct mtk8250_data *data = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(data->line);
struct uart_8250_port *up = data->uport;
/* wait until UART in idle status */
while
@@ -587,9 +588,9 @@ static int mtk8250_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
data->line = serial8250_register_8250_port(&uart);
if (data->line < 0)
return data->line;
data->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(data->uport))
return PTR_ERR(data->uport);
data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1);
@@ -605,7 +606,7 @@ static void mtk8250_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(data->uport);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
@@ -617,7 +618,7 @@ static int __maybe_unused mtk8250_suspend(struct device *dev)
int irq = data->rx_wakeup_irq;
int err;
serial8250_suspend_port(data->line);
serial8250_suspend_port(data->uport);
pinctrl_pm_select_sleep_state(dev);
if (irq >= 0) {
@@ -627,7 +628,7 @@ static int __maybe_unused mtk8250_suspend(struct device *dev)
"failed to enable irq wake on IRQ %d: %d\n",
irq, err);
pinctrl_pm_select_default_state(dev);
serial8250_resume_port(data->line);
serial8250_resume_port(data->uport);
return err;
}
}
@@ -644,7 +645,7 @@ static int __maybe_unused mtk8250_resume(struct device *dev)
disable_irq_wake(irq);
pinctrl_pm_select_default_state(dev);
serial8250_resume_port(data->line);
serial8250_resume_port(data->uport);
return 0;
}
+24 -19
View File
@@ -9,6 +9,7 @@
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
@@ -102,13 +103,14 @@
#define MOXA_ODD_RS_MASK GENMASK(7, 4)
struct mxpcie8250_port {
int line;
struct uart_8250_port *uport;
u8 rx_trig_level;
};
struct mxpcie8250 {
unsigned int supp_rs;
unsigned int num_ports;
unsigned int nr; /* ports actually registered */
void __iomem *bar1_base; /* UART registers (MMIO) */
void __iomem *bar2_base; /* UIR / GPIO / CPLD (IO) */
struct mxpcie8250_port port[] __counted_by(num_ports);
@@ -217,8 +219,6 @@ static void mxpcie8250_set_termios(struct uart_port *port,
const struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_struct *tty = port->state->port.tty;
unsigned int cflag = tty->termios.c_cflag;
u8 efr, val;
serial8250_do_set_termios(port, new, old);
@@ -228,23 +228,25 @@ static void mxpcie8250_set_termios(struct uart_port *port,
efr = serial_in(up, MOXA_PUART_EFR);
efr &= ~(MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
if (cflag & CRTSCTS) {
if (new->c_cflag & CRTSCTS) {
efr |= (MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
up->port.status |= (UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
}
/* Set on-chip software flow control character */
serial_out(up, MOXA_PUART_XON1, START_CHAR(tty));
serial_out(up, MOXA_PUART_XON2, START_CHAR(tty));
serial_out(up, MOXA_PUART_XOFF1, STOP_CHAR(tty));
serial_out(up, MOXA_PUART_XOFF2, STOP_CHAR(tty));
serial_out(up, MOXA_PUART_XON1, new->c_cc[VSTART]);
serial_out(up, MOXA_PUART_XON2, new->c_cc[VSTART]);
serial_out(up, MOXA_PUART_XOFF1, new->c_cc[VSTOP]);
serial_out(up, MOXA_PUART_XOFF2, new->c_cc[VSTOP]);
val = I_IXON(tty) ? MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_RX_FLOW_DISABLED;
val = (new->c_iflag & IXON) ? MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 :
MOXA_PUART_EFR_RX_FLOW_DISABLED;
FIELD_MODIFY(MOXA_PUART_EFR_RX_FLOW_MASK, &efr, val);
val = I_IXOFF(tty) ? MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_TX_FLOW_DISABLED;
val = (new->c_iflag & IXOFF) ? MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 :
MOXA_PUART_EFR_TX_FLOW_DISABLED;
FIELD_MODIFY(MOXA_PUART_EFR_TX_FLOW_MASK, &efr, val);
if (I_IXOFF(tty))
if (new->c_iflag & IXOFF)
up->port.status |= UPSTAT_AUTOXOFF;
serial_out(up, MOXA_PUART_EFR, efr);
@@ -517,6 +519,7 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
struct mxpcie8250 *priv;
unsigned short device = pdev->device;
unsigned int num_ports;
unsigned int i;
int ret;
ret = pcim_enable_device(pdev);
@@ -542,6 +545,8 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
mxpcie8250_init_board(pdev, priv);
pci_set_drvdata(pdev, priv);
up.port.dev = dev;
up.port.irq = pdev->irq;
up.port.uartclk = MOXA_PUART_BASE_BAUD * 16;
@@ -562,23 +567,23 @@ static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
up.port.handle_irq = mxpcie8250_handle_irq;
up.port.break_ctl = mxpcie8250_break_ctl;
for (unsigned int i = 0; i < num_ports; i++) {
for (i = 0; i < num_ports; i++) {
mxpcie8250_setup_port(pdev, priv, &up, i);
dev_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n",
up.port.iobase, up.port.irq, up.port.iotype);
priv->port[i].line = serial8250_register_8250_port(&up);
if (priv->port[i].line < 0) {
priv->port[i].uport = serial8250_register_8250_port(&up);
if (IS_ERR(priv->port[i].uport)) {
dev_err(dev,
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
"Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
up.port.iobase, up.port.irq,
up.port.iotype, priv->port[i].line);
up.port.iotype, priv->port[i].uport);
break;
}
priv->port[i].rx_trig_level = MOXA_PUART_RX_TRIG_DEFAULT;
}
pci_set_drvdata(pdev, priv);
priv->nr = i;
return 0;
}
@@ -587,8 +592,8 @@ static void mxpcie8250_remove(struct pci_dev *pdev)
{
struct mxpcie8250 *priv = pci_get_drvdata(pdev);
for (unsigned int i = 0; i < priv->num_ports; i++)
serial8250_unregister_port(priv->port[i].line);
for (unsigned int i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->port[i].uport);
}
static const struct pci_device_id mxpcie8250_pci_ids[] = {
+6 -6
View File
@@ -14,6 +14,7 @@
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -73,7 +74,7 @@ struct ni16550_device_info {
};
struct ni16550_data {
int line;
struct uart_8250_port *uport;
struct clk *clk;
};
@@ -383,10 +384,9 @@ static int ni16550_probe(struct platform_device *pdev)
ni16550_rs485_setup(&uart->port);
}
ret = serial8250_register_8250_port(uart);
if (ret < 0)
return ret;
data->line = ret;
data->uport = serial8250_register_8250_port(uart);
if (IS_ERR(data->uport))
return PTR_ERR(data->uport);
platform_set_drvdata(pdev, data);
return 0;
@@ -396,7 +396,7 @@ static void ni16550_remove(struct platform_device *pdev)
{
struct ni16550_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(data->uport);
}
/* NI 16550 RS-485 Interface */
+13 -12
View File
@@ -8,6 +8,7 @@
#include <linux/align.h>
#include <linux/bits.h>
#include <linux/console.h>
#include <linux/err.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -28,7 +29,7 @@ struct of_serial_info {
struct clk *bus_clk;
struct reset_control *rst;
int type;
int line;
struct uart_8250_port *uport;
struct notifier_block clk_notifier;
};
@@ -71,11 +72,10 @@ static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigne
void *data)
{
struct of_serial_info *info = clk_nb_to_info(nb);
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
struct clk_notifier_data *ndata = data;
if (event == POST_RATE_CHANGE) {
serial8250_update_uartclk(&port8250->port, ndata->new_rate);
serial8250_update_uartclk(&info->uport->port, ndata->new_rate);
return NOTIFY_OK;
}
@@ -292,12 +292,13 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
&port8250.overrun_backoff_time_ms) != 0)
port8250.overrun_backoff_time_ms = 0;
ret = serial8250_register_8250_port(&port8250);
if (ret < 0)
info->uport = serial8250_register_8250_port(&port8250);
if (IS_ERR(info->uport)) {
ret = PTR_ERR(info->uport);
goto err_dispose;
}
info->type = port_type;
info->line = ret;
platform_set_drvdata(ofdev, info);
if (info->clk) {
@@ -311,7 +312,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
return 0;
err_unregister:
serial8250_unregister_port(info->line);
serial8250_unregister_port(info->uport);
err_dispose:
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
@@ -330,7 +331,7 @@ static void of_platform_serial_remove(struct platform_device *ofdev)
if (info->clk)
clk_notifier_unregister(info->clk, &info->clk_notifier);
serial8250_unregister_port(info->line);
serial8250_unregister_port(info->uport);
reset_control_assert(info->rst);
pm_runtime_put_sync(&ofdev->dev);
@@ -342,10 +343,10 @@ static void of_platform_serial_remove(struct platform_device *ofdev)
static int of_serial_suspend(struct device *dev)
{
struct of_serial_info *info = dev_get_drvdata(dev);
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
struct uart_8250_port *port8250 = info->uport;
struct uart_port *port = &port8250->port;
serial8250_suspend_port(info->line);
serial8250_suspend_port(port8250);
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_put_sync(dev);
@@ -358,7 +359,7 @@ static int of_serial_suspend(struct device *dev)
static int of_serial_resume(struct device *dev)
{
struct of_serial_info *info = dev_get_drvdata(dev);
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
struct uart_8250_port *port8250 = info->uport;
struct uart_port *port = &port8250->port;
if (!uart_console(port) || console_suspend_enabled) {
@@ -367,7 +368,7 @@ static int of_serial_resume(struct device *dev)
clk_prepare_enable(info->clk);
}
serial8250_resume_port(info->line);
serial8250_resume_port(port8250);
return 0;
}
+22 -23
View File
@@ -11,6 +11,7 @@
#include <linux/atomic.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
@@ -124,7 +125,7 @@
#define UART_OMAP_TO_H 0x27
struct omap8250_priv {
void __iomem *membase;
int line;
struct uart_8250_port *uport;
u8 habit;
u8 mdr1;
u8 mdr3;
@@ -628,7 +629,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port);
static irqreturn_t omap8250_irq(int irq, void *dev_id)
{
struct omap8250_priv *priv = dev_id;
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
struct uart_port *port = &up->port;
unsigned int iir, lsr;
int ret;
@@ -711,6 +712,9 @@ static int omap_8250_startup(struct uart_port *port)
struct uart_8250_dma *dma = &priv->omap8250_dma;
int ret;
/* ISR and runtime PM need the uport; probe sets it only after registration */
priv->uport = up;
#ifdef CONFIG_PM
up->capabilities |= UART_CAP_RPM;
#endif
@@ -1076,7 +1080,7 @@ static void omap_8250_dma_tx_complete(void *param)
bool en_thri = false;
struct omap8250_priv *priv = p->port.private_data;
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
guard(uart_port_lock_irqsave)(&p->port);
@@ -1193,7 +1197,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
dma->tx_cookie = dmaengine_submit(desc);
dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
dma_sync_single_for_device(dmaengine_get_dma_device(dma->txchan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_async_issue_pending(dma->txchan);
@@ -1506,7 +1510,7 @@ static int omap8250_probe(struct platform_device *pdev)
}
priv->membase = membase;
priv->line = -ENODEV;
priv->uport = NULL;
priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
priv->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
cpu_latency_qos_add_request(&priv->pm_qos_request, priv->latency);
@@ -1587,12 +1591,13 @@ static int omap8250_probe(struct platform_device *pdev)
goto err;
}
ret = serial8250_register_8250_port(&up);
if (ret < 0) {
struct uart_8250_port *uport = serial8250_register_8250_port(&up);
if (IS_ERR(uport)) {
ret = PTR_ERR(uport);
dev_err(&pdev->dev, "unable to register 8250 port\n");
goto err;
}
priv->line = ret;
priv->uport = uport;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
@@ -1621,10 +1626,10 @@ static void omap8250_remove(struct platform_device *pdev)
if (err)
dev_err(&pdev->dev, "Failed to resume hardware\n");
up = serial8250_get_port(priv->line);
up = priv->uport;
omap_8250_shutdown(&up->port);
serial8250_unregister_port(priv->line);
priv->line = -ENODEV;
serial8250_unregister_port(up);
priv->uport = NULL;
dev_pm_clear_wake_irq(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
@@ -1656,7 +1661,7 @@ static void omap8250_complete(struct device *dev)
static int omap8250_suspend(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
int err = 0;
err = omap8250_select_wakeup_pinctrl(dev, priv);
@@ -1666,7 +1671,7 @@ static int omap8250_suspend(struct device *dev)
return err;
}
serial8250_suspend_port(priv->line);
serial8250_suspend_port(up);
err = pm_runtime_resume_and_get(dev);
if (err)
@@ -1684,7 +1689,7 @@ static int omap8250_suspend(struct device *dev)
static int omap8250_resume(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
int err;
err = pinctrl_select_default_state(dev);
@@ -1700,7 +1705,7 @@ static int omap8250_resume(struct device *dev)
return err;
}
serial8250_resume_port(priv->line);
serial8250_resume_port(up);
/* Paired with pm_runtime_resume_and_get() in omap8250_suspend() */
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -1772,10 +1777,7 @@ static int omap8250_soft_reset(struct device *dev)
static int omap8250_runtime_suspend(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = NULL;
if (priv->line >= 0)
up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
if (priv->habit & UART_ERRATA_CLOCK_DISABLE) {
int ret;
@@ -1805,15 +1807,12 @@ static int omap8250_runtime_suspend(struct device *dev)
static int omap8250_runtime_resume(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = NULL;
struct uart_8250_port *up = priv->uport;
/* Did the hardware wake to a device IO interrupt before a wakeirq? */
if (atomic_read(&priv->active))
return 0;
if (priv->line >= 0)
up = serial8250_get_port(priv->line);
if (up && omap8250_lost_context(up)) {
guard(uart_port_lock_irq)(&up->port);
omap8250_restore_regs(up);
+7 -7
View File
@@ -5,6 +5,7 @@
* (c) Copyright Matthew Wilcox <willy@debian.org> 2001-2002
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -22,9 +23,8 @@
static int __init serial_init_chip(struct parisc_device *dev)
{
struct uart_8250_port uart;
struct uart_8250_port *uport, uart;
unsigned long address;
int err;
#if defined(CONFIG_64BIT) && defined(CONFIG_IOSAPIC)
if (!dev->irq && (dev->id.sversion == 0xad))
@@ -64,13 +64,13 @@ static int __init serial_init_chip(struct parisc_device *dev)
uart.port.flags = UPF_BOOT_AUTOCONF;
uart.port.dev = &dev->dev;
err = serial8250_register_8250_port(&uart);
if (err < 0) {
uport = serial8250_register_8250_port(&uart);
if (IS_ERR(uport)) {
dev_warn(&dev->dev,
"serial8250_register_8250_port returned error %d\n",
err);
"serial8250_register_8250_port returned error %pe\n",
uport);
iounmap(uart.port.membase);
return err;
return PTR_ERR(uport);
}
return 0;
+11 -12
View File
@@ -20,6 +20,7 @@
#include <linux/8250_pci.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/err.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -116,7 +117,7 @@ struct serial_private {
unsigned int nr;
struct pci_serial_quirk *quirk;
const struct pciserial_board *board;
int line[];
struct uart_8250_port *uport[];
};
#define PCI_DEVICE_ID_HPE_PCI_SERIAL 0x37e
@@ -3894,7 +3895,7 @@ static const struct pci_device_id blacklist[] = {
{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), },
/* Moxa devices */
{ PCI_VDEVICE(MOXA, PCI_ANY_ID), REPORT_8250_CONFIG(MOXA), },
{ PCI_VDEVICE(MOXA, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(MOXA), },
/* End of the black list */
{ }
@@ -4028,7 +4029,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
nr_ports = rc;
}
priv = kzalloc_flex(*priv, line, nr_ports);
priv = kzalloc_flex(*priv, uport, nr_ports);
if (!priv) {
priv = ERR_PTR(-ENOMEM);
goto err_deinit;
@@ -4071,12 +4072,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
pci_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype);
priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
priv->uport[i] = serial8250_register_8250_port(&uart);
if (IS_ERR(priv->uport[i])) {
pci_err(dev,
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
"Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
uart.port.iobase, uart.port.irq,
uart.port.iotype, priv->line[i]);
uart.port.iotype, priv->uport[i]);
break;
}
}
@@ -4098,7 +4099,7 @@ static void pciserial_detach_ports(struct serial_private *priv)
int i;
for (i = 0; i < priv->nr; i++)
serial8250_unregister_port(priv->line[i]);
serial8250_unregister_port(priv->uport[i]);
/*
* Find the exit quirks.
@@ -4120,8 +4121,7 @@ void pciserial_suspend_ports(struct serial_private *priv)
int i;
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]);
serial8250_suspend_port(priv->uport[i]);
/*
* Ensure that every init quirk is properly torn down
@@ -4142,8 +4142,7 @@ void pciserial_resume_ports(struct serial_private *priv)
priv->quirk->init(priv->dev);
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_resume_port(priv->line[i]);
serial8250_resume_port(priv->uport[i]);
}
EXPORT_SYMBOL_GPL(pciserial_resume_ports);
+20 -21
View File
@@ -12,6 +12,7 @@
#include <linux/bits.h>
#include <linux/circ_buf.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gfp_types.h>
#include <linux/io.h>
@@ -152,7 +153,7 @@ struct pci1xxxx_8250 {
u8 dev_rev;
u8 pad[3];
void __iomem *membase;
int line[] __counted_by(nr);
struct uart_8250_port *uport[] __counted_by(nr);
};
static const struct serial_rs485 pci1xxxx_rs485_supported = {
@@ -551,9 +552,8 @@ static int pci1xxxx_handle_irq(struct uart_port *port)
return 1;
}
static bool pci1xxxx_port_suspend(int line)
static bool pci1xxxx_port_suspend(struct uart_8250_port *up)
{
struct uart_8250_port *up = serial8250_get_port(line);
struct uart_port *port = &up->port;
struct tty_port *tport = &port->state->port;
unsigned long flags;
@@ -578,9 +578,8 @@ static bool pci1xxxx_port_suspend(int line)
return ret;
}
static void pci1xxxx_port_resume(int line)
static void pci1xxxx_port_resume(struct uart_8250_port *up)
{
struct uart_8250_port *up = serial8250_get_port(line);
struct uart_port *port = &up->port;
struct tty_port *tport = &port->state->port;
unsigned long flags;
@@ -608,9 +607,9 @@ static int pci1xxxx_suspend(struct device *dev)
int i;
for (i = 0; i < priv->nr; i++) {
if (priv->line[i] >= 0) {
serial8250_suspend_port(priv->line[i]);
wakeup |= pci1xxxx_port_suspend(priv->line[i]);
if (priv->uport[i]) {
serial8250_suspend_port(priv->uport[i]);
wakeup |= pci1xxxx_port_suspend(priv->uport[i]);
}
}
@@ -661,9 +660,9 @@ static int pci1xxxx_resume(struct device *dev)
iounmap(p);
for (i = 0; i < priv->nr; i++) {
if (priv->line[i] >= 0) {
pci1xxxx_port_resume(priv->line[i]);
serial8250_resume_port(priv->line[i]);
if (priv->uport[i]) {
pci1xxxx_port_resume(priv->uport[i]);
serial8250_resume_port(priv->uport[i]);
}
}
@@ -779,7 +778,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
nr_ports = pci1xxxx_get_num_ports(pdev);
priv = devm_kzalloc(dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
priv = devm_kzalloc(dev, struct_size(priv, uport, nr_ports), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -812,8 +811,6 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
writeb(UART_PCI_CTRL_SET_MULTIPLE_MSI, priv->membase + UART_PCI_CTRL_REG);
for (i = 0; i < nr_ports; i++) {
priv->line[i] = -ENODEV;
port_idx = pci1xxxx_logical_to_physical_port_translate(subsys_dev, i);
if (num_vectors == max_vec_reqd)
@@ -827,13 +824,15 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
continue;
}
priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
struct uart_8250_port *uport = serial8250_register_8250_port(&uart);
if (IS_ERR(uport)) {
dev_warn(dev,
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype,
priv->line[i]);
"Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
uart.port.iobase, uart.port.irq, uart.port.iotype, uport);
continue;
}
priv->uport[i] = uport;
}
pci_set_drvdata(pdev, priv);
@@ -847,8 +846,8 @@ static void pci1xxxx_serial_remove(struct pci_dev *dev)
unsigned int i;
for (i = 0; i < priv->nr; i++) {
if (priv->line[i] >= 0)
serial8250_unregister_port(priv->line[i]);
if (priv->uport[i])
serial8250_unregister_port(priv->uport[i]);
}
pci_free_irq_vectors(dev);
+8 -7
View File
@@ -2,6 +2,7 @@
/* Driver for Pericom UART */
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/pci.h>
@@ -45,7 +46,7 @@
struct pericom8250 {
void __iomem *virt;
unsigned int nr;
int line[];
struct uart_8250_port *uport[];
};
static void pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
@@ -102,7 +103,7 @@ static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *i
else
nr = 1;
pericom = devm_kzalloc(&pdev->dev, struct_size(pericom, line, nr), GFP_KERNEL);
pericom = devm_kzalloc(&pdev->dev, struct_size(pericom, uport, nr), GFP_KERNEL);
if (!pericom)
return -ENOMEM;
@@ -127,12 +128,12 @@ static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *i
dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
uart.port.iobase, uart.port.irq, uart.port.iotype);
pericom->line[i] = serial8250_register_8250_port(&uart);
if (pericom->line[i] < 0) {
pericom->uport[i] = serial8250_register_8250_port(&uart);
if (IS_ERR(pericom->uport[i])) {
dev_err(&pdev->dev,
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
"Couldn't register serial port %lx, irq %d, type %d, error %pe\n",
uart.port.iobase, uart.port.irq,
uart.port.iotype, pericom->line[i]);
uart.port.iotype, pericom->uport[i]);
break;
}
}
@@ -148,7 +149,7 @@ static void pericom8250_remove(struct pci_dev *pdev)
unsigned int i;
for (i = 0; i < pericom->nr; i++)
serial8250_unregister_port(pericom->line[i]);
serial8250_unregister_port(pericom->uport[i]);
}
static const struct pci_device_id pericom8250_pci_ids[] = {
+18 -14
View File
@@ -11,6 +11,7 @@
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -110,7 +111,7 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *regs;
int ret, line;
int ret;
struct uart_8250_port *uart __free(kfree) = kzalloc_obj(*uart);
if (!uart)
@@ -146,16 +147,12 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
if (ret)
return ret;
line = serial8250_register_8250_port(uart);
if (line < 0)
return line;
return 0;
return PTR_ERR_OR_ZERO(serial8250_register_8250_port(uart));
}
static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
{
int ret, i;
int i;
struct uart_8250_port *uart __free(kfree) = kzalloc_obj(*uart);
if (!uart)
@@ -192,12 +189,12 @@ static int serial8250_probe_platform(struct platform_device *dev, struct plat_se
if (share_irqs)
uart->port.irqflags |= IRQF_SHARED;
ret = serial8250_register_8250_port(uart);
if (ret < 0) {
struct uart_8250_port *uport = serial8250_register_8250_port(uart);
if (IS_ERR(uport)) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
"(IO%lx MEM%llx IRQ%d): %pe\n", i,
p->iobase, (unsigned long long)p->mapbase,
p->irq, ret);
p->irq, uport);
}
}
return 0;
@@ -239,7 +236,7 @@ static void serial8250_remove(struct platform_device *dev)
struct uart_8250_port *up = serial8250_get_port(i);
if (up->port.dev == &dev->dev)
serial8250_unregister_port(i);
serial8250_unregister_port(up);
}
}
@@ -265,7 +262,7 @@ static int serial8250_resume(struct platform_device *dev)
struct uart_8250_port *up = serial8250_get_port(i);
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
serial8250_resume_port(i);
serial8250_resume_port(up);
}
return 0;
@@ -320,10 +317,14 @@ static int __init serial8250_init(void)
if (ret)
goto unreg_uart_drv;
ret = serial8250_hub6_init();
if (ret)
goto unreg_pnp;
serial8250_isa_devs = platform_device_alloc("serial8250", PLAT8250_DEV_LEGACY);
if (!serial8250_isa_devs) {
ret = -ENOMEM;
goto unreg_pnp;
goto unreg_hub6;
}
ret = platform_device_add(serial8250_isa_devs);
@@ -339,6 +340,8 @@ static int __init serial8250_init(void)
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
unreg_hub6:
serial8250_hub6_exit();
unreg_pnp:
serial8250_pnp_exit();
unreg_uart_drv:
@@ -366,6 +369,7 @@ static void __exit serial8250_exit(void)
platform_driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
serial8250_hub6_exit();
serial8250_pnp_exit();
#ifdef CONFIG_SPARC
+11 -12
View File
@@ -8,6 +8,7 @@
*
* Ported to the Linux PnP Layer - (C) Adam Belay.
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm.h>
@@ -436,7 +437,6 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_8250_port uart, *port;
int ret, flags = dev_id->driver_data;
long line;
if (flags & UNKNOWN_DEV) {
ret = serial_pnp_guess_board(dev);
@@ -477,39 +477,38 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
uart.port.iobase, (unsigned long long)uart.port.mapbase,
(unsigned long long)uart.port.mapsize, uart.port.irq, uart.port.iotype);
line = serial8250_register_8250_port(&uart);
if (line < 0 || (flags & CIR_PORT))
port = serial8250_register_8250_port(&uart);
if (IS_ERR(port) || (flags & CIR_PORT))
return -ENODEV;
port = serial8250_get_port(line);
if (uart_console(&port->port))
dev->capabilities |= PNP_CONSOLE;
pnp_set_drvdata(dev, (void *)line);
pnp_set_drvdata(dev, port);
return 0;
}
static void serial_pnp_remove(struct pnp_dev *dev)
{
long line = (long)pnp_get_drvdata(dev);
struct uart_8250_port *uport = pnp_get_drvdata(dev);
dev->capabilities &= ~PNP_CONSOLE;
serial8250_unregister_port(line);
serial8250_unregister_port(uport);
}
static int serial_pnp_suspend(struct device *dev)
{
long line = (long)dev_get_drvdata(dev);
struct uart_8250_port *uport = dev_get_drvdata(dev);
serial8250_suspend_port(line);
serial8250_suspend_port(uport);
return 0;
}
static int serial_pnp_resume(struct device *dev)
{
long line = (long)dev_get_drvdata(dev);
struct uart_8250_port *uport = dev_get_drvdata(dev);
serial8250_resume_port(line);
serial8250_resume_port(uport);
return 0;
}
@@ -526,7 +525,7 @@ static struct pnp_driver serial_pnp_driver = {
.id_table = pnp_dev_table,
};
int serial8250_pnp_init(void)
int __init serial8250_pnp_init(void)
{
return pnp_register_driver(&serial_pnp_driver);
}
+37 -13
View File
@@ -319,6 +319,22 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {15, 31, 63, 111},
.flags = UART_CAP_FIFO,
},
[UART_PORT_AIROHA] = {
.name = "Airoha UART",
.fifo_size = 8,
.tx_loadsz = 1,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_CLEAR_RCVR,
.rxtrig_bytes = {1, 4, 4, 4},
.flags = UART_CAP_FIFO,
},
[UART_PORT_AIROHA_HS] = {
.name = "Airoha HSUART",
.fifo_size = 128,
.tx_loadsz = 128,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | UART_FCR_CLEAR_RCVR,
.rxtrig_bytes = {1, 4},
.flags = UART_CAP_FIFO,
},
};
/* Uart divisor latch read */
@@ -526,7 +542,6 @@ void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
@@ -667,7 +682,6 @@ static void serial8250_rpm_put_tx(struct uart_8250_port *p)
rpm_active = xchg(&p->rpm_tx_active, 0);
if (!rpm_active)
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
@@ -1880,13 +1894,22 @@ EXPORT_SYMBOL_GPL(serial8250_handle_irq);
static int serial8250_default_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir;
int pm_status;
int ret;
guard(serial8250_rpm)(up);
/* if driver suspended, return, probably shared interrupt */
pm_status = pm_runtime_get_if_active(port->dev);
if (!pm_status)
return 0;
iir = serial_port_in(port, UART_IIR);
return serial8250_handle_irq(port, iir);
ret = serial8250_handle_irq(port, iir);
if (pm_status > 0)
pm_runtime_put_autosuspend(port->dev);
return ret;
}
/*
@@ -2024,7 +2047,7 @@ static bool wait_for_lsr(struct uart_8250_port *up, int bits)
}
/* Wait for transmitter and holding register to empty with timeout */
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
void serial8250_wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int tmout;
bool tx_ready;
@@ -2052,6 +2075,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
}
}
}
EXPORT_SYMBOL_NS_GPL(serial8250_wait_for_xmitr, "SERIAL_8250");
#ifdef CONFIG_CONSOLE_POLL
/*
@@ -2098,7 +2122,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
ier = serial_port_in(port, UART_IER);
__serial8250_clear_IER(up);
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
/*
* Send the character out.
*/
@@ -2108,7 +2132,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
* Finally, wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
serial_port_out(port, UART_IER, ier);
}
@@ -2223,7 +2247,7 @@ static void serial8250_THRE_test(struct uart_port *port)
* Synchronize UART_IER access against the console.
*/
scoped_guard(uart_port_lock_irqsave, port) {
wait_for_xmitr(up, UART_LSR_THRE);
serial8250_wait_for_xmitr(up, UART_LSR_THRE);
serial_port_out_sync(port, UART_IER, UART_IER_THRI);
udelay(1); /* allow THRE to set */
iir_noint1 = serial_port_in(port, UART_IIR) & UART_IIR_NO_INT;
@@ -2428,8 +2452,8 @@ void serial8250_do_shutdown(struct uart_port *port)
synchronize_irq(port->irq);
serial8250_release_dma(up);
up->dma = NULL;
if (up->dma)
serial8250_release_dma(up);
scoped_guard(uart_port_lock_irqsave, port) {
if (port->flags & UPF_FOURPORT) {
@@ -3293,7 +3317,7 @@ static void serial8250_console_wait_putchar(struct uart_port *port, unsigned cha
{
struct uart_8250_port *up = up_to_u8250p(port);
wait_for_xmitr(up, UART_LSR_THRE);
serial8250_wait_for_xmitr(up, UART_LSR_THRE);
serial8250_console_putchar(port, ch);
}
@@ -3507,7 +3531,7 @@ void serial8250_console_write(struct uart_8250_port *up,
* Finally, wait for transmitter to become empty
* and restore the IER
*/
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
serial8250_wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
if (em485) {
mdelay(port->rs485.delay_rts_after_send);
+9 -8
View File
@@ -11,6 +11,7 @@
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -26,7 +27,7 @@
#include "8250.h"
struct pxa8250_data {
int line;
struct uart_8250_port *uport;
struct clk *clk;
};
@@ -34,7 +35,7 @@ static int __maybe_unused serial_pxa_suspend(struct device *dev)
{
struct pxa8250_data *data = dev_get_drvdata(dev);
serial8250_suspend_port(data->line);
serial8250_suspend_port(data->uport);
return 0;
}
@@ -43,7 +44,7 @@ static int __maybe_unused serial_pxa_resume(struct device *dev)
{
struct pxa8250_data *data = dev_get_drvdata(dev);
serial8250_resume_port(data->line);
serial8250_resume_port(data->uport);
return 0;
}
@@ -128,11 +129,11 @@ static int serial_pxa_probe(struct platform_device *pdev)
uart.tx_loadsz = 32;
uart.dl_write = serial_pxa_dl_write;
ret = serial8250_register_8250_port(&uart);
if (ret < 0)
data->uport = serial8250_register_8250_port(&uart);
if (IS_ERR(data->uport)) {
ret = PTR_ERR(data->uport);
goto err_clk;
data->line = ret;
}
platform_set_drvdata(pdev, data);
@@ -147,7 +148,7 @@ static void serial_pxa_remove(struct platform_device *pdev)
{
struct pxa8250_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
serial8250_unregister_port(data->uport);
clk_unprepare(data->clk);
}
+11 -9
View File
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -20,7 +21,7 @@
struct tegra_uart {
struct clk *clk;
struct reset_control *rst;
int line;
struct uart_8250_port *uport;
};
static void tegra_uart_handle_break(struct uart_port *p)
@@ -103,12 +104,13 @@ static int tegra_uart_probe(struct platform_device *pdev)
if (ret)
goto err_clkdisable;
ret = serial8250_register_8250_port(&port8250);
if (ret < 0)
uart->uport = serial8250_register_8250_port(&port8250);
if (IS_ERR(uart->uport)) {
ret = PTR_ERR(uart->uport);
goto err_ctrl_assert;
}
platform_set_drvdata(pdev, uart);
uart->line = ret;
return 0;
@@ -124,7 +126,7 @@ static void tegra_uart_remove(struct platform_device *pdev)
{
struct tegra_uart *uart = platform_get_drvdata(pdev);
serial8250_unregister_port(uart->line);
serial8250_unregister_port(uart->uport);
reset_control_assert(uart->rst);
clk_disable_unprepare(uart->clk);
}
@@ -133,10 +135,10 @@ static void tegra_uart_remove(struct platform_device *pdev)
static int tegra_uart_suspend(struct device *dev)
{
struct tegra_uart *uart = dev_get_drvdata(dev);
struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
struct uart_8250_port *port8250 = uart->uport;
struct uart_port *port = &port8250->port;
serial8250_suspend_port(uart->line);
serial8250_suspend_port(port8250);
if (!uart_console(port) || console_suspend_enabled)
clk_disable_unprepare(uart->clk);
@@ -147,13 +149,13 @@ static int tegra_uart_suspend(struct device *dev)
static int tegra_uart_resume(struct device *dev)
{
struct tegra_uart *uart = dev_get_drvdata(dev);
struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
struct uart_8250_port *port8250 = uart->uport;
struct uart_port *port = &port8250->port;
if (!uart_console(port) || console_suspend_enabled)
clk_prepare_enable(uart->clk);
serial8250_resume_port(uart->line);
serial8250_resume_port(port8250);
return 0;
}
+16 -27
View File
@@ -5,6 +5,7 @@
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -31,7 +32,7 @@
#define UNIPHIER_UART_DLR (9 << (UNIPHIER_UART_REGSHIFT))
struct uniphier8250_priv {
int line;
struct uart_8250_port *uport;
struct clk *clk;
spinlock_t atomic_write_lock;
};
@@ -165,10 +166,8 @@ static int uniphier_uart_probe(struct platform_device *pdev)
int ret;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_err(dev, "failed to get memory resource\n");
return -EINVAL;
}
if (!regs)
return dev_err_probe(dev, -EINVAL, "failed to get memory resource\n");
membase = devm_ioremap(dev, regs->start, resource_size(regs));
if (!membase)
@@ -180,15 +179,10 @@ static int uniphier_uart_probe(struct platform_device *pdev)
memset(&up, 0, sizeof(up));
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
priv->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(priv->clk))
return dev_err_probe(dev, PTR_ERR(priv->clk),
"failed to get and enable clock\n");
up.port.uartclk = clk_get_rate(priv->clk);
@@ -219,13 +213,9 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.dl_read = uniphier_serial_dl_read;
up.dl_write = uniphier_serial_dl_write;
ret = serial8250_register_8250_port(&up);
if (ret < 0) {
dev_err(dev, "failed to register 8250 port\n");
clk_disable_unprepare(priv->clk);
return ret;
}
priv->line = ret;
priv->uport = serial8250_register_8250_port(&up);
if (IS_ERR(priv->uport))
return dev_err_probe(dev, PTR_ERR(priv->uport), "failed to register 8250 port\n");
platform_set_drvdata(pdev, priv);
@@ -236,16 +226,15 @@ static void uniphier_uart_remove(struct platform_device *pdev)
{
struct uniphier8250_priv *priv = platform_get_drvdata(pdev);
serial8250_unregister_port(priv->line);
clk_disable_unprepare(priv->clk);
serial8250_unregister_port(priv->uport);
}
static int __maybe_unused uniphier_uart_suspend(struct device *dev)
{
struct uniphier8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
serial8250_suspend_port(priv->line);
serial8250_suspend_port(up);
if (!uart_console(&up->port) || console_suspend_enabled)
clk_disable_unprepare(priv->clk);
@@ -256,7 +245,7 @@ static int __maybe_unused uniphier_uart_suspend(struct device *dev)
static int __maybe_unused uniphier_uart_resume(struct device *dev)
{
struct uniphier8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
struct uart_8250_port *up = priv->uport;
int ret;
if (!uart_console(&up->port) || console_suspend_enabled) {
@@ -265,7 +254,7 @@ static int __maybe_unused uniphier_uart_resume(struct device *dev)
return ret;
}
serial8250_resume_port(priv->line);
serial8250_resume_port(up);
return 0;
}
+13 -2
View File
@@ -304,8 +304,8 @@ config SERIAL_8250_EXAR_ST16C554
will be called 8250_exar_st16c554.
config SERIAL_8250_HUB6
tristate "Support Hub6 cards"
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
bool "Support Hub6 cards"
depends on SERIAL_8250_MANY_PORTS && ISA
help
Say Y here if you have a HUB6 serial board.
@@ -347,6 +347,17 @@ config SERIAL_8250_ACORN
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
config SERIAL_8250_AIROHA
tristate "Airoha UART support"
depends on ARCH_AIROHA || COMPILE_TEST
depends on SERIAL_8250
help
Selecting this option enables an Airoha SoC specific baud rate
calculation routine on an otherwise 16550 compatible UART hardware.
If you have an Airoha based board and want to use the serial port,
say Y to this option. If unsure, say N.
config SERIAL_8250_BCM2835AUX
tristate "BCM2835 auxiliar mini UART support"
depends on ARCH_BCM2835 || COMPILE_TEST
+2 -1
View File
@@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o
8250-y := 8250_core.o
8250-y += 8250_platform.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
8250-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250) += 8250_base.o
8250_base-y := 8250_port.o
@@ -20,6 +21,7 @@ obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
obj-$(CONFIG_SERIAL_8250_AIROHA) += 8250_airoha.o
obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o
@@ -35,7 +37,6 @@ obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
obj-$(CONFIG_SERIAL_8250_KEBA) += 8250_keba.o
+7 -8
View File
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
@@ -86,7 +87,7 @@ struct serial_info {
int manfid;
int prodid;
int c950ctrl;
int line[4];
struct uart_8250_port *uport[4];
const struct serial_quirk *quirk;
};
@@ -266,7 +267,7 @@ static void serial_remove(struct pcmcia_device *link)
* Recheck to see if the device is still configured.
*/
for (i = 0; i < info->ndev; i++)
serial8250_unregister_port(info->line[i]);
serial8250_unregister_port(info->uport[i]);
if (!info->slave)
pcmcia_disable_device(link);
@@ -278,7 +279,7 @@ static int serial_suspend(struct pcmcia_device *link)
int i;
for (i = 0; i < info->ndev; i++)
serial8250_suspend_port(info->line[i]);
serial8250_suspend_port(info->uport[i]);
return 0;
}
@@ -289,7 +290,7 @@ static int serial_resume(struct pcmcia_device *link)
int i;
for (i = 0; i < info->ndev; i++)
serial8250_resume_port(info->line[i]);
serial8250_resume_port(info->uport[i]);
if (info->quirk && info->quirk->wakeup)
info->quirk->wakeup(link);
@@ -347,7 +348,6 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
unsigned int iobase, int irq)
{
struct uart_8250_port uart;
int line;
memset(&uart, 0, sizeof(uart));
uart.port.iobase = iobase;
@@ -361,14 +361,13 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info *info,
if (info->quirk && info->quirk->setup)
info->quirk->setup(handle, &uart);
line = serial8250_register_8250_port(&uart);
if (line < 0) {
info->uport[info->ndev] = serial8250_register_8250_port(&uart);
if (IS_ERR(info->uport[info->ndev])) {
pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n",
(unsigned long)iobase, irq);
return -EINVAL;
}
info->line[info->ndev] = line;
info->ndev++;
return 0;
+11
View File
@@ -904,6 +904,7 @@ config SERIAL_JSM
config SERIAL_MSM
tristate "MSM on-chip serial port support"
depends on ARCH_QCOM || COMPILE_TEST
select PM_OPP
select SERIAL_CORE
config SERIAL_MSM_CONSOLE
@@ -1386,6 +1387,16 @@ config SERIAL_MEN_Z135
This driver can also be build as a module. If so, the module will be called
men_z135_uart.ko
config SDIO_UART
tristate "SDIO UART/GPS class support"
depends on TTY && MMC
help
SDIO function driver for SDIO cards that implements the UART
class, as well as the GPS class which appears like a UART.
This driver can also be built as a module. If so, the module will
be called sdio_uart.
config SERIAL_SPRD
tristate "Support for Spreadtrum serial"
select SERIAL_CORE
+1
View File
@@ -77,6 +77,7 @@ obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
obj-$(CONFIG_SERIAL_SC16IS7XX_SPI) += sc16is7xx_spi.o
obj-$(CONFIG_SERIAL_SC16IS7XX_I2C) += sc16is7xx_i2c.o
obj-$(CONFIG_SDIO_UART) += sdio_uart.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
+105 -18
View File
@@ -327,6 +327,7 @@ struct uart_amba_port {
char type[12];
ktime_t rs485_tx_drain_interval; /* nano */
enum pl011_rs485_tx_state rs485_tx_state;
bool rs485_break;
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
bool console_line_ended;
@@ -435,8 +436,8 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
enum dma_data_direction dir)
{
db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
&db->dma, GFP_KERNEL);
db->buf = dma_alloc_coherent(dmaengine_get_dma_device(chan),
PL011_DMA_BUFFER_SIZE, &db->dma, GFP_KERNEL);
if (!db->buf)
return -ENOMEM;
db->len = PL011_DMA_BUFFER_SIZE;
@@ -448,7 +449,7 @@ static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
enum dma_data_direction dir)
{
if (db->buf) {
dma_free_coherent(chan->device->dev,
dma_free_coherent(dmaengine_get_dma_device(chan),
PL011_DMA_BUFFER_SIZE, db->buf, db->dma);
}
}
@@ -609,7 +610,7 @@ static void pl011_dma_tx_callback(void *data)
uart_port_lock_irqsave(&uap->port, &flags);
if (uap->dmatx.queued)
dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
dma_unmap_single(dmaengine_get_dma_device(dmatx->chan), dmatx->dma,
dmatx->len, DMA_TO_DEVICE);
dmacr = uap->dmacr;
@@ -721,7 +722,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
dmaengine_submit(desc);
/* Fire the DMA transaction */
dma_dev->device_issue_pending(chan);
dma_async_issue_pending(chan);
uap->dmacr |= UART011_TXDMAE;
pl011_write(uap->dmacr, uap, REG_DMACR);
@@ -867,7 +868,7 @@ __acquires(&uap->port.lock)
dmaengine_terminate_async(uap->dmatx.chan);
if (uap->dmatx.queued) {
dma_unmap_single(uap->dmatx.chan->device->dev, uap->dmatx.dma,
dma_unmap_single(dmaengine_get_dma_device(uap->dmatx.chan), uap->dmatx.dma,
uap->dmatx.len, DMA_TO_DEVICE);
uap->dmatx.queued = false;
uap->dmacr &= ~UART011_TXDMAE;
@@ -1011,8 +1012,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
*/
if (dmaengine_pause(rxchan))
dev_err(uap->port.dev, "unable to pause DMA transfer\n");
dmastat = rxchan->device->device_tx_status(rxchan,
dmarx->cookie, &state);
dmastat = dmaengine_tx_status(rxchan, dmarx->cookie, &state);
if (dmastat != DMA_PAUSED)
dev_err(uap->port.dev, "unable to pause DMA transfer\n");
@@ -1066,7 +1066,7 @@ static void pl011_dma_rx_callback(void *data)
* Rx data can be taken by the UART interrupts during
* the DMA irq handler. So we check the residue here.
*/
rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
dmaengine_tx_status(rxchan, dmarx->cookie, &state);
pending = dbuf->len - state.residue;
BUG_ON(pending > PL011_DMA_BUFFER_SIZE);
/* Then we terminate the transfer - we now know our residue */
@@ -1124,7 +1124,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
struct dma_tx_state state;
dbuf = dmarx->use_buf_b ? &uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
dmaengine_tx_status(rxchan, dmarx->cookie, &state);
if (likely(state.residue < dmarx->last_residue)) {
dmataken = dbuf->len - dmarx->last_residue;
size = dmarx->last_residue - state.residue;
@@ -1249,7 +1249,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
/* In theory, this should already be done by pl011_dma_flush_buffer */
dmaengine_terminate_sync(uap->dmatx.chan);
if (uap->dmatx.queued) {
dma_unmap_single(uap->dmatx.chan->device->dev,
dma_unmap_single(dmaengine_get_dma_device(uap->dmatx.chan),
uap->dmatx.dma, uap->dmatx.len,
DMA_TO_DEVICE);
uap->dmatx.queued = false;
@@ -1280,6 +1280,11 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
return uap->using_rx_dma && uap->dmarx.running;
}
static inline bool pl011_dma_tx_queued(struct uart_amba_port *uap)
{
return uap->dmatx.queued;
}
#else
/* Blank functions if the DMA engine is not available */
static inline void pl011_dma_remove(struct uart_amba_port *uap)
@@ -1331,6 +1336,11 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
return false;
}
static inline bool pl011_dma_tx_queued(struct uart_amba_port *uap)
{
return false;
}
#define pl011_dma_flush_buffer NULL
#endif
@@ -1358,6 +1368,10 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
{
struct uart_port *port = &uap->port;
/* pl011_break_ctl() stops the transmission when the break ends */
if (uap->rs485_break)
return;
if (uap->rs485_tx_state == SEND)
uap->rs485_tx_state = WAIT_AFTER_SEND;
@@ -1420,10 +1434,6 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
struct uart_port *port = &uap->port;
u32 cr;
if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
uap->rs485_tx_state = SEND;
return;
}
if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY) {
hrtimer_try_to_cancel(&uap->trigger_stop_tx);
@@ -1462,6 +1472,10 @@ static void pl011_start_tx(struct uart_port *port)
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
uap->rs485_tx_state != SEND) {
/* trigger_start_tx starts TX once delay_rts_before_send passed */
if (uap->rs485_tx_state == WAIT_AFTER_RTS)
return;
pl011_rs485_tx_start(uap);
if (uap->rs485_tx_state == WAIT_AFTER_RTS)
return;
@@ -1478,8 +1492,12 @@ static enum hrtimer_restart pl011_trigger_start_tx(struct hrtimer *t)
unsigned long flags;
uart_port_lock_irqsave(&uap->port, &flags);
if (uap->rs485_tx_state == WAIT_AFTER_RTS)
pl011_start_tx(&uap->port);
if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
uap->rs485_tx_state = SEND;
/* A break can arm the timer while TX is stopped */
if (!uart_tx_stopped(&uap->port))
pl011_start_tx(&uap->port);
}
uart_port_unlock_irqrestore(&uap->port, flags);
return HRTIMER_NORESTART;
@@ -1771,16 +1789,60 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
struct tty_port *tport = &port->state->port;
bool rs485 = port->rs485.flags & SER_RS485_ENABLED;
unsigned long flags;
unsigned int lcr_h;
uart_port_lock_irqsave(&uap->port, &flags);
/*
* In RS485 mode the transceiver only drives the bus while
* transmitting. Treat a break as a transmission.
*/
if (rs485 && break_state == -1 && !uap->rs485_break) {
uap->rs485_break = true;
/* Pending data already enabled the transceiver */
if (uap->rs485_tx_state != SEND &&
uap->rs485_tx_state != WAIT_AFTER_RTS)
pl011_rs485_tx_start(uap);
/*
* Wait out delay_rts_before_send before starting the break.
* The state stays WAIT_AFTER_RTS, so the TX path behaves as
* without a break. Start it here if trigger_start_tx is late.
*/
if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
uart_port_unlock_irqrestore(&uap->port, flags);
msleep(port->rs485.delay_rts_before_send);
uart_port_lock_irqsave(&uap->port, &flags);
if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
hrtimer_try_to_cancel(&uap->trigger_start_tx);
uap->rs485_tx_state = SEND;
if (!uart_tx_stopped(port))
pl011_start_tx(port);
}
}
}
lcr_h = pl011_read(uap, REG_LCRH_TX);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
pl011_write(lcr_h, uap, REG_LCRH_TX);
if (break_state == 0 && uap->rs485_break) {
uap->rs485_break = false;
/* An active TX path stops the transmission when it is done */
if (rs485 && (uart_tx_stopped(port) ||
(!pl011_dma_tx_queued(uap) &&
kfifo_is_empty(&tport->xmit_fifo))))
pl011_rs485_tx_stop(uap);
}
uart_port_unlock_irqrestore(&uap->port, flags);
}
@@ -2101,6 +2163,7 @@ static void pl011_shutdown(struct uart_port *port)
hrtimer_cancel(&uap->trigger_stop_tx);
uart_port_lock_irq(port);
uap->rs485_break = false;
if (uap->rs485_tx_state != OFF)
pl011_rs485_tx_stop_now(uap);
uart_port_unlock_irq(port);
@@ -2397,8 +2460,32 @@ static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
if (port->rs485.flags & SER_RS485_ENABLED)
uap->rs485_break = false;
if ((port->rs485.flags & SER_RS485_ENABLED) &&
!(rs485->flags & SER_RS485_ENABLED)) {
bool tx_pending = uap->rs485_tx_state == WAIT_AFTER_RTS;
u32 cr = pl011_read(uap, REG_CR);
/*
* Leaving RS485 mode, which only enables the transmitter while
* sending. Don't stop it, as that stalls a DMA transfer still
* in flight. Drop pending deferred starts and stops and keep
* it enabled.
*/
hrtimer_try_to_cancel(&uap->trigger_start_tx);
hrtimer_try_to_cancel(&uap->trigger_stop_tx);
uap->rs485_tx_state = OFF;
cr |= UART011_CR_TXE | UART011_CR_RXE;
pl011_write(cr, uap, REG_CR);
/* Start TX that was still waiting for delay_rts_before_send */
if (tx_pending && !uart_tx_stopped(port) &&
!pl011_dma_tx_start(uap))
pl011_start_tx_pio(uap);
} else if (port->rs485.flags & SER_RS485_ENABLED) {
pl011_rs485_tx_stop(uap);
}
/* Make sure auto RTS is disabled */
if (rs485->flags & SER_RS485_ENABLED) {
+1 -1
View File
@@ -304,7 +304,7 @@ static unsigned int arc_serial_get_mctrl(struct uart_port *port)
{
/*
* Pretend we have a Modem status reg and following bits are
* always set, to satify the serial core state machine
* always set, to satisfy the serial core state machine
* (DSR) Data Set Ready
* (CTS) Clear To Send
* (CAR) Carrier Detect
+4 -4
View File
@@ -2723,7 +2723,7 @@ static bool atmel_serial_clk_will_stop(void)
#endif
}
static int __maybe_unused atmel_serial_suspend(struct device *dev)
static int atmel_serial_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -2765,7 +2765,7 @@ static int __maybe_unused atmel_serial_suspend(struct device *dev)
return 0;
}
static int __maybe_unused atmel_serial_resume(struct device *dev)
static int atmel_serial_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -2996,7 +2996,7 @@ static void atmel_serial_remove(struct platform_device *pdev)
pdev->dev.of_node = NULL;
}
static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
static DEFINE_SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
atmel_serial_resume);
static struct platform_driver atmel_serial_driver = {
@@ -3005,7 +3005,7 @@ static struct platform_driver atmel_serial_driver = {
.driver = {
.name = "atmel_usart_serial",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
.pm = pm_ptr(&atmel_serial_pm_ops),
.pm = pm_sleep_ptr(&atmel_serial_pm_ops),
},
};
+5 -5
View File
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -59,11 +60,10 @@ static void __init earlycon_init(struct earlycon_device *device,
const char *s;
size_t len;
/* scan backwards from end of string for first non-numeral */
for (s = name + strlen(name);
s > name && s[-1] >= '0' && s[-1] <= '9';
s--)
;
/* Scan backwards to split the trailing index from the console name. */
s = name + strlen(name);
while (s > name && isdigit(s[-1]))
s--;
if (*s)
earlycon->index = simple_strtoul(s, NULL, 10);
len = s - name;
+9 -9
View File
@@ -491,7 +491,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl,
ARRAY_SIZE(sport->tx_sgl), sport->dma_tx_bytes);
ret = dma_map_sg(chan->device->dev, sgl, sport->dma_tx_nents,
ret = dma_map_sg(dmaengine_get_dma_device(chan), sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
if (!ret) {
dev_err(dev, "DMA mapping error for TX.\n");
@@ -502,7 +502,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
ret, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
if (!sport->dma_tx_desc) {
dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
dma_unmap_sg(dmaengine_get_dma_device(chan), sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
dev_err(dev, "Cannot prepare TX slave DMA!\n");
return;
@@ -535,7 +535,7 @@ static void lpuart_dma_tx_complete(void *arg)
return;
}
dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
dma_unmap_sg(dmaengine_get_dma_device(chan), sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
uart_xmit_advance(&sport->port, sport->dma_tx_bytes);
@@ -606,7 +606,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
if (sport->lpuart_dma_tx_use) {
if (sport->dma_tx_in_progress) {
dma_unmap_sg(chan->device->dev, &sport->tx_sgl[0],
dma_unmap_sg(dmaengine_get_dma_device(chan), &sport->tx_sgl[0],
sport->dma_tx_nents, DMA_TO_DEVICE);
sport->dma_tx_in_progress = false;
}
@@ -1176,7 +1176,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
}
/* CPU claims ownership of RX DMA buffer */
dma_sync_sg_for_cpu(chan->device->dev, &sport->rx_sgl, 1,
dma_sync_sg_for_cpu(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1,
DMA_FROM_DEVICE);
/*
@@ -1237,7 +1237,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
sport->last_residue = state.residue;
exit:
dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1,
dma_sync_sg_for_device(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1,
DMA_FROM_DEVICE);
uart_port_unlock_irqrestore(&sport->port, flags);
@@ -1374,7 +1374,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
return -ENOMEM;
sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
nent = dma_map_sg(chan->device->dev, &sport->rx_sgl, 1,
nent = dma_map_sg(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1,
DMA_FROM_DEVICE);
if (!nent) {
@@ -1430,7 +1430,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
return 0;
err_unmap_sg:
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
dma_unmap_sg(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1, DMA_FROM_DEVICE);
err_free_buf:
kfree(ring->buf);
ring->buf = NULL;
@@ -1447,7 +1447,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
if (!sport->dma_idle_int)
timer_delete_sync(&sport->lpuart_timer);
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
dma_unmap_sg(dmaengine_get_dma_device(chan), &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
sport->rx_ring.tail = 0;
sport->rx_ring.head = 0;
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Based on the same principle as kgdboe using the NETPOLL api, this
* driver uses a console polling api to implement a gdb serial inteface
* driver uses a console polling api to implement a gdb serial interface
* which is multiplexed on a console port.
*
* Maintainer: Jason Wessel <jason.wessel@windriver.com>
+1 -1
View File
@@ -639,7 +639,7 @@ static struct console ma35d1serial_console = {
.write = ma35d1serial_console_write,
.device = uart_console_device,
.setup = ma35d1serial_console_setup,
.flags = CON_PRINTBUFFER | CON_ENABLED,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &ma35d1serial_reg,
};
+595 -37
View File
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/property.h>
@@ -156,10 +157,17 @@
#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */
/* LCR bits owned by termios; TX break and RTS are driven elsewhere */
#define MAX310X_LCR_TERMIOS_MASK GENMASK(5, 0)
/* IRDA register bits */
#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */
#define MAX310X_IRDA_RTSINVERT_BIT (1 << 2) /* Invert RTS output */
/* HDPIXDELAY accessor macros */
#define MAX310X_HDPIXDELAY_SETUP(val) (((val) & 0x0f) << 4)
#define MAX310X_HDPIXDELAY_HOLD(val) ((val) & 0x0f)
/* Flow control trigger level register masks */
#define MAX310X_FLOWLVL_HALT_MASK GENMASK(3, 0) /* Flow control halt level */
@@ -288,12 +296,30 @@ struct max310x_devtype {
u8 power_bit; /* Bit for sleep or power-off mode (active high). */
};
/* Software-timed RS485 RTS envelope phase */
enum max310x_tx_state {
MAX310X_TX_OFF, /* idle, RTS released */
MAX310X_TX_WAIT_BEFORE_SEND, /* RTS asserted, before-send delay */
MAX310X_TX_SEND, /* data in flight, awaiting TX-empty */
MAX310X_TX_WAIT_AFTER_SEND, /* data drained, after-send hold */
};
struct max310x_one {
struct uart_port port;
struct work_struct tx_work;
struct work_struct md_work;
struct work_struct rs_work;
struct work_struct rts_work;
struct hrtimer tx_delay_tmr;
struct regmap *regmap;
unsigned int char_time_us;
unsigned int baud;
bool sw_rts_during_tx;
bool cancel_tx_delay_tmr;
bool tx_teardown; /* envelope being torn down */
bool rs485_pending; /* rs_work not yet applied */
bool tx_break; /* break_ctl() owns the transceiver */
enum max310x_tx_state tx_state;
u8 rx_buf[MAX310X_FIFO_SIZE];
};
@@ -678,6 +704,44 @@ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int l
regmap_noinc_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
}
static void max310x_rts_ctl(struct uart_port *port, bool rts_state)
{
max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_RTS_BIT,
rts_state ? MAX310X_LCR_RTS_BIT : 0);
}
/* RTS level for the transmitting or the idle phase of an RS485 envelope */
static bool max310x_rts_level(struct uart_port *port, bool active)
{
return active ? (port->rs485.flags & SER_RS485_RTS_ON_SEND) :
(port->rs485.flags & SER_RS485_RTS_AFTER_SEND);
}
/*
* Drive the RS485 RTS line to match the current tx_state and break
* ownership. This is the only place that touches RTS, and it reads the
* state rather than a fixed assert/deassert intent, so a newer assert is
* never clobbered by a stale release and an expiring after-send hold never
* releases a break in progress. It also arms the before-send timer once the
* RTS edge is on the wire, so data is never shifted before RTS is asserted.
*/
static void max310x_rts_work_proc(struct work_struct *ws)
{
struct max310x_one *one = container_of(ws, struct max310x_one, rts_work);
struct uart_port *port = &one->port;
bool rts_on = READ_ONCE(one->tx_state) != MAX310X_TX_OFF ||
READ_ONCE(one->tx_break);
max310x_rts_ctl(port, max310x_rts_level(port, rts_on));
guard(spinlock_irqsave)(&port->lock);
if (READ_ONCE(one->tx_state) == MAX310X_TX_WAIT_BEFORE_SEND &&
!one->cancel_tx_delay_tmr && !hrtimer_active(&one->tx_delay_tmr))
hrtimer_start(&one->tx_delay_tmr,
ms_to_ktime(port->rs485.delay_rts_before_send),
HRTIMER_MODE_REL);
}
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
{
struct max310x_one *one = to_max310x_port(port);
@@ -774,6 +838,77 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
tty_flip_buffer_push(&port->state->port);
}
static enum hrtimer_restart max310x_tmr_tx(struct hrtimer *timer)
{
struct max310x_one *one = container_of(timer, struct max310x_one,
tx_delay_tmr);
guard(spinlock_irqsave)(&one->port.lock);
if (!one->cancel_tx_delay_tmr) {
if (READ_ONCE(one->tx_state) == MAX310X_TX_WAIT_AFTER_SEND) {
/* After-send hold elapsed: drop RTS via the rts worker. */
WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
schedule_work(&one->rts_work);
} else {
WRITE_ONCE(one->tx_state, MAX310X_TX_SEND);
schedule_work(&one->tx_work);
}
}
return HRTIMER_NORESTART;
}
static void max310x_delayed_stop_tx(struct uart_port *port)
{
struct max310x_one *one = to_max310x_port(port);
unsigned int txlvl;
if (READ_ONCE(one->tx_state) == MAX310X_TX_OFF)
return;
/*
* Data still queued for transmission defers the hold: a refill is
* coming and the envelope is not over. Stopped output does not
* count - it drains nowhere, and the envelope must end.
*/
if (!kfifo_is_empty(&port->state->port.xmit_fifo) &&
!uart_tx_stopped(port))
return;
/*
* The kfifo can be empty while the chip TX FIFO is still draining, so arm
* the after-send hold only once the chip FIFO is empty too - the TX-empty
* interrupt re-invokes us then. Otherwise the hold starts early and RTS
* drops mid-character, clipping the last byte(s).
*/
txlvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
if (txlvl)
return;
/*
* Runs from tx_work without port->lock, so re-check the state under it:
* shutdown() may have cancelled the envelope meanwhile. Only
* MAX310X_TX_SEND may arm the hold.
*/
guard(spinlock_irqsave)(&one->port.lock);
if (one->cancel_tx_delay_tmr ||
READ_ONCE(one->tx_state) != MAX310X_TX_SEND)
return;
if (!hrtimer_active(&one->tx_delay_tmr)) {
/*
* Add one character for the byte still in the shift register -
* TX-empty fires as it enters, not as it leaves.
*/
ktime_t delay = us_to_ktime(one->char_time_us +
port->rs485.delay_rts_after_send *
USEC_PER_MSEC);
WRITE_ONCE(one->tx_state, MAX310X_TX_WAIT_AFTER_SEND);
hrtimer_start(&one->tx_delay_tmr, delay, HRTIMER_MODE_REL);
}
}
static void max310x_handle_tx(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
@@ -785,8 +920,16 @@ static void max310x_handle_tx(struct uart_port *port)
return;
}
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
/*
* Unwind the envelope even if a reconfigure has moved the
* port to the hardware path mid-envelope: a stranded
* tx_state would make a later reconfigure believe a
* software envelope still owns RTS.
*/
max310x_delayed_stop_tx(port);
return;
}
/*
* It's a circ buffer -- wrap around.
@@ -811,11 +954,75 @@ static void max310x_handle_tx(struct uart_port *port)
uart_write_wakeup(port);
}
/*
* Begin a software-timed RTS envelope: set the before-send phase and queue the
* rts worker to assert RTS. tx_state is set synchronously here (start_tx() holds
* port.lock) so close()/shutdown can see an envelope is in flight; rts_work then
* asserts RTS and arms the before-send timer (see there).
*/
static void max310x_delayed_start_tx(struct uart_port *port)
{
struct max310x_one *one = to_max310x_port(port);
WRITE_ONCE(one->tx_state, MAX310X_TX_WAIT_BEFORE_SEND);
one->cancel_tx_delay_tmr = false;
schedule_work(&one->rts_work);
}
/* called with port.lock taken and irqs off */
static void max310x_start_tx(struct uart_port *port)
{
struct max310x_one *one = to_max310x_port(port);
schedule_work(&one->tx_work);
/* A teardown is in progress; nothing may start an envelope or TX. */
if (one->tx_teardown)
return;
/*
* An RS485 reconfigure is scheduled but not applied yet: transmitting
* now would use the old path against half-programmed registers - a
* TIOCSRS485 switching paths followed immediately by a write puts the
* data on the wire with the transceiver released. Leave the data in
* the kfifo; rs_work restarts TX once the configuration is applied.
*/
if (one->rs485_pending)
return;
if (READ_ONCE(one->sw_rts_during_tx)) {
/*
* The before- and after-send phases share one delay timer. If an
* after-send release is pending, cancel it before starting a new
* TX so the just-asserted RTS is not yanked; re-arming the timer
* for the before-send phase then supersedes the release.
*/
int res = 0;
if (READ_ONCE(one->tx_state) == MAX310X_TX_WAIT_AFTER_SEND)
res = hrtimer_try_to_cancel(&one->tx_delay_tmr);
if (unlikely(res == -1)) {
one->cancel_tx_delay_tmr = true;
uart_port_unlock(port);
hrtimer_cancel(&one->tx_delay_tmr);
uart_port_lock(port);
/*
* The lock was dropped: a teardown may have run to
* completion or a reconfigure may have been posted
* meanwhile. Re-check before starting.
*/
if (one->tx_teardown || one->rs485_pending)
return;
}
/* Already sending: pump the new data, don't rewind. */
if (READ_ONCE(one->tx_state) == MAX310X_TX_SEND) {
schedule_work(&one->tx_work);
return;
}
max310x_delayed_start_tx(port);
} else {
schedule_work(&one->tx_work);
}
}
static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
@@ -840,8 +1047,12 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
}
if (rxlen)
max310x_handle_rx(port, rxlen);
/*
* TXEMPTY latches on the FIFO becoming empty, so a stale
* interrupt cannot pump data during an RTS setup delay.
*/
if (ists & MAX310X_IRQ_TXEMPTY_BIT)
max310x_start_tx(port);
schedule_work(&s->p[portno].tx_work);
} while (1);
return res;
@@ -923,17 +1134,198 @@ static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
schedule_work(&one->md_work);
}
/*
* A reconfigure can move the port off the hardware RTS path while the chip's
* auto-RTS still owns a transmission in flight; tx_state does not track
* those. Take such a transfer over before auto-RTS is disabled: enter
* MAX310X_TX_SEND, so the caller keeps RTS driven across the handover and
* the normal drain path arms the after-send hold. Returns true when a
* transmission owns RTS - adopted here or started concurrently - and false
* when the line is really idle.
*/
static bool max310x_adopt_hw_tx(struct max310x_one *one)
{
struct uart_port *port = &one->port;
if (!max310x_port_read(port, MAX310X_TXFIFOLVL_REG) &&
kfifo_is_empty(&port->state->port.xmit_fifo))
return false;
scoped_guard(spinlock_irqsave, &port->lock) {
if (one->tx_teardown)
return false;
if (READ_ONCE(one->tx_state) != MAX310X_TX_OFF)
return true;
WRITE_ONCE(one->tx_state, MAX310X_TX_SEND);
one->cancel_tx_delay_tmr = false;
}
return true;
}
/*
* Pick hardware or software RTS timing for the current port. The chip can
* deliver up to 15 bit-times of setup/hold delay via HDPIXDELAY; anything
* longer (or any RTS polarity the chip cannot produce automatically) must
* be driven by software via tx_delay_tmr and rts_work.
*/
static void max310x_set_rts_ctl_params(struct max310x_one *one)
{
const unsigned int max_bit_dly = 15;
struct uart_port *port = &one->port;
unsigned int setup = 0, hold = 0;
u8 mode1 = 0, irda = 0;
bool sw_rts = false;
if (!(port->rs485.flags & SER_RS485_ENABLED))
goto out;
/* Convert milliseconds to bit-times, rounding up. */
setup = DIV_ROUND_UP(one->baud * port->rs485.delay_rts_before_send,
MSEC_PER_SEC);
hold = DIV_ROUND_UP(one->baud * port->rs485.delay_rts_after_send,
MSEC_PER_SEC);
/*
* Compare in bit-times: a delay of exactly max_bit_dly bit-times
* must stay on the hardware path, which a nanosecond ceiling
* computed from the truncated per-bit time would reject. Without
* a baud rate the conversion is meaningless - use software.
*/
if (!one->baud || setup > max_bit_dly || hold > max_bit_dly ||
!!(port->rs485.flags & SER_RS485_RTS_ON_SEND) ==
!!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND)) {
sw_rts = true;
setup = 0;
hold = 0;
}
out:
/* Assign once; a transient false would be seen by other readers. */
WRITE_ONCE(one->sw_rts_during_tx, sw_rts);
max310x_port_write(port, MAX310X_HDPIXDELAY_REG,
MAX310X_HDPIXDELAY_SETUP(setup) |
MAX310X_HDPIXDELAY_HOLD(hold));
/*
* A break owns the transceiver: break_ctl() disabled auto-RTS and
* drives RTS manually, and restores it from the current
* configuration when the break ends. Touching them here would
* release the transceiver mid-break.
*/
if (one->tx_break)
return;
if (port->rs485.flags & SER_RS485_ENABLED) {
if (sw_rts) {
/*
* Only settle RTS at idle when no transmission owns it.
* A reconfigure while one is in flight - rs_work runs
* on every TIOCSRS485 - would otherwise release the
* transceiver mid-character. A transfer the hardware
* path owns is invisible to tx_state - adopt it
* instead of settling. The reverse strand also
* exists: an envelope the hardware path inherited
* mid-envelope leaves tx_state set with nothing
* driving the pin.
*/
if (READ_ONCE(one->tx_state) != MAX310X_TX_OFF ||
max310x_adopt_hw_tx(one)) {
/*
* The transfer may be running under auto-RTS:
* assert before auto-RTS is disabled below so
* the pin is never released under it, and arm
* the after-send hold - with the chip FIFO
* already drained no TX-empty interrupt
* arrives to arm it.
*/
max310x_rts_ctl(port,
max310x_rts_level(port, true));
max310x_delayed_stop_tx(port);
} else {
max310x_rts_ctl(port,
max310x_rts_level(port, false));
/*
* serial_core calls set_termios() without
* port->lock, so an envelope may have started
* while the idle level was written and the
* settle can land after its RTS assert.
* rts_work re-derives the level from
* tx_state; requeue it to converge.
*/
if (READ_ONCE(one->tx_state) != MAX310X_TX_OFF)
schedule_work(&one->rts_work);
}
} else {
mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT;
/*
* The auto-RTS engine asserts RTS high on send; for an
* active-low RTS let IRDA.RTSINVERT invert the output
* stage.
*/
if (!(port->rs485.flags & SER_RS485_RTS_ON_SEND))
irda = MAX310X_IRDA_RTSINVERT_BIT;
}
} else {
max310x_rts_ctl(port, 0);
}
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
max310x_port_update(port, MAX310X_IRDA_REG,
MAX310X_IRDA_RTSINVERT_BIT, irda);
}
static void max310x_break_ctl(struct uart_port *port, int break_state)
{
struct max310x_one *one = to_max310x_port(port);
one->tx_break = break_state;
max310x_port_update(port, MAX310X_LCR_REG,
MAX310X_LCR_TXBREAK_BIT,
break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
/*
* The chip's auto-RTS asserts the transceiver only while FIFO data is
* shifting out, and a break is not FIFO data. Disable auto-RTS for the
* break duration and drive RTS manually so the break reaches the wire;
* restore auto-RTS when the break ends. For an active-low RTS,
* IRDA.RTSINVERT already inverts the RTS_ output stage, so break_state
* is driven as it is.
*/
if (break_state) {
if (!(port->rs485.flags & SER_RS485_ENABLED))
return;
if (READ_ONCE(one->sw_rts_during_tx)) {
max310x_rts_ctl(port, max310x_rts_level(port, 1));
} else {
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
max310x_rts_ctl(port, 1);
}
} else {
/*
* Reapply the current configuration: a reconfigure that
* arrived during the break was deferred by the tx_break
* guard, and RS485 may have been disabled outright - the
* manually driven RTS must not leak past the break. On the
* software path the helper also settles the idle level; on
* the hardware path release the manual RTS - auto-RTS owns
* the pin again.
*/
max310x_set_rts_ctl_params(one);
if (!READ_ONCE(one->sw_rts_during_tx))
max310x_rts_ctl(port, 0);
}
}
static void max310x_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
unsigned int frame_bits = tty_get_frame_size(termios->c_cflag);
unsigned int lcr = 0, flow = 0;
int baud;
@@ -967,8 +1359,13 @@ static void max310x_set_termios(struct uart_port *port,
if (termios->c_cflag & CSTOPB)
lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */
/* Update LCR register */
max310x_port_write(port, MAX310X_LCR_REG, lcr);
/*
* Update LCR register. Leave the TX break and RTS bits alone: they are
* driven by break_ctl() and by the software-timed RS485 RTS, and a
* whole-register write here would end a break in progress or release
* the transceiver mid-character.
*/
max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_TERMIOS_MASK, lcr);
/* Set read status mask */
port->read_status_mask = MAX310X_LSR_RXOVR_BIT;
@@ -1040,41 +1437,101 @@ static void max310x_set_termios(struct uart_port *port,
/* Update timeout according to new baud rate */
uart_update_timeout(port, termios->c_cflag, baud);
/*
* Cache the new baud rate and the time it takes to clock out one
* character before reprogramming the RS485 RTS delays: the
* millisecond-to-bit-time conversion divides by the baud rate, and
* taking over an in-flight transfer arms the after-send hold from
* the character time.
*/
to_max310x_port(port)->baud = baud;
to_max310x_port(port)->char_time_us =
DIV_ROUND_UP(USEC_PER_SEC * frame_bits, baud);
max310x_set_rts_ctl_params(to_max310x_port(port));
}
static void max310x_rs_proc(struct work_struct *ws)
{
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
unsigned int delay, mode1 = 0, mode2 = 0;
unsigned int mode2 = 0;
unsigned long flags;
bool chip_tx_empty;
delay = (one->port.rs485.delay_rts_before_send << 4) |
one->port.rs485.delay_rts_after_send;
max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, delay);
/*
* Serialize against break_ctl() and set_termios(), which run under
* port->mutex: the tx_break-guarded register writes must not
* straddle a break starting or ending.
*/
guard(mutex)(&one->port.state->port.mutex);
if (one->port.rs485.flags & SER_RS485_ENABLED) {
mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT;
/* Flush an rts_work that read tx_state before the disable cleared it. */
if (!(one->port.rs485.flags & SER_RS485_ENABLED))
cancel_work_sync(&one->rts_work);
if (!(one->port.rs485.flags & SER_RS485_RX_DURING_TX))
mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
}
max310x_set_rts_ctl_params(one);
if (one->port.rs485.flags & SER_RS485_ENABLED &&
!(one->port.rs485.flags & SER_RS485_RX_DURING_TX))
mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
max310x_port_update(&one->port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
max310x_port_update(&one->port, MAX310X_MODE2_REG,
MAX310X_MODE2_ECHOSUPR_BIT, mode2);
MAX310X_MODE2_ECHOSUPR_BIT, mode2);
/*
* The configuration is applied: release any TX that start_tx()
* deferred while the reconfigure was pending, now on the right
* path. start_tx() can drop and retake the lock through the
* uart_port API - a raw spinlock guard here would unbalance it.
*/
chip_tx_empty = !max310x_port_read(&one->port,
MAX310X_TXFIFOLVL_REG);
uart_port_lock_irqsave(&one->port, &flags);
one->rs485_pending = false;
if (one->port.x_char ||
!kfifo_is_empty(&one->port.state->port.xmit_fifo)) {
/*
* A send state adopted without chip data is the deferred
* write itself: restart it as a fresh envelope so the
* before-send delay is honoured.
*/
if (chip_tx_empty &&
READ_ONCE(one->tx_state) == MAX310X_TX_SEND)
WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
max310x_start_tx(&one->port);
}
uart_port_unlock_irqrestore(&one->port, flags);
}
/* called with port.lock taken and irqs off */
static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
struct max310x_one *one = to_max310x_port(port);
if ((rs485->delay_rts_before_send > 0x0f) ||
(rs485->delay_rts_after_send > 0x0f))
return -ERANGE;
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
/*
* Make sure no SW-timed RTS toggle survives an RS485 disable, even
* if the delay timer happens to be running right now.
*/
if (!(rs485->flags & SER_RS485_ENABLED)) {
one->tx_teardown = true;
one->cancel_tx_delay_tmr = true;
if (hrtimer_try_to_cancel(&one->tx_delay_tmr) == -1) {
uart_port_unlock(port);
hrtimer_cancel(&one->tx_delay_tmr);
uart_port_lock(port);
}
WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
one->tx_teardown = false;
}
port->rs485 = *rs485;
one->rs485_pending = true;
schedule_work(&one->rs_work);
return 0;
@@ -1082,13 +1539,23 @@ static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios
static int max310x_startup(struct uart_port *port)
{
struct max310x_one *one = to_max310x_port(port);
unsigned int val;
max310x_power(port, 1);
/* Configure MODE1 register */
/*
* Clear a latched break: nothing clears TXBREAK when a port is
* closed with a break still asserted, and set_termios() no longer
* rewrites it.
*/
one->tx_break = false;
max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_TXBREAK_BIT, 0);
/* Configure MODE1: re-enable the transmitter shutdown() stopped */
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
MAX310X_MODE1_TRNSCVCTRL_BIT |
MAX310X_MODE1_TXDIS_BIT, 0);
/* Configure MODE2 register & Reset FIFOs*/
val = MAX310X_MODE2_RXEMPTINV_BIT | MAX310X_MODE2_FIFORST_BIT;
@@ -1096,21 +1563,22 @@ static int max310x_startup(struct uart_port *port)
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_FIFORST_BIT, 0);
/* Configure mode1/mode2 to have rs485/rs232 enabled at startup */
val = (clamp(port->rs485.delay_rts_before_send, 0U, 15U) << 4) |
clamp(port->rs485.delay_rts_after_send, 0U, 15U);
max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
one->tx_teardown = false;
if (port->rs485.flags & SER_RS485_ENABLED) {
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT,
MAX310X_MODE1_TRNSCVCTRL_BIT);
/*
* Configure the RS485 RTS timing (HW auto-RTS vs software-driven) and
* the RS485/RS232 mode bits. Don't hardcode HW auto-RTS here - let
* max310x_set_rts_ctl_params() pick HW or SW per the configured
* delays, otherwise the chip's auto-RTS would override the software
* RTS hold and the after-send delay is lost.
*/
max310x_set_rts_ctl_params(one);
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_ECHOSUPR_BIT,
MAX310X_MODE2_ECHOSUPR_BIT);
}
if (port->rs485.flags & SER_RS485_ENABLED &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_ECHOSUPR_BIT,
MAX310X_MODE2_ECHOSUPR_BIT);
/*
* Configure flow control levels:
@@ -1132,9 +1600,91 @@ static int max310x_startup(struct uart_port *port)
static void max310x_shutdown(struct uart_port *port)
{
/* Disable all interrupts */
struct max310x_one *one = to_max310x_port(port);
/*
* Gate new transmissions and interrupts first: a concurrent
* start_tx() either sees the interlock or happens-before it, and
* nothing below may start a new envelope. The timer and the works
* stay live for now - they are what completes a running after-send
* hold.
*/
scoped_guard(spinlock_irqsave, &port->lock)
one->tx_teardown = true;
max310x_port_write(port, MAX310X_IRQEN_REG, 0);
/*
* Stop the transmitter: the character in flight completes, data
* still queued is abandoned (the next startup() resets the FIFOs).
*/
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TXDIS_BIT, MAX310X_MODE1_TXDIS_BIT);
if (READ_ONCE(one->sw_rts_during_tx)) {
/*
* Honour a running after-send hold before the port is
* powered down. The bound covers the final character -
* tx_empty() cannot see the transmit shift register - plus
* the hold itself. Data beyond that is abandoned: it is
* only still queued when the tty layer was told not to
* wait, and the release below drives RTS to idle
* regardless.
*/
unsigned int tries = port->rs485.delay_rts_after_send +
2 * DIV_ROUND_UP(one->char_time_us, USEC_PER_MSEC);
while (READ_ONCE(one->tx_state) != MAX310X_TX_OFF && tries-- > 0)
fsleep(USEC_PER_MSEC);
} else {
/*
* Let the character in flight finish (the chip has no
* transmitter-idle status), then empty the FIFO: auto-RTS
* releases only once the transmitter is empty, and the
* power-off below would freeze an asserted pin until the
* next open. The hold is at most 15 bit-times.
*/
fsleep(one->char_time_us);
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_FIFORST_BIT,
MAX310X_MODE2_FIFORST_BIT);
max310x_port_update(port, MAX310X_MODE2_REG,
MAX310X_MODE2_FIFORST_BIT, 0);
if (port->rs485.flags & SER_RS485_ENABLED && one->baud) {
unsigned int hold = DIV_ROUND_UP(one->baud *
port->rs485.delay_rts_after_send,
MSEC_PER_SEC);
fsleep(max(DIV_ROUND_UP((hold + 1) * USEC_PER_SEC,
one->baud), 100U));
}
}
/*
* The wind-down is over: cancel unconditionally. The SW/HW decision
* is recomputed on every reconfigure, so a TIOCSRS485 can clear
* sw_rts_during_tx while an envelope is still in flight, and
* neither the timer nor the works may outlive the port.
*/
scoped_guard(spinlock_irqsave, &port->lock)
one->cancel_tx_delay_tmr = true;
cancel_work_sync(&one->tx_work);
hrtimer_cancel(&one->tx_delay_tmr);
cancel_work_sync(&one->rts_work);
WRITE_ONCE(one->tx_state, MAX310X_TX_OFF);
if (READ_ONCE(one->sw_rts_during_tx)) {
max310x_rts_ctl(port, max310x_rts_level(port, false));
/*
* The power-off below stops the UART clock that moves the
* RTS pin: released too late, the write reaches the register
* but the pin stays at its old level until the next startup
* restarts the clock. Give the release one bit time (at
* least 100 us) to reach the pin - the measured propagation
* is about one tick of the 16x oversampling clock.
*/
fsleep(max(one->char_time_us / 10, 100U));
}
max310x_power(port, 0);
}
@@ -1300,7 +1850,8 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
#endif
static const struct serial_rs485 max310x_rs485_supported = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX,
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX,
.delay_rts_before_send = 1,
.delay_rts_after_send = 1,
};
@@ -1427,6 +1978,11 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
/* Initialize queue for changing RS485 mode */
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
/* Initialize queue for software-driven RTS toggling */
INIT_WORK(&s->p[i].rts_work, max310x_rts_work_proc);
hrtimer_setup(&s->p[i].tx_delay_tmr, max310x_tmr_tx,
CLOCK_MONOTONIC, HRTIMER_MODE_REL);
s->p[i].tx_state = MAX310X_TX_OFF;
}
#ifdef CONFIG_GPIOLIB
@@ -1538,6 +2094,8 @@ static void max310x_remove(struct device *dev)
int i;
for (i = 0; i < s->devtype->nr; i++) {
hrtimer_cancel(&s->p[i].tx_delay_tmr);
cancel_work_sync(&s->p[i].rts_work);
cancel_work_sync(&s->p[i].tx_work);
cancel_work_sync(&s->p[i].md_work);
cancel_work_sync(&s->p[i].rs_work);
+2 -2
View File
@@ -4,7 +4,7 @@
/*
* mcf.c -- Freescale ColdFire UART driver
*
* (C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.org>
* (C) Copyright 2003-2007, Greg Ungerer <gerg@linux-m68k.org>
*/
/****************************************************************************/
@@ -654,7 +654,7 @@ static void __exit mcf_exit(void)
module_init(mcf_init);
module_exit(mcf_exit);
MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
MODULE_AUTHOR("Greg Ungerer <gerg@linux-m68k.org>");
MODULE_DESCRIPTION("Freescale ColdFire UART driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mcfuart");
+2 -2
View File
@@ -811,7 +811,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
priv->desc_rx = desc;
desc->callback = pch_dma_rx_complete;
desc->callback_param = priv;
desc->tx_submit(desc);
dmaengine_submit(desc);
dma_async_issue_pending(priv->chan_rx);
return PCH_UART_HANDLED_RX_INT;
@@ -971,7 +971,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
desc->callback = pch_dma_tx_complete;
desc->callback_param = priv;
desc->tx_submit(desc);
dmaengine_submit(desc);
dma_async_issue_pending(priv->chan_tx);
+3 -2
View File
@@ -233,6 +233,7 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
ch &= uap->parity_mask;
if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
uap->flags &= ~PMACZILOG_FLAG_BREAK;
r1 |= BRK_ABRT;
}
#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
@@ -444,7 +445,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
skip_a:
uart_port_unlock(&uap_a->port);
if (push)
tty_flip_buffer_push(&uap->port.state->port);
tty_flip_buffer_push(&uap_a->port.state->port);
if (!uap_b)
goto out;
@@ -469,7 +470,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
skip_b:
uart_port_unlock(&uap_b->port);
if (push)
tty_flip_buffer_push(&uap->port.state->port);
tty_flip_buffer_push(&uap_b->port.state->port);
out:
return rc;
+22 -27
View File
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/panic_notifier.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -288,6 +287,10 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console,
} else {
int max_alias_num = of_alias_get_highest_id("serial");
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
if (!port)
return ERR_PTR(-ENOMEM);
if (line < 0 || line >= nr_ports)
line = ida_alloc_range(&port_ida, max_alias_num + 1,
nr_ports - 1, GFP_KERNEL);
@@ -298,10 +301,6 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console,
if (line < 0)
return ERR_PTR(-ENXIO);
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
if (!port)
return ERR_PTR(-ENOMEM);
port->uport.iotype = UPIO_MEM;
port->uport.ops = &qcom_geni_uart_pops;
port->uport.flags = UPF_BOOT_AUTOCONF;
@@ -1293,7 +1292,6 @@ out_unlock:
static int setup_fifos(struct qcom_geni_serial_port *port)
{
struct uart_port *uport;
u32 old_rx_fifo_depth = port->rx_fifo_depth;
uport = &port->uport;
port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se);
@@ -1302,19 +1300,6 @@ static int setup_fifos(struct qcom_geni_serial_port *port)
uport->fifosize =
(port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE;
if (port->rx_buf && (old_rx_fifo_depth != port->rx_fifo_depth) && port->rx_fifo_depth) {
/*
* Use krealloc rather than krealloc_array because rx_buf is
* accessed as 1 byte entries as well as 4 byte entries so it's
* not necessarily an array.
*/
port->rx_buf = devm_krealloc(uport->dev, port->rx_buf,
port->rx_fifo_depth * sizeof(u32),
GFP_KERNEL);
if (!port->rx_buf)
return -ENOMEM;
}
return 0;
}
@@ -1484,7 +1469,7 @@ static int geni_serial_set_rate(struct geni_se *se, unsigned long baud)
* Bump up BW vote on CPU and CORE path as driver supports FIFO mode
* only.
*/
avg_bw_core = baud > 115200 ? CORE_2X_50_MHZ : CORE_2X_19_2_MHZ;
avg_bw_core = (baud > 115200) ? CORE_2X_50_MHZ : CORE_2X_19_2_MHZ;
port->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(avg_bw_core);
port->se.icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(baud);
geni_icc_set_bw(&port->se);
@@ -1920,7 +1905,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
ret = port->dev_data->resources_init(&port->se);
if (ret)
return ret;
goto error;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -1970,8 +1955,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
uport->irq = irq;
uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
if (!data->console)
if (!data->console) {
port->wakeup_irq = platform_get_irq_optional(pdev, 1);
if (port->wakeup_irq < 0 && port->wakeup_irq != -ENXIO) {
ret = port->wakeup_irq;
goto error;
}
}
if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"))
port->rx_tx_swap = true;
@@ -2002,7 +1992,6 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->wakeup_irq);
if (ret) {
device_init_wakeup(&pdev->dev, false);
ida_free(&port_ida, uport->line);
goto error;
}
}
@@ -2026,12 +2015,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
return 0;
error:
if (!data->console)
ida_free(&port_ida, uport->line);
if (port->rx_dma_addr) {
dma_unmap_single(pdev->dev.parent, port->rx_dma_addr,
DMA_RX_BUF_SIZE, DMA_FROM_DEVICE);
port->rx_dma_addr = 0;
}
dev_pm_domain_detach_list(port->se.pd_list);
return ret;
}
@@ -2047,7 +2037,8 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
irq_work_sync(&port->tx_kick);
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
ida_free(&port_ida, uport->line);
if (!port->dev_data->console)
ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
if (port->rx_dma_addr) {
@@ -2055,8 +2046,6 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
DMA_RX_BUF_SIZE, DMA_FROM_DEVICE);
port->rx_dma_addr = 0;
}
dev_pm_domain_detach_list(port->se.pd_list);
}
static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev)
@@ -2128,6 +2117,12 @@ static int qcom_geni_serial_resume(struct device *dev)
return ret;
}
if (console_suspend_enabled && uart_console(uport)) {
ret = pm_runtime_resume(dev);
if (ret < 0)
return ret;
}
ret = uart_resume_port(private_data->drv, uport);
if (uart_console(uport)) {
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS);
+15 -12
View File
@@ -300,7 +300,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
dmaengine_pause(dma->tx_chan);
dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
dmaengine_terminate_all(dma->tx_chan);
dma_sync_single_for_cpu(dma->tx_chan->device->dev,
dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->tx_chan),
dma->tx_transfer_addr, dma->tx_size,
DMA_TO_DEVICE);
async_tx_ack(dma->tx_desc);
@@ -333,7 +333,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
count = dma->tx_bytes_requested - state.residue;
async_tx_ack(dma->tx_desc);
dma_sync_single_for_cpu(dma->tx_chan->device->dev,
dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->tx_chan),
dma->tx_transfer_addr, dma->tx_size,
DMA_TO_DEVICE);
@@ -435,7 +435,7 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
dma->tx_transfer_addr = dma->tx_addr + tail;
dma_sync_single_for_device(dma->tx_chan->device->dev,
dma_sync_single_for_device(dmaengine_get_dma_device(dma->tx_chan),
dma->tx_transfer_addr, dma->tx_size,
DMA_TO_DEVICE);
@@ -509,7 +509,7 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
if (!count)
return;
dma_sync_single_for_cpu(dma->rx_chan->device->dev, dma->rx_addr,
dma_sync_single_for_cpu(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
ourport->port.icount.rx += count;
@@ -631,7 +631,7 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
{
struct s3c24xx_uart_dma *dma = ourport->dma;
dma_sync_single_for_device(dma->rx_chan->device->dev, dma->rx_addr,
dma_sync_single_for_device(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
@@ -1101,20 +1101,23 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
goto err_release_tx;
}
dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
struct device *rx_dev = dmaengine_get_dma_device(dma->rx_chan);
struct device *tx_dev = dmaengine_get_dma_device(dma->tx_chan);
dma->rx_addr = dma_map_single(rx_dev, dma->rx_buf,
dma->rx_size, DMA_FROM_DEVICE);
if (dma_mapping_error(dma->rx_chan->device->dev, dma->rx_addr)) {
if (dma_mapping_error(rx_dev, dma->rx_addr)) {
reason = "DMA mapping error for RX buffer";
ret = -EIO;
goto err_free_rx;
}
/* TX buffer */
dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
dma->tx_addr = dma_map_single(tx_dev,
p->port.state->port.xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) {
if (dma_mapping_error(tx_dev, dma->tx_addr)) {
reason = "DMA mapping error for TX buffer";
ret = -EIO;
goto err_unmap_rx;
@@ -1123,7 +1126,7 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
return 0;
err_unmap_rx:
dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
dma_unmap_single(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
err_free_rx:
kfree(dma->rx_buf);
@@ -1143,7 +1146,7 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
if (dma->rx_chan) {
dmaengine_terminate_all(dma->rx_chan);
dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
dma_unmap_single(dmaengine_get_dma_device(dma->rx_chan), dma->rx_addr,
dma->rx_size, DMA_FROM_DEVICE);
kfree(dma->rx_buf);
dma_release_channel(dma->rx_chan);
@@ -1152,7 +1155,7 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
if (dma->tx_chan) {
dmaengine_terminate_all(dma->tx_chan);
dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
dma_unmap_single(dmaengine_get_dma_device(dma->tx_chan), dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->tx_chan);
dma->tx_chan = NULL;
+3 -1
View File
@@ -501,7 +501,9 @@ static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case SC16IS7XX_RHR_REG: /* Shared address space with THR & DLL */
case SC16IS7XX_IER_REG: /* Shared address space with DLH */
case SC16IS7XX_IIR_REG: /* Shared address space with FCR & EFR */
case SC16IS7XX_MCR_REG: /* Shared address space with XON1 */
case SC16IS7XX_LSR_REG: /* Shared address space with XON2 */
case SC16IS7XX_MSR_REG: /* Shared address space with TCR & XOFF1 */
case SC16IS7XX_SPR_REG: /* Shared address space with TLR & XOFF2 */
@@ -1516,7 +1518,7 @@ static int sc16is7xx_setup_channel(struct sc16is7xx_one *one, int i,
/* Initialize port data */
port->type = PORT_SC16IS7XX;
port->fifosize = SC16IS7XX_FIFO_SIZE;
port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY | UPF_SOFT_FLOW;
port->iotype = UPIO_BUS;
port->rs485_config = sc16is7xx_config_rs485;
port->rs485_supported = sc16is7xx_rs485_supported;
File renamed without changes.
+30 -40
View File
@@ -14,6 +14,7 @@
#include <linux/sched/signal.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/of.h>
@@ -33,7 +34,6 @@
#include <linux/uaccess.h>
#include "serial_base.h"
#include "8250/8250.h" /* For hub6_match_port() */
/*
* This is used to lock changes in serial line configuration.
@@ -247,29 +247,29 @@ static int uart_alloc_xmit_buf(struct tty_port *port)
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
unsigned long flags;
unsigned long page;
u8 *buf;
/*
* Initialise and allocate the transmit and temporary
* buffer.
*/
page = get_zeroed_page(GFP_KERNEL);
if (!page)
buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
state->port.xmit_buf = (unsigned char *)page;
state->port.xmit_buf = buf;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
uart_port_unlock_deref(uport, flags);
} else {
uart_port_unlock_deref(uport, flags);
/*
* Do not free() the page under the port lock, see
* Do not free() the buffer under the port lock, see
* uart_free_xmit_buf().
*/
free_page(page);
kfree(buf);
}
return 0;
@@ -280,10 +280,10 @@ static void uart_free_xmit_buf(struct tty_port *port)
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
unsigned long flags;
char *xmit_buf;
u8 *xmit_buf;
/*
* Do not free() the transmit buffer page under the port lock since
* Do not free() the transmit buffer under the port lock since
* this can create various circular locking scenarios. For instance,
* console driver may need to allocate/free a debug object, which
* can end up in printk() recursion.
@@ -294,7 +294,7 @@ static void uart_free_xmit_buf(struct tty_port *port)
INIT_KFIFO(port->xmit_fifo);
uart_port_unlock_deref(uport, flags);
free_page((unsigned long)xmit_buf);
kfree(xmit_buf);
}
/*
@@ -896,7 +896,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
upf_t old_flags, new_flags;
int retval;
if (!uport || tty_io_error(tty))
/*
* TTY_IO_ERROR is also set on a port that could not be started, and
* this is how such a port is configured. Only refuse a hung up port.
*/
if (!uport || !tty_port_active(port))
return -EIO;
new_port = new_info->port;
@@ -1144,7 +1148,8 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
*/
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &port->mutex) {
uport = uart_port_check(state);
if (!uport || tty_io_error(tty))
/* As in uart_set_info(), only refuse a hung up port. */
if (!uport || !tty_port_active(port))
return -EIO;
if (tty_port_users(port) != 1)
@@ -2133,7 +2138,8 @@ EXPORT_SYMBOL_GPL(uart_console_write);
/**
* uart_parse_earlycon - Parse earlycon options
* @p: ptr to 2nd field (ie., just beyond '<name>,')
* @p: ptr to 2nd field (ie., just beyond '<name>,'); %NULL if
* no console options were supplied
* @iotype: ptr for decoded iotype (out)
* @addr: ptr for decoded mapbase/iobase (out)
* @options: ptr for <options> field; %NULL if not present (out)
@@ -2153,6 +2159,9 @@ EXPORT_SYMBOL_GPL(uart_console_write);
int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
resource_size_t *addr, char **options)
{
if (!p)
return -EINVAL;
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
p += 5;
@@ -2211,7 +2220,7 @@ uart_parse_options(const char *options, int *baud, int *parity,
const char *s = options;
*baud = simple_strtoul(s, NULL, 10);
while (*s >= '0' && *s <= '9')
while (isdigit(*s))
s++;
if (*s)
*parity = *s++;
@@ -3236,6 +3245,13 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
if (uart_console(uport))
unregister_console(uport->cons);
scoped_guard(mutex, &port->mutex) {
port->console = false;
if (tty_port_initialized(port))
uart_shutdown(NULL, state);
}
/*
* Free the port IO and memory resources, if any.
*/
@@ -3256,32 +3272,6 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
state->uart_port = NULL;
}
/**
* uart_match_port - are the two ports equivalent?
* @port1: first port
* @port2: second port
*
* This utility function can be used to determine whether two uart_port
* structures describe the same port.
*/
bool uart_match_port(const struct uart_port *port1,
const struct uart_port *port2)
{
if (port1->iotype != port2->iotype)
return false;
else if (port1->iotype == UPIO_PORT)
return port1->iobase == port2->iobase;
else if (port1->iotype == UPIO_HUB6)
return hub6_match_port(port1, port2);
else if (uart_iotype_mmio(port1->iotype))
return port1->mapbase == port2->mapbase;
else if (port1->iotype == UPIO_BUS)
return true;
else
return false;
}
EXPORT_SYMBOL(uart_match_port);
static struct serial_ctrl_device *
serial_core_get_ctrl_dev(struct serial_port_device *port_dev)
{
+9 -53
View File
@@ -965,7 +965,12 @@ static int serial_txx9_register_port(struct uart_port *port)
mutex_lock(&serial_txx9_mutex);
for (i = 0; i < UART_NR; i++) {
uart = &serial_txx9_ports[i];
if (uart_match_port(uart, port)) {
/*
* serial_txx9_register_port() is only called from
* pciserial_txx9_init_one(). So .iotype is UPIO_PORT and
* comparing .iobase serves to distinguish ports.
*/
if (uart->iobase == port->iobase) {
uart_remove_one_port(&serial_txx9_reg, uart);
break;
}
@@ -1009,7 +1014,8 @@ static void serial_txx9_unregister_port(int line)
struct uart_port *uart = &serial_txx9_ports[line];
mutex_lock(&serial_txx9_mutex);
uart_remove_one_port(&serial_txx9_reg, uart);
if (uart->iobase || uart->mapbase)
uart_remove_one_port(&serial_txx9_reg, uart);
uart->flags = 0;
uart->type = PORT_UNKNOWN;
uart->iobase = 0;
@@ -1019,52 +1025,6 @@ static void serial_txx9_unregister_port(int line)
mutex_unlock(&serial_txx9_mutex);
}
/*
* Register a set of serial devices attached to a platform device.
*/
static int serial_txx9_probe(struct platform_device *dev)
{
struct uart_port *p = dev_get_platdata(&dev->dev);
struct uart_port port;
int ret, i;
memset(&port, 0, sizeof(struct uart_port));
for (i = 0; p && p->uartclk != 0; p++, i++) {
port.iobase = p->iobase;
port.membase = p->membase;
port.irq = p->irq;
port.uartclk = p->uartclk;
port.iotype = p->iotype;
port.flags = p->flags;
port.mapbase = p->mapbase;
port.dev = &dev->dev;
port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_TXX9_CONSOLE);
ret = serial_txx9_register_port(&port);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
"(IO%lx MEM%llx IRQ%d): %d\n", i,
p->iobase, (unsigned long long)p->mapbase,
p->irq, ret);
}
}
return 0;
}
/*
* Remove serial ports registered against a platform device.
*/
static void serial_txx9_remove(struct platform_device *dev)
{
int i;
for (i = 0; i < UART_NR; i++) {
struct uart_port *up = &serial_txx9_ports[i];
if (up->dev == &dev->dev)
serial_txx9_unregister_port(i);
}
}
#ifdef CONFIG_PM
static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
{
@@ -1096,8 +1056,6 @@ static int serial_txx9_resume(struct platform_device *dev)
#endif
static struct platform_driver serial_txx9_plat_driver = {
.probe = serial_txx9_probe,
.remove = serial_txx9_remove,
#ifdef CONFIG_PM
.suspend = serial_txx9_suspend,
.resume = serial_txx9_resume,
@@ -1251,9 +1209,7 @@ static void __exit serial_txx9_exit(void)
platform_driver_unregister(&serial_txx9_plat_driver);
platform_device_unregister(serial_txx9_plat_devs);
for (i = 0; i < UART_NR; i++) {
struct uart_port *up = &serial_txx9_ports[i];
if (up->iobase || up->mapbase)
uart_remove_one_port(&serial_txx9_reg, up);
serial_txx9_unregister_port(i);
}
uart_unregister_driver(&serial_txx9_reg);
+14 -8
View File
@@ -1495,7 +1495,7 @@ static void sci_dma_rx_release(struct sci_port *s)
uart_port_unlock_irqrestore(port, flags);
dmaengine_terminate_sync(chan);
dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
dma_free_coherent(dmaengine_get_dma_device(chan), s->buf_len_rx * 2, s->rx_buf[0],
sg_dma_address(&s->sg_rx[0]));
dma_release_channel(chan);
}
@@ -1591,7 +1591,7 @@ static void sci_dma_tx_release(struct sci_port *s)
s->chan_tx_saved = s->chan_tx = NULL;
s->cookie_tx = -EINVAL;
dmaengine_terminate_sync(chan);
dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
dma_unmap_single(dmaengine_get_dma_device(chan), s->tx_dma_addr, UART_XMIT_SIZE,
DMA_TO_DEVICE);
dma_release_channel(chan);
}
@@ -1676,7 +1676,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
goto switch_to_pio;
}
dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
dma_sync_single_for_device(dmaengine_get_dma_device(chan), buf, s->tx_dma_len,
DMA_TO_DEVICE);
desc->callback = sci_dma_tx_complete;
@@ -1832,12 +1832,13 @@ static void sci_request_dma(struct uart_port *port)
chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV);
dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
if (chan) {
struct device *dma_dev = dmaengine_get_dma_device(chan);
/* UART circular tx buffer is an aligned page. */
s->tx_dma_addr = dma_map_single(chan->device->dev,
s->tx_dma_addr = dma_map_single(dma_dev,
tport->xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
if (dma_mapping_error(dma_dev, s->tx_dma_addr)) {
dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n");
dma_release_channel(chan);
} else {
@@ -1853,12 +1854,13 @@ static void sci_request_dma(struct uart_port *port)
chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM);
dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
if (chan) {
struct device *dma_dev = dmaengine_get_dma_device(chan);
unsigned int i;
dma_addr_t dma;
void *buf;
s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize);
buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2,
buf = dma_alloc_coherent(dma_dev, s->buf_len_rx * 2,
&dma, GFP_KERNEL);
if (!buf) {
dev_warn(port->dev,
@@ -3937,12 +3939,12 @@ static int sci_probe(struct platform_device *dev)
if (sp->port.fifosize > 1) {
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_trigger);
if (ret)
return ret;
goto err_remove_port;
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout);
if (ret) {
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
return ret;
goto err_remove_port;
}
}
@@ -3952,6 +3954,10 @@ static int sci_probe(struct platform_device *dev)
sci_ports_in_use |= BIT(dev_id);
return 0;
err_remove_port:
uart_remove_one_port(&sci_uart_driver, &sp->port);
return ret;
}
static int sci_suspend(struct device *dev)
+1 -1
View File
@@ -999,7 +999,7 @@ static int sifive_serial_probe(struct platform_device *pdev)
}
#ifdef CONFIG_SERIAL_SIFIVE_CONSOLE
if (id > SIFIVE_SERIAL_MAX_PORTS) {
if (id >= SIFIVE_SERIAL_MAX_PORTS) {
dev_err(&pdev->dev, "too many UARTs (%d)\n", id);
return -EINVAL;
}
+10 -12
View File
@@ -179,9 +179,10 @@ static int tegra_tcu_probe(struct platform_device *pdev)
{
struct uart_port *port;
struct tegra_tcu *tcu;
struct device *dev = &pdev->dev;
int err;
tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL);
tcu = devm_kzalloc(dev, sizeof(*tcu), GFP_KERNEL);
if (!tcu)
return -ENOMEM;
@@ -190,11 +191,9 @@ static int tegra_tcu_probe(struct platform_device *pdev)
tcu->rx_client.rx_callback = tegra_tcu_receive;
tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx");
if (IS_ERR(tcu->tx)) {
err = PTR_ERR(tcu->tx);
dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err);
return err;
}
if (IS_ERR(tcu->tx))
return dev_err_probe(dev, PTR_ERR(tcu->tx),
"failed to get tx mailbox\n");
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE)
/* setup the console */
@@ -218,15 +217,14 @@ static int tegra_tcu_probe(struct platform_device *pdev)
err = uart_register_driver(&tcu->driver);
if (err) {
dev_err(&pdev->dev, "failed to register UART driver: %d\n",
err);
dev_err_probe(dev, err, "failed to register UART driver\n");
goto free_tx;
}
/* setup the port */
port = &tcu->port;
spin_lock_init(&port->lock);
port->dev = &pdev->dev;
port->dev = dev;
port->type = PORT_TEGRA_TCU;
port->ops = &tegra_tcu_uart_ops;
port->fifosize = 1;
@@ -236,7 +234,7 @@ static int tegra_tcu_probe(struct platform_device *pdev)
err = uart_add_one_port(&tcu->driver, port);
if (err) {
dev_err(&pdev->dev, "failed to add UART port: %d\n", err);
dev_err_probe(dev, err, "failed to add UART port\n");
goto unregister_uart;
}
@@ -246,8 +244,8 @@ static int tegra_tcu_probe(struct platform_device *pdev)
*/
tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx");
if (IS_ERR(tcu->rx)) {
err = PTR_ERR(tcu->rx);
dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err);
err = dev_err_probe(dev, PTR_ERR(tcu->rx),
"failed to get rx mailbox\n");
goto remove_uart_port;
}
+1 -4
View File
@@ -911,10 +911,7 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
* keyboard state so we can release keys that have been
* pressed before entering SysRq mode.
*/
if (value)
set_bit(code, sysrq->key_down);
else
clear_bit(code, sysrq->key_down);
assign_bit(code, sysrq->key_down, value);
if (was_active)
schedule_work(&sysrq->reinject_work);
+4 -4
View File
@@ -240,13 +240,13 @@ EXPORT_SYMBOL_GPL(tty_port_unregister_device);
int tty_port_alloc_xmit_buf(struct tty_port *port)
{
/* We may sleep in get_zeroed_page() */
/* We may sleep in kzalloc() */
guard(mutex)(&port->buf_mutex);
if (port->xmit_buf)
return 0;
port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
port->xmit_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (port->xmit_buf == NULL)
return -ENOMEM;
@@ -259,7 +259,7 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
void tty_port_free_xmit_buf(struct tty_port *port)
{
guard(mutex)(&port->buf_mutex);
free_page((unsigned long)port->xmit_buf);
kfree(port->xmit_buf);
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
}
@@ -288,7 +288,7 @@ static void tty_port_destructor(struct kref *kref)
/* check if last port ref was dropped before tty release */
if (WARN_ON(port->itty))
return;
free_page((unsigned long)port->xmit_buf);
kfree(port->xmit_buf);
tty_port_destroy(port);
if (port->ops && port->ops->destruct)
port->ops->destruct(port);
+3 -1
View File
@@ -2002,7 +2002,9 @@ static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
return 0;
#endif
unsigned short __free(kfree) *new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
unsigned short __free(kfree) *new_map =
kmalloc_array(ARRAY_SIZE(plain_map), sizeof(*new_map),
GFP_KERNEL);
if (!new_map)
return -ENOMEM;
+4 -4
View File
@@ -186,10 +186,10 @@ static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
return container_of(up, struct uart_8250_port, port);
}
int serial8250_register_8250_port(const struct uart_8250_port *);
void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
void serial8250_resume_port(int line);
struct uart_8250_port *serial8250_register_8250_port(const struct uart_8250_port *);
void serial8250_unregister_port(struct uart_8250_port *);
void serial8250_suspend_port(struct uart_8250_port *);
void serial8250_resume_port(struct uart_8250_port *);
int early_serial_setup(struct uart_port *port);
int early_serial8250_setup(struct earlycon_device *device, const char *options);
-2
View File
@@ -1140,8 +1140,6 @@ int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
void uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_read_port_properties(struct uart_port *port);
int uart_read_and_validate_port_properties(struct uart_port *port);
bool uart_match_port(const struct uart_port *port1,
const struct uart_port *port2);
/*
* Power Management
+9 -3
View File
@@ -347,12 +347,18 @@ struct geni_se {
#define QUP_SE_VERSION_2_5 0x20050000
/*
* QUP Core 2X clock votes used by GENI clients through the "qup-core" ICC
* path. Values are in Bps and must be converted with Bps_to_icc() before
* setting avg_bw.
* ICC bandwidth values in Bps for the GENI_TO_CORE ("qup-core") path.
* Convert them with Bps_to_icc() before setting avg_bw. The QUP ICC provider
* maps each threshold to the Core 2X rate named by the macro suffix.
*
* These values are core clock votes, not GENI transfer bandwidths.
*/
#define CORE_2X_19_2_MHZ 9600000
#define CORE_2X_50_MHZ 25000000
#define CORE_2X_100_MHZ 50000000
#define CORE_2X_150_MHZ 75000000
#define CORE_2X_200_MHZ 100000000
#define CORE_2X_236_MHZ 118000000
#define GENI_DEFAULT_BW Bps_to_icc(1000)