/* pic32_sport pointer for console use */ staticstruct pic32_sport *pic32_sports[PIC32_MAX_UARTS];
staticinlinevoid pic32_wait_deplete_txbuf(struct pic32_sport *sport)
{ /* wait for tx empty, otherwise chars will be lost or corrupted */ while (!(pic32_uart_readl(sport, PIC32_UART_STA) & PIC32_UART_STA_TRMT))
udelay(1);
}
/* serial core request to check if uart tx buffer is empty */ staticunsignedint pic32_uart_tx_empty(struct uart_port *port)
{ struct pic32_sport *sport = to_pic32_sport(port);
u32 val = pic32_uart_readl(sport, PIC32_UART_STA);
return (val & PIC32_UART_STA_TRMT) ? 1 : 0;
}
/* serial core request to set UART outputs */ staticvoid pic32_uart_set_mctrl(struct uart_port *port, unsignedint mctrl)
{ struct pic32_sport *sport = to_pic32_sport(port);
/* set loopback mode */ if (mctrl & TIOCM_LOOP)
pic32_uart_writel(sport, PIC32_SET(PIC32_UART_MODE),
PIC32_UART_MODE_LPBK); else
pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_MODE),
PIC32_UART_MODE_LPBK);
}
/* serial core request to return the state of misc UART input pins */ staticunsignedint pic32_uart_get_mctrl(struct uart_port *port)
{ struct pic32_sport *sport = to_pic32_sport(port); unsignedint mctrl = 0;
/* get the state of CTS input pin for this port */ if (!sport->cts_gpiod)
mctrl |= TIOCM_CTS; elseif (gpiod_get_value(sport->cts_gpiod))
mctrl |= TIOCM_CTS;
/* DSR and CD are not supported in PIC32, so return 1 * RI is not supported in PIC32, so return 0
*/
mctrl |= TIOCM_CD;
mctrl |= TIOCM_DSR;
return mctrl;
}
/* stop tx and start tx are not called in pairs, therefore a flag indicates * the status of irq to control the irq-depth.
*/ staticinlinevoid pic32_uart_irqtxen(struct pic32_sport *sport, u8 en)
{ if (en && !sport->enable_tx_irq) {
enable_irq(sport->irq_tx);
sport->enable_tx_irq = true;
} elseif (!en && sport->enable_tx_irq) { /* use disable_irq_nosync() and not disable_irq() to avoid self * imposed deadlock by not waiting for irq handler to end, * since this callback is called from interrupt context.
*/
disable_irq_nosync(sport->irq_tx);
sport->enable_tx_irq = false;
}
}
/* serial core request to disable tx ASAP (used for flow control) */ staticvoid pic32_uart_stop_tx(struct uart_port *port)
{ struct pic32_sport *sport = to_pic32_sport(port);
if (!(pic32_uart_readl(sport, PIC32_UART_MODE) & PIC32_UART_MODE_ON)) return;
if (!(pic32_uart_readl(sport, PIC32_UART_STA) & PIC32_UART_STA_UTXEN)) return;
/* wait for tx empty */
pic32_wait_deplete_txbuf(sport);
/* serial core request to stop rx, called before port shutdown */ staticvoid pic32_uart_stop_rx(struct uart_port *port)
{ struct pic32_sport *sport = to_pic32_sport(port);
/* receiver Enable bit OFF */
pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA),
PIC32_UART_STA_URXEN);
}
/* serial core request to start/stop emitting break char */ staticvoid pic32_uart_break_ctl(struct uart_port *port, int ctl)
{ struct pic32_sport *sport = to_pic32_sport(port); unsignedlong flags;
uart_port_lock_irqsave(port, &flags);
if (ctl)
pic32_uart_writel(sport, PIC32_SET(PIC32_UART_STA),
PIC32_UART_STA_UTXBRK); else
pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA),
PIC32_UART_STA_UTXBRK);
uart_port_unlock_irqrestore(port, flags);
}
/* get port type in string format */ staticconstchar *pic32_uart_type(struct uart_port *port)
{ return (port->type == PORT_PIC32) ? PIC32_DEV_NAME : NULL;
}
/* read all chars in rx fifo and send them to core */ staticvoid pic32_uart_do_rx(struct uart_port *port)
{ struct pic32_sport *sport = to_pic32_sport(port); struct tty_port *tty; unsignedint max_count;
/* limit number of char read in interrupt, should not be * higher than fifo size anyway since we're much faster than * serial port
*/
max_count = PIC32_UART_RX_FIFO_DEPTH;
uart_port_lock(port);
tty = &port->state->port;
do {
u32 sta_reg, c; char flag;
/* get overrun/fifo empty information from status register */
sta_reg = pic32_uart_readl(sport, PIC32_UART_STA); if (unlikely(sta_reg & PIC32_UART_STA_OERR)) {
/* fifo reset is required to clear interrupt */
pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA),
PIC32_UART_STA_OERR);
/* Can at least one more character can be read? */ if (!(sta_reg & PIC32_UART_STA_URXDA)) break;
/* read the character and increment the rx counter */
c = pic32_uart_readl(sport, PIC32_UART_RX);
port->icount.rx++;
flag = TTY_NORMAL;
c &= 0xff;
if (unlikely((sta_reg & PIC32_UART_STA_PERR) ||
(sta_reg & PIC32_UART_STA_FERR))) {
/* do stats first */ if (sta_reg & PIC32_UART_STA_PERR)
port->icount.parity++; if (sta_reg & PIC32_UART_STA_FERR)
port->icount.frame++;
/* update flag wrt read_status_mask */
sta_reg &= port->read_status_mask;
if (sta_reg & PIC32_UART_STA_FERR)
flag = TTY_FRAME; if (sta_reg & PIC32_UART_STA_PERR)
flag = TTY_PARITY;
}
if (uart_handle_sysrq_char(port, c)) continue;
if ((sta_reg & port->ignore_status_mask) == 0)
tty_insert_flip_char(tty, c, flag);
} while (--max_count);
uart_port_unlock(port);
tty_flip_buffer_push(tty);
}
/* fill tx fifo with chars to send, stop when fifo is about to be full * or when all chars have been sent.
*/ staticvoid pic32_uart_do_tx(struct uart_port *port)
{ struct pic32_sport *sport = to_pic32_sport(port); struct tty_port *tport = &port->state->port; unsignedint max_count = PIC32_UART_TX_FIFO_DEPTH;
if (uart_tx_stopped(port)) {
pic32_uart_stop_tx(port); return;
}
if (kfifo_is_empty(&tport->xmit_fifo)) goto txq_empty;
/* keep stuffing chars into uart tx buffer * 1) until uart fifo is full * or * 2) until the circ buffer is empty * (all chars have been sent) * or * 3) until the max count is reached * (prevents lingering here for too long in certain cases)
*/ while (!(PIC32_UART_STA_UTXBF &
pic32_uart_readl(sport, PIC32_UART_STA))) { unsignedchar c;
if (!uart_fifo_get(port, &c)) break;
pic32_uart_writel(sport, PIC32_UART_TX, c);
if (--max_count == 0) break;
}
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (kfifo_is_empty(&tport->xmit_fifo)) goto txq_empty;
/* serial core request to initialize uart and start rx operation */ staticint pic32_uart_startup(struct uart_port *port)
{ struct pic32_sport *sport = to_pic32_sport(port);
u32 dflt_baud = (port->uartclk / PIC32_UART_DFLT_BRATE / 16) - 1; unsignedlong flags; int ret;
local_irq_save(flags);
ret = clk_prepare_enable(sport->clk); if (ret) {
local_irq_restore(flags); goto out_done;
}
/* clear status and mode registers */
pic32_uart_writel(sport, PIC32_UART_MODE, 0);
pic32_uart_writel(sport, PIC32_UART_STA, 0);
/* disable uart and mask all interrupts */
pic32_uart_dsbl_and_mask(port);
/* set default baud */
pic32_uart_writel(sport, PIC32_UART_BRG, dflt_baud);
local_irq_restore(flags);
/* Each UART of a PIC32 has three interrupts therefore, * we setup driver to register the 3 irqs for the device. * * For each irq request_irq() is called with interrupt disabled. * And the irq is enabled as soon as we are ready to handle them.
*/
sport->enable_tx_irq = false;
/* serial core request to do any port required auto-configuration */ staticvoid pic32_uart_config_port(struct uart_port *port, int flags)
{ if (flags & UART_CONFIG_TYPE) { if (pic32_uart_request_port(port)) return;
port->type = PORT_PIC32;
}
}
/* serial core request to check that port information in serinfo are suitable */ staticint pic32_uart_verify_port(struct uart_port *port, struct serial_struct *serinfo)
{ if (port->type != PORT_PIC32) return -EINVAL; if (port->irq != serinfo->irq) return -EINVAL; if (port->iotype != serinfo->io_type) return -EINVAL; if (port->mapbase != (unsignedlong)serinfo->iomem_base) return -EINVAL;
/* call uart helper to deal with \r\n */
uart_console_write(&sport->port, s, count, pic32_console_putchar);
}
/* console core request to setup given console, find matching uart * port and setup it.
*/ staticint pic32_console_setup(struct console *co, char *options)
{ struct pic32_sport *sport; int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n'; int ret = 0;
if (unlikely(co->index < 0 || co->index >= PIC32_MAX_UARTS)) return -ENODEV;
sport = pic32_sports[co->index]; if (!sport) return -ENODEV;
ret = clk_prepare_enable(sport->clk); if (ret) return ret;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
ret = uart_add_one_port(&pic32_uart_driver, port); if (ret) {
port->membase = NULL;
dev_err(port->dev, "%s: uart add port error!\n", __func__); goto err;
}
#ifdef CONFIG_SERIAL_PIC32_CONSOLE if (uart_console_registered(port)) { /* The peripheral clock has been enabled by console_setup, * so disable it till the port is used.
*/
clk_disable_unprepare(sport->clk);
} #endif
ret = uart_register_driver(&pic32_uart_driver); if (ret) {
pr_err("failed to register %s:%d\n",
pic32_uart_driver.driver_name, ret); return ret;
}
ret = platform_driver_register(&pic32_uart_platform_driver); if (ret) {
pr_err("fail to register pic32 uart\n");
uart_unregister_driver(&pic32_uart_driver);
}
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.