// SPDX-License-Identifier: GPL-2.0+ /* * SC16IS7xx tty serial driver - common code * * Copyright (C) 2014 GridPoint * Author: Jon Ringle <jringle@gridpoint.com> * Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
*/
/* MSR register bits */ #define SC16IS7XX_MSR_DCTS_BIT BIT(0) /* Delta CTS Clear To Send */ #define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready * or (IO4) * - only on 75x/76x
*/ #define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator * or (IO7) * - only on 75x/76x
*/ #define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect * or (IO6) * - only on 75x/76x
*/ #define SC16IS7XX_MSR_CTS_BIT BIT(4) /* CTS */ #define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4) * - only on 75x/76x
*/ #define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7) * - only on 75x/76x
*/ #define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6) * - only on 75x/76x
*/
/* * TCR register bits * TCR trigger levels are available from 0 to 60 characters with a granularity * of four. * The programmer must program the TCR such that TCR[3:0] > TCR[7:4]. There is * no built-in hardware check to make sure this condition is met. Also, the TCR * must be programmed with this condition before auto RTS or software flow * control is enabled to avoid spurious operation of the device.
*/ #define SC16IS7XX_TCR_RX_HALT(words) ((((words) / 4) & 0x0f) << 0) #define SC16IS7XX_TCR_RX_RESUME(words) ((((words) / 4) & 0x0f) << 4)
/* * TLR register bits * If TLR[3:0] or TLR[7:4] are logical 0, the selectable trigger levels via the * FIFO Control Register (FCR) are used for the transmit and receive FIFO * trigger levels. Trigger levels from 4 characters to 60 characters are * available with a granularity of four. * * When the trigger level setting in TLR is zero, the SC16IS74x/75x/76x uses the * trigger level setting defined in FCR. If TLR has non-zero trigger level value * the trigger level defined in FCR is discarded. This applies to both transmit * FIFO and receive FIFO trigger level setting. * * When TLR is used for RX trigger level control, FCR[7:6] should be left at the * default state, that is, '00'.
*/ #define SC16IS7XX_TLR_TX_TRIGGER(words) ((((words) / 4) & 0x0f) << 0) #define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4)
staticvoid sc16is7xx_power(struct uart_port *port, int on)
{
sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
SC16IS7XX_IER_SLEEP_BIT,
on ? 0 : SC16IS7XX_IER_SLEEP_BIT);
}
/* * In an amazing feat of design, the Enhanced Features Register (EFR) * shares the address of the Interrupt Identification Register (IIR). * Access to EFR is switched on by writing a magic value (0xbf) to the * Line Control Register (LCR). Any interrupt firing during this time will * see the EFR where it expects the IIR to be, leading to * "Unexpected interrupt" messages. * * Prevent this possibility by claiming a mutex while accessing the EFR, * and claiming the same mutex from within the interrupt handler. This is * similar to disabling the interrupt, but that doesn't work because the * bulk of the interrupt processing is run as a workqueue job in thread * context.
*/ staticvoid sc16is7xx_efr_lock(struct uart_port *port)
{ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
mutex_lock(&one->efr_lock);
/* Backup content of LCR. */
one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
/* Enable access to Enhanced register set */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B);
/* Disable cache updates when writing to EFR registers */
regcache_cache_bypass(one->regmap, true);
}
staticbool sc16is7xx_regmap_volatile(struct device *dev, unsignedint reg)
{ switch (reg) { case SC16IS7XX_RHR_REG: case SC16IS7XX_IIR_REG: case SC16IS7XX_LSR_REG: case SC16IS7XX_MSR_REG: case SC16IS7XX_TXLVL_REG: case SC16IS7XX_RXLVL_REG: case SC16IS7XX_IOSTATE_REG: case SC16IS7XX_IOCONTROL_REG: returntrue; default: returnfalse;
}
}
/* * Configure programmable baud rate generator (divisor) according to the * desired baud rate. * * From the datasheet, the divisor is computed according to: * * XTAL1 input frequency * ----------------------- * prescaler * divisor = --------------------------- * baud-rate x sampling-rate
*/ staticint sc16is7xx_set_baud(struct uart_port *port, int baud)
{ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
u8 lcr; unsignedint prescaler = 1; unsignedlong clk = port->uartclk, div = clk / 16 / baud;
if (div >= BIT(16)) {
prescaler = 4;
div /= prescaler;
}
/* If bit MCR_CLKSEL is set, the divide by 4 prescaler is activated. */
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_CLKSEL_BIT,
prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT);
mutex_lock(&one->efr_lock);
/* Backup LCR and access special register set (DLL/DLH) */
lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_A);
/* Write the new divisor */
regcache_cache_bypass(one->regmap, true);
sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256);
sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256);
regcache_cache_bypass(one->regmap, false);
/* Restore LCR and access to general register set */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
if (unlikely(rxlen >= sizeof(one->buf))) {
dev_warn_ratelimited(port->dev, "ttySC%i: Possible RX FIFO overrun: %d\n",
port->line, rxlen);
port->icount.buf_overrun++; /* Ensure sanity of RX level */
rxlen = sizeof(one->buf);
}
while (rxlen) { /* Only read lsr if there are possible errors in FIFO */ if (read_lsr) {
lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); if (!(lsr & SC16IS7XX_LSR_FIFOE_BIT))
read_lsr = false; /* No errors left in FIFO */
} else
lsr = 0;
/* Limit to space available in TX FIFO */
txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); if (txlen > SC16IS7XX_FIFO_SIZE) {
dev_err_ratelimited(port->dev, "chip reports %d free bytes in TX fifo, but it only has %d",
txlen, SC16IS7XX_FIFO_SIZE);
txlen = 0;
}
switch (iir) { case SC16IS7XX_IIR_RDI_SRC: case SC16IS7XX_IIR_RLSE_SRC: case SC16IS7XX_IIR_RTOI_SRC: case SC16IS7XX_IIR_XOFFI_SRC:
rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG);
/* * There is a silicon bug that makes the chip report a * time-out interrupt but no data in the FIFO. This is * described in errata section 18.1.4. * * When this happens, read one byte from the FIFO to * clear the interrupt.
*/ if (iir == SC16IS7XX_IIR_RTOI_SRC && !rxlen)
rxlen = 1;
if (rxlen)
sc16is7xx_handle_rx(port, rxlen, iir); break; /* CTSRTS interrupt comes only when CTS goes inactive */ case SC16IS7XX_IIR_CTSRTS_SRC: case SC16IS7XX_IIR_MSI_SRC:
sc16is7xx_update_mlines(one); break; case SC16IS7XX_IIR_THRI_SRC:
sc16is7xx_handle_tx(port); break; default:
dev_err_ratelimited(port->dev, "ttySC%i: Unexpected interrupt: %x",
port->line, iir); break;
}
/* * Hardware flow control is enabled and thus the device ignores RTS * value set in MCR register. Stop reading data from RX FIFO so the * AutoRTS feature will de-activate RTS output.
*/
uart_port_lock_irqsave(port, &flags);
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
uart_port_unlock_irqrestore(port, flags);
}
if (rs485->flags & SER_RS485_ENABLED) { /* * RTS signal is handled by HW, it's timing can't be influenced. * However, it's sometimes useful to delay TX even without RTS * control therefore we try to handle .delay_rts_before_send.
*/ if (rs485->delay_rts_after_send) return -EINVAL;
}
/* Now, initialize the UART */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8);
/* Enable IrDA mode if requested in DT */ /* This bit must be written with LCR[7] = 0 */
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_IRDA_BIT,
one->irda_mode ?
SC16IS7XX_MCR_IRDA_BIT : 0);
/* Enable the Rx and Tx FIFO */
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
SC16IS7XX_EFCR_RXDISABLE_BIT |
SC16IS7XX_EFCR_TXDISABLE_BIT,
0);
/* Enable RX, CTS change and modem lines interrupts */
val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_CTSI_BIT |
SC16IS7XX_IER_MSI_BIT;
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
if (val)
state |= BIT(offset); else
state &= ~BIT(offset);
/* * If we write IOSTATE first, and then IODIR, the output value is not * transferred to the corresponding I/O pin. * The datasheet states that each register bit will be transferred to * the corresponding I/O pin programmed as output when writing to * IOSTATE. Therefore, configure direction first with IODIR, and then * set value after with IOSTATE.
*/
sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset),
BIT(offset));
sc16is7xx_port_write(port, SC16IS7XX_IOSTATE_REG, state);
ret = device_property_read_u32_array(dev, "nxp,modem-control-line-ports",
mctrl_port, count); if (ret) return ret;
s->mctrl_mask = 0;
for (i = 0; i < count; i++) { /* Use GPIO lines as modem control lines */ if (mctrl_port[i] == 0)
s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_A_BIT; elseif (mctrl_port[i] == 1)
s->mctrl_mask |= SC16IS7XX_IOCONTROL_MODEM_B_BIT;
}
if (s->mctrl_mask)
regmap_update_bits(
regmap,
SC16IS7XX_IOCONTROL_REG,
SC16IS7XX_IOCONTROL_MODEM_A_BIT |
SC16IS7XX_IOCONTROL_MODEM_B_BIT, s->mctrl_mask);
/* Assert reset GPIO if defined and valid. */
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(reset_gpio)) return dev_err_probe(dev, PTR_ERR(reset_gpio), "Failed to get reset GPIO\n");
int sc16is7xx_probe(struct device *dev, conststruct sc16is7xx_devtype *devtype, struct regmap *regmaps[], int irq)
{ unsignedlong freq = 0, *pfreq = dev_get_platdata(dev); unsignedint val;
u32 uartclk = 0; int i, ret; struct sc16is7xx_port *s; bool port_registered[SC16IS7XX_MAX_PORTS];
for (i = 0; i < devtype->nr_uart; i++) if (IS_ERR(regmaps[i])) return PTR_ERR(regmaps[i]);
/* * This device does not have an identification register that would * tell us if we are really connected to the correct device. * The best we can do is to check if communication is at all possible. * * Note: regmap[0] is used in the probe function to access registers * common to all channels/ports, as it is guaranteed to be present on * all variants.
*/
ret = regmap_read(regmaps[0], SC16IS7XX_LSR_REG, &val); if (ret < 0) return -EPROBE_DEFER;
/* Alloc port structure */
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); if (!s) {
dev_err(dev, "Error allocating port structure\n"); return -ENOMEM;
}
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
s->polling = (irq <= 0); if (s->polling)
dev_dbg(dev, "No interrupt pin definition, falling back to polling mode\n");
s->clk = devm_clk_get_optional(dev, NULL); if (IS_ERR(s->clk)) return PTR_ERR(s->clk);
ret = clk_prepare_enable(s->clk); if (ret) return ret;
freq = clk_get_rate(s->clk); if (freq == 0) { if (uartclk)
freq = uartclk; if (pfreq)
freq = *pfreq; if (freq)
dev_dbg(dev, "Clock frequency: %luHz\n", freq); else return -EINVAL;
}
s->devtype = devtype;
dev_set_drvdata(dev, s);
kthread_init_worker(&s->kworker);
s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, "sc16is7xx"); if (IS_ERR(s->kworker_task)) {
ret = PTR_ERR(s->kworker_task); goto out_clk;
}
sched_set_fifo(s->kworker_task);
ret = sc16is7xx_reset(dev, regmaps[0]); if (ret) goto out_kthread;
/* Mark each port line and status as uninitialised. */ for (i = 0; i < devtype->nr_uart; ++i) {
s->p[i].port.line = SC16IS7XX_MAX_DEVS;
port_registered[i] = false;
}
for (i = 0; i < devtype->nr_uart; ++i) {
ret = ida_alloc_max(&sc16is7xx_lines,
SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL); if (ret < 0) goto out_ports;
s->p[i].port.line = ret;
/* Initialize port data */
s->p[i].port.dev = dev;
s->p[i].port.irq = irq;
s->p[i].port.type = PORT_SC16IS7XX;
s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE;
s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
s->p[i].port.iobase = i; /* * Use all ones as membase to make sure uart_configure_port() in * serial_core.c does not abort for SPI/I2C devices where the * membase address is not applicable.
*/
s->p[i].port.membase = (void __iomem *)~0;
s->p[i].port.iotype = UPIO_PORT;
s->p[i].port.uartclk = freq;
s->p[i].port.rs485_config = sc16is7xx_config_rs485;
s->p[i].port.rs485_supported = sc16is7xx_rs485_supported;
s->p[i].port.ops = &sc16is7xx_ops;
s->p[i].old_mctrl = 0;
s->p[i].regmap = regmaps[i];
mutex_init(&s->p[i].efr_lock);
ret = uart_get_rs485_mode(&s->p[i].port); if (ret) goto out_ports;
/* Enable write access to enhanced features */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG,
SC16IS7XX_EFR_ENABLE_BIT);
regcache_cache_bypass(regmaps[i], false);
/* Restore access to general registers */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00);
/* Go to suspend mode */
sc16is7xx_power(&s->p[i].port, 0);
}
sc16is7xx_setup_irda_ports(s);
ret = sc16is7xx_setup_mctrl_ports(s, regmaps[0]); if (ret) goto out_ports;
#ifdef CONFIG_GPIOLIB
ret = sc16is7xx_setup_gpio_chip(s); if (ret) goto out_ports; #endif
if (s->polling) { /* Initialize kernel thread for polling */
kthread_init_delayed_work(&s->poll_work, sc16is7xx_poll_proc); return 0;
}
/* * Setup interrupt. We first try to acquire the IRQ line as level IRQ. * If that succeeds, we can allow sharing the interrupt as well. * In case the interrupt controller doesn't support that, we fall * back to a non-shared falling-edge trigger.
*/
ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq,
IRQF_TRIGGER_LOW | IRQF_SHARED |
IRQF_ONESHOT,
dev_name(dev), s); if (!ret) return 0;
ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(dev), s); if (!ret) return 0;
#ifdef CONFIG_GPIOLIB if (s->gpio_valid_mask)
gpiochip_remove(&s->gpio); #endif
out_ports: for (i = 0; i < devtype->nr_uart; i++) { if (s->p[i].port.line < SC16IS7XX_MAX_DEVS)
ida_free(&sc16is7xx_lines, s->p[i].port.line); if (port_registered[i])
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.