/* ASC_RXBUF */ #define ASC_RXBUF_PE 0x100 #define ASC_RXBUF_FE 0x200 /* * Some of status comes from higher bits of the character and some come from * the status register. Combining both of them in to single status using dummy * bits.
*/ #define ASC_RXBUF_DUMMY_RX 0x10000 #define ASC_RXBUF_DUMMY_BE 0x20000 #define ASC_RXBUF_DUMMY_OE 0x40000
/* * Some simple utility functions to enable and disable interrupts. * Note that these need to be called with interrupts disabled.
*/ staticinlinevoid asc_disable_tx_interrupts(struct uart_port *port)
{
u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_THE;
asc_out(port, ASC_INTEN, intenable);
(void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
}
/* * Start transmitting chars. * This is called from both interrupt and task level. * Either way interrupts are disabled.
*/ staticvoid asc_transmit_chars(struct uart_port *port)
{
u8 ch;
/* * Datasheet states: If the MODE field selects an 8-bit frame then * this [parity error] bit is undefined. Software should ignore this * bit when reading 8-bit frames.
*/
mode = asc_in(port, ASC_CTL) & ASC_CTL_MODE_MSK; if (mode == ASC_CTL_MODE_8BIT || mode == ASC_CTL_MODE_8BIT_PAR)
ignore_pe = true;
if (irqd_is_wakeup_set(irq_get_irq_data(port->irq)))
pm_wakeup_event(tport->tty->dev, 0);
while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) {
c = asc_in(port, ASC_RXBUF) | ASC_RXBUF_DUMMY_RX;
flag = TTY_NORMAL;
port->icount.rx++;
if (status & ASC_STA_OE || c & ASC_RXBUF_FE ||
(c & ASC_RXBUF_PE && !ignore_pe)) {
if (c & ASC_RXBUF_FE) { if (c == (ASC_RXBUF_FE | ASC_RXBUF_DUMMY_RX)) {
port->icount.brk++; if (uart_handle_break(port)) continue;
c |= ASC_RXBUF_DUMMY_BE;
} else {
port->icount.frame++;
}
} elseif (c & ASC_RXBUF_PE) {
port->icount.parity++;
} /* * Reading any data from the RX FIFO clears the * overflow error condition.
*/ if (status & ASC_STA_OE) {
port->icount.overrun++;
c |= ASC_RXBUF_DUMMY_OE;
}
c &= port->read_status_mask;
if (c & ASC_RXBUF_DUMMY_BE)
flag = TTY_BREAK; elseif (c & ASC_RXBUF_PE)
flag = TTY_PARITY; elseif (c & ASC_RXBUF_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, c & 0xff)) continue;
uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag);
}
/* Tell the rest of the system the news. New characters! */
tty_flip_buffer_push(tport);
}
/* * This routine is used for seting signals of: DTR, DCD, CTS and RTS. * We use ASC's hardware for CTS/RTS when hardware flow-control is * enabled, however if the RTS line is required for another purpose, * commonly controlled using HUP from userspace, then we need to toggle * it manually, using GPIO. * * Some boards also have DTR and DCD implemented using PIO pins, code to * do this should be hooked in here.
*/
if (!ascport->rts) return;
/* If HW flow-control is enabled, we can't fiddle with the RTS line */ if (asc_in(port, ASC_CTL) & ASC_CTL_CTSENABLE) return;
staticunsignedint asc_get_mctrl(struct uart_port *port)
{ /* * This routine is used for geting signals of: DTR, DCD, DSR, RI, * and CTS/RTS
*/ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
/* There are probably characters waiting to be transmitted. */ staticvoid asc_start_tx(struct uart_port *port)
{ struct tty_port *tport = &port->state->port;
if (!kfifo_is_empty(&tport->xmit_fifo))
asc_enable_tx_interrupts(port);
}
switch (state) { case UART_PM_STATE_ON:
clk_prepare_enable(ascport->clk); break; case UART_PM_STATE_OFF: /* * Disable the ASC baud rate generator, which is as close as * we can come to turning it off. Note this is not called with * the port spinlock held.
*/
uart_port_lock_irqsave(port, &flags);
ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN;
asc_out(port, ASC_CTL, ctl);
uart_port_unlock_irqrestore(port, flags);
clk_disable_unprepare(ascport->clk); break;
}
}
/* * Called when the port is opened, and UPF_BOOT_AUTOCONF flag is set * Set type field if successful
*/ staticvoid asc_config_port(struct uart_port *port, int flags)
{ if ((flags & UART_CONFIG_TYPE))
port->type = PORT_ASC;
}
staticint
asc_verify_port(struct uart_port *port, struct serial_struct *ser)
{ /* No user changeable parameters */ return -EINVAL;
}
#ifdef CONFIG_CONSOLE_POLL /* * Console polling routines for writing and reading from the uart while * in an interrupt or debug context (i.e. kgdb).
*/
if (WARN_ON(IS_ERR(ascport->clk))) return -EINVAL; /* ensure that clk rate is correct by enabling the clk */
ret = clk_prepare_enable(ascport->clk); if (ret) return ret;
ascport->port.uartclk = clk_get_rate(ascport->clk);
WARN_ON(ascport->port.uartclk == 0);
clk_disable_unprepare(ascport->clk);
ascport->pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR(ascport->pinctrl)) {
ret = PTR_ERR(ascport->pinctrl);
dev_err(&pdev->dev, "Failed to get Pinctrl: %d\n", ret); return ret;
}
ascport->states[DEFAULT] =
pinctrl_lookup_state(ascport->pinctrl, "default"); if (IS_ERR(ascport->states[DEFAULT])) {
ret = PTR_ERR(ascport->states[DEFAULT]);
dev_err(&pdev->dev, "Failed to look up Pinctrl state 'default': %d\n", ret); return ret;
}
/* "no-hw-flowctrl" state is optional */
ascport->states[NO_HW_FLOWCTRL] =
pinctrl_lookup_state(ascport->pinctrl, "no-hw-flowctrl"); if (IS_ERR(ascport->states[NO_HW_FLOWCTRL]))
ascport->states[NO_HW_FLOWCTRL] = NULL;
if (port->sysrq)
locked = 0; /* asc_interrupt has already claimed the lock */ elseif (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags); else
uart_port_lock_irqsave(port, &flags);
/* * Disable interrupts so we don't get the IRQ line bouncing * up and down while interrupts are disabled.
*/
intenable = asc_in(port, ASC_INTEN);
asc_out(port, ASC_INTEN, 0);
(void)asc_in(port, ASC_INTEN); /* Defeat bus write posting */
while (--timeout && !asc_txfifo_is_empty(port))
udelay(1);
asc_out(port, ASC_INTEN, intenable);
if (locked)
uart_port_unlock_irqrestore(port, flags);
}
staticint asc_console_setup(struct console *co, char *options)
{ struct asc_port *ascport; int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n';
if (co->index >= ASC_MAX_PORTS) return -ENODEV;
ascport = &asc_ports[co->index];
/* * This driver does not support early console initialization * (use ARM early printk support instead), so we only expect * this to be called during the uart port registration when the * driver gets probed and the port should be mapped at that point.
*/ if (ascport->port.mapbase == 0 || ascport->port.membase == NULL) return -ENXIO;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
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.