diff options
Diffstat (limited to 'drivers/tty/serial/atmel_serial.c')
| -rw-r--r-- | drivers/tty/serial/atmel_serial.c | 816 |
1 files changed, 397 insertions, 419 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 05147fe24343..08dd8f887956 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -8,34 +8,32 @@ * * DMA support added by Chip Coldwell. */ +#include <linux/circ_buf.h> #include <linux/tty.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/serial.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/console.h> #include <linux/sysrq.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> #include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/atmel_pdc.h> #include <linux/uaccess.h> #include <linux/platform_data/atmel.h> #include <linux/timer.h> -#include <linux/gpio.h> -#include <linux/gpio/consumer.h> #include <linux/err.h> #include <linux/irq.h> #include <linux/suspend.h> #include <linux/mm.h> +#include <linux/io.h> #include <asm/div64.h> -#include <asm/io.h> #include <asm/ioctls.h> #define PDC_BUFFER_SIZE 512 @@ -51,10 +49,6 @@ #define ATMEL_RTS_HIGH_OFFSET 16 #define ATMEL_RTS_LOW_OFFSET 20 -#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/serial_core.h> #include "serial_mctrl_gpio.h" @@ -102,7 +96,9 @@ struct atmel_uart_char { * can contain up to 1024 characters in PIO mode and up to 4096 characters in * DMA mode. */ -#define ATMEL_SERIAL_RINGSIZE 1024 +#define ATMEL_SERIAL_RINGSIZE 1024 +#define ATMEL_SERIAL_RX_SIZE array_size(sizeof(struct atmel_uart_char), \ + ATMEL_SERIAL_RINGSIZE) /* * at91: 6 USARTs and one DBGU port (SAM9260) @@ -116,6 +112,7 @@ struct atmel_uart_char { struct atmel_uart_port { struct uart_port uart; /* uart */ struct clk *clk; /* uart clock */ + struct clk *gclk; /* uart generic clock */ int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */ u32 backup_imr; /* IMR saved during suspend */ int break_active; /* break being received */ @@ -137,8 +134,8 @@ struct atmel_uart_port { struct dma_async_tx_descriptor *desc_rx; dma_cookie_t cookie_tx; dma_cookie_t cookie_rx; - struct scatterlist sg_tx; - struct scatterlist sg_rx; + dma_addr_t tx_phys; + dma_addr_t rx_phys; struct tasklet_struct tasklet_rx; struct tasklet_struct tasklet_tx; atomic_t tasklet_shutdown; @@ -156,6 +153,7 @@ struct atmel_uart_port { u32 rts_low; bool ms_irq_enabled; u32 rtor; /* address of receiver timeout register if it exists */ + bool is_usart; bool has_frac_baudrate; bool has_hw_timer; struct timer_list uart_timer; @@ -166,11 +164,12 @@ struct atmel_uart_port { unsigned int pending_status; spinlock_t lock_suspended; + bool hd_start_rx; /* can start RX during half-duplex operation */ + /* ISO7816 */ unsigned int fidi_min; unsigned int fidi_max; -#ifdef CONFIG_PM struct { u32 cr; u32 mr; @@ -181,7 +180,6 @@ struct atmel_uart_port { u32 fmr; u32 fimr; } cache; -#endif int (*prepare_rx)(struct uart_port *port); int (*prepare_tx)(struct uart_port *port); @@ -194,10 +192,6 @@ struct atmel_uart_port { static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART); -#ifdef SUPPORT_SYSRQ -static struct console atmel_console; -#endif - #if defined(CONFIG_OF) static const struct of_device_id atmel_serial_dt_ids[] = { { .compatible = "atmel,at91rm9200-usart-serial" }, @@ -231,6 +225,18 @@ static inline void atmel_uart_write_char(struct uart_port *port, u8 value) __raw_writeb(value, port->membase + ATMEL_US_THR); } +static inline int atmel_uart_is_half_duplex(struct uart_port *port) +{ + return ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || + (port->iso7816.flags & SER_ISO7816_ENABLED); +} + +static inline int atmel_error_rate(int desired_value, int actual_value) +{ + return 100 - (desired_value * 100) / actual_value; +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -285,52 +291,8 @@ static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port, tasklet_schedule(t); } -static unsigned int atmel_get_lines_status(struct uart_port *port) -{ - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status, ret = 0; - - status = atmel_uart_readl(port, ATMEL_US_CSR); - - mctrl_gpio_get(atmel_port->gpios, &ret); - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_CTS))) { - if (ret & TIOCM_CTS) - status &= ~ATMEL_US_CTS; - else - status |= ATMEL_US_CTS; - } - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_DSR))) { - if (ret & TIOCM_DSR) - status &= ~ATMEL_US_DSR; - else - status |= ATMEL_US_DSR; - } - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_RI))) { - if (ret & TIOCM_RI) - status &= ~ATMEL_US_RI; - else - status |= ATMEL_US_RI; - } - - if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios, - UART_GPIO_DCD))) { - if (ret & TIOCM_CD) - status &= ~ATMEL_US_DCD; - else - status |= ATMEL_US_DCD; - } - - return status; -} - /* Enable or disable the rs485 support */ -static int atmel_config_rs485(struct uart_port *port, +static int atmel_config_rs485(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); @@ -341,16 +303,16 @@ static int atmel_config_rs485(struct uart_port *port, mode = atmel_uart_readl(port, ATMEL_US_MR); - /* Resetting serial mode to RS232 (0x0) */ - mode &= ~ATMEL_US_USMODE; - - port->rs485 = *rs485conf; - if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); - atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; + if (rs485conf->flags & SER_RS485_RX_DURING_TX) + atmel_port->tx_done_mask = ATMEL_US_TXRDY; + else + atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; + atmel_uart_writel(port, ATMEL_US_TTGR, rs485conf->delay_rts_after_send); + mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -591,27 +553,30 @@ static u_int atmel_get_mctrl(struct uart_port *port) static void atmel_stop_tx(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + bool is_pdc = atmel_use_pdc_tx(port); + bool is_dma = is_pdc || atmel_use_dma_tx(port); - if (atmel_use_pdc_tx(port)) { + if (is_pdc) { /* disable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); } - /* - * Disable the transmitter. - * This is mandatory when DMA is used, otherwise the DMA buffer - * is fully transmitted. - */ - atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS); - atmel_port->tx_stopped = true; + if (is_dma) { + /* + * Disable the transmitter. + * This is mandatory when DMA is used, otherwise the DMA buffer + * is fully transmitted. + */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS); + atmel_port->tx_stopped = true; + } /* Disable interrupts */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) - atmel_start_rx(port); + if (atmel_uart_is_half_duplex(port)) + if (!atomic_read(&atmel_port->tasklet_shutdown)) + atmel_start_rx(port); } /* @@ -620,29 +585,31 @@ static void atmel_stop_tx(struct uart_port *port) static void atmel_start_tx(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + bool is_pdc = atmel_use_pdc_tx(port); + bool is_dma = is_pdc || atmel_use_dma_tx(port); - if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR) + if (is_pdc && (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN)) /* The transmitter is already running. Yes, we really need this.*/ return; - if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) - if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) - atmel_stop_rx(port); + if (is_dma && atmel_uart_is_half_duplex(port)) + atmel_stop_rx(port); - if (atmel_use_pdc_tx(port)) + if (is_pdc) { /* re-enable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); + } /* Enable interrupts */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); - /* re-enable the transmitter */ - atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); - atmel_port->tx_stopped = false; + if (is_dma) { + /* re-enable the transmitter */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); + atmel_port->tx_stopped = false; + } } /* @@ -733,7 +700,7 @@ static void atmel_disable_ms(struct uart_port *port) atmel_port->ms_irq_enabled = false; - mctrl_gpio_disable_ms(atmel_port->gpios); + mctrl_gpio_disable_ms_no_sync(atmel_port->gpios); if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) idr |= ATMEL_US_CTSIC; @@ -865,77 +832,70 @@ static void atmel_rx_chars(struct uart_port *port) */ static void atmel_tx_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->state->xmit; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + bool pending; + u8 ch; + + pending = uart_port_tx(port, ch, + atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY, + atmel_uart_write_char(port, ch)); + if (pending) { + /* we still have characters to transmit, so we should continue + * transmitting them when TX is ready, regardless of + * mode or duplexity + */ + atmel_port->tx_done_mask |= ATMEL_US_TXRDY; - if (port->x_char && - (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { - atmel_uart_write_char(port, port->x_char); - port->icount.tx++; - port->x_char = 0; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; - - while (atmel_uart_readl(port, ATMEL_US_CSR) & - atmel_port->tx_done_mask) { - atmel_uart_write_char(port, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!uart_circ_empty(xmit)) /* Enable interrupts */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); + } else { + if (atmel_uart_is_half_duplex(port)) + atmel_port->tx_done_mask &= ~ATMEL_US_TXRDY; + } } static void atmel_complete_tx_dma(void *arg) { struct atmel_uart_port *atmel_port = arg; struct uart_port *port = &atmel_port->uart; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_chan *chan = atmel_port->chan_tx; unsigned long flags; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); if (chan) dmaengine_terminate_all(chan); - xmit->tail += atmel_port->tx_len; - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += atmel_port->tx_len; + uart_xmit_advance(port, atmel_port->tx_len); - spin_lock_irq(&atmel_port->lock_tx); + spin_lock(&atmel_port->lock_tx); async_tx_ack(atmel_port->desc_tx); atmel_port->cookie_tx = -EINVAL; atmel_port->desc_tx = NULL; - spin_unlock_irq(&atmel_port->lock_tx); + spin_unlock(&atmel_port->lock_tx); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* - * xmit is a circular buffer so, if we have just send data from - * xmit->tail to the end of xmit->buf, now we have to transmit the - * remaining data from the beginning of xmit->buf to xmit->head. + * xmit is a circular buffer so, if we have just send data from the + * tail to the end, now we have to transmit the remaining data from the + * beginning to the head. */ - if (!uart_circ_empty(xmit)) + if (!kfifo_is_empty(&tport->xmit_fifo)) atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); - else if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) { - /* DMA done, stop TX, start RX for RS485 */ - atmel_start_rx(port); + else if (atmel_uart_is_half_duplex(port)) { + /* + * DMA done, re-enable TXEMPTY and signal that we can stop + * TX and start RX for RS485 + */ + atmel_port->hd_start_rx = true; + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void atmel_release_tx_dma(struct uart_port *port) @@ -946,8 +906,8 @@ static void atmel_release_tx_dma(struct uart_port *port) if (chan) { dmaengine_terminate_all(chan); dma_release_channel(chan); - dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1, - DMA_TO_DEVICE); + dma_unmap_single(port->dev, atmel_port->tx_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); } atmel_port->desc_tx = NULL; @@ -961,18 +921,18 @@ static void atmel_release_tx_dma(struct uart_port *port) static void atmel_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct dma_chan *chan = atmel_port->chan_tx; struct dma_async_tx_descriptor *desc; - struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; - unsigned int tx_len, part1_len, part2_len, sg_len; + struct scatterlist sgl[2], *sg; + unsigned int tx_len, tail, part1_len, part2_len, sg_len; dma_addr_t phys_addr; /* Make sure we have an idle channel */ if (atmel_port->desc_tx != NULL) return; - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) { /* * DMA is idle now. * Port xmit buffer is already mapped, @@ -982,9 +942,8 @@ static void atmel_tx_dma(struct uart_port *port) * Take the port lock to get a * consistent xmit buffer state. */ - tx_len = CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE); + tx_len = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); if (atmel_port->fifo_size) { /* multi data mode */ @@ -998,7 +957,7 @@ static void atmel_tx_dma(struct uart_port *port) sg_init_table(sgl, 2); sg_len = 0; - phys_addr = sg_dma_address(sg_tx) + xmit->tail; + phys_addr = atmel_port->tx_phys + tail; if (part1_len) { sg = &sgl[sg_len++]; sg_dma_address(sg) = phys_addr; @@ -1015,7 +974,7 @@ static void atmel_tx_dma(struct uart_port *port) /* * save tx_len so atmel_complete_tx_dma() will increase - * xmit->tail correctly + * tail correctly */ atmel_port->tx_len = tx_len; @@ -1030,56 +989,61 @@ static void atmel_tx_dma(struct uart_port *port) return; } - dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE); + dma_sync_single_for_device(port->dev, atmel_port->tx_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); atmel_port->desc_tx = desc; desc->callback = atmel_complete_tx_dma; desc->callback_param = atmel_port; atmel_port->cookie_tx = dmaengine_submit(desc); + if (dma_submit_error(atmel_port->cookie_tx)) { + dev_err(port->dev, "dma_submit_error %d\n", + atmel_port->cookie_tx); + return; + } + + dma_async_issue_pending(chan); } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } static int atmel_prepare_tx_dma(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_port *tport = &port->state->port; struct device *mfd_dev = port->dev->parent; dma_cap_mask_t mask; struct dma_slave_config config; - int ret, nent; + struct dma_chan *chan; + int ret; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx"); - if (atmel_port->chan_tx == NULL) + chan = dma_request_chan(mfd_dev, "tx"); + if (IS_ERR(chan)) { + atmel_port->chan_tx = NULL; goto chan_err; + } + atmel_port->chan_tx = chan; dev_info(port->dev, "using %s for tx DMA transfers\n", dma_chan_name(atmel_port->chan_tx)); spin_lock_init(&atmel_port->lock_tx); - sg_init_table(&atmel_port->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ - BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf)); - sg_set_page(&atmel_port->sg_tx, - virt_to_page(port->state->xmit.buf), - UART_XMIT_SIZE, - offset_in_page(port->state->xmit.buf)); - nent = dma_map_sg(port->dev, - &atmel_port->sg_tx, - 1, - DMA_TO_DEVICE); - - if (!nent) { + BUG_ON(!PAGE_ALIGNED(tport->xmit_buf)); + atmel_port->tx_phys = dma_map_single(port->dev, tport->xmit_buf, + UART_XMIT_SIZE, DMA_TO_DEVICE); + + if (dma_mapping_error(port->dev, atmel_port->tx_phys)) { dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, - sg_dma_len(&atmel_port->sg_tx), - port->state->xmit.buf, - &sg_dma_address(&atmel_port->sg_tx)); + dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", __func__, + UART_XMIT_SIZE, tport->xmit_buf, + &atmel_port->tx_phys); } /* Configure the slave DMA */ @@ -1102,7 +1066,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) chan_err: dev_err(port->dev, "TX channel not available, switch to pio\n"); - atmel_port->use_dma_tx = 0; + atmel_port->use_dma_tx = false; if (atmel_port->chan_tx) atmel_release_tx_dma(port); return -EINVAL; @@ -1124,8 +1088,8 @@ static void atmel_release_rx_dma(struct uart_port *port) if (chan) { dmaengine_terminate_all(chan); dma_release_channel(chan); - dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1, - DMA_FROM_DEVICE); + dma_unmap_single(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); } atmel_port->desc_rx = NULL; @@ -1158,10 +1122,8 @@ static void atmel_rx_from_dma(struct uart_port *port) } /* CPU claims ownership of RX DMA buffer */ - dma_sync_sg_for_cpu(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); /* * ring->head points to the end of data already written by the DMA. @@ -1170,8 +1132,8 @@ static void atmel_rx_from_dma(struct uart_port *port) * The current transfer size should not be larger than the dma buffer * length. */ - ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue; - BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx)); + ring->head = ATMEL_SERIAL_RX_SIZE - state.residue; + BUG_ON(ring->head > ATMEL_SERIAL_RX_SIZE); /* * At this point ring->head may point to the first byte right after the * last byte of the dma buffer: @@ -1185,7 +1147,7 @@ static void atmel_rx_from_dma(struct uart_port *port) * tail to the end of the buffer then reset tail. */ if (ring->head < ring->tail) { - count = sg_dma_len(&atmel_port->sg_rx) - ring->tail; + count = ATMEL_SERIAL_RX_SIZE - ring->tail; tty_insert_flip_string(tport, ring->buf + ring->tail, count); ring->tail = 0; @@ -1198,25 +1160,17 @@ static void atmel_rx_from_dma(struct uart_port *port) tty_insert_flip_string(tport, ring->buf + ring->tail, count); /* Wrap ring->head if needed */ - if (ring->head >= sg_dma_len(&atmel_port->sg_rx)) + if (ring->head >= ATMEL_SERIAL_RX_SIZE) ring->head = 0; ring->tail = ring->head; port->icount.rx += count; } - /* USART retreives ownership of RX DMA buffer */ - dma_sync_sg_for_device(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); + /* USART retrieves ownership of RX DMA buffer */ + dma_sync_single_for_device(port->dev, atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); } @@ -1229,40 +1183,36 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dma_cap_mask_t mask; struct dma_slave_config config; struct circ_buf *ring; - int ret, nent; + struct dma_chan *chan; + int ret; ring = &atmel_port->rx_ring; dma_cap_zero(mask); dma_cap_set(DMA_CYCLIC, mask); - atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx"); - if (atmel_port->chan_rx == NULL) + chan = dma_request_chan(mfd_dev, "rx"); + if (IS_ERR(chan)) { + atmel_port->chan_rx = NULL; goto chan_err; + } + atmel_port->chan_rx = chan; dev_info(port->dev, "using %s for rx DMA transfers\n", dma_chan_name(atmel_port->chan_rx)); spin_lock_init(&atmel_port->lock_rx); - sg_init_table(&atmel_port->sg_rx, 1); /* UART circular rx buffer is an aligned page. */ BUG_ON(!PAGE_ALIGNED(ring->buf)); - sg_set_page(&atmel_port->sg_rx, - virt_to_page(ring->buf), - sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, - offset_in_page(ring->buf)); - nent = dma_map_sg(port->dev, - &atmel_port->sg_rx, - 1, - DMA_FROM_DEVICE); - - if (!nent) { + atmel_port->rx_phys = dma_map_single(port->dev, ring->buf, + ATMEL_SERIAL_RX_SIZE, + DMA_FROM_DEVICE); + + if (dma_mapping_error(port->dev, atmel_port->rx_phys)) { dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, - sg_dma_len(&atmel_port->sg_rx), - ring->buf, - &sg_dma_address(&atmel_port->sg_rx)); + dev_dbg(port->dev, "%s: mapped %zu@%p to %pad\n", __func__, + ATMEL_SERIAL_RX_SIZE, ring->buf, &atmel_port->rx_phys); } /* Configure the slave DMA */ @@ -1283,21 +1233,32 @@ static int atmel_prepare_rx_dma(struct uart_port *port) * each one is half ring buffer size */ desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx, - sg_dma_address(&atmel_port->sg_rx), - sg_dma_len(&atmel_port->sg_rx), - sg_dma_len(&atmel_port->sg_rx)/2, + atmel_port->rx_phys, + ATMEL_SERIAL_RX_SIZE, + ATMEL_SERIAL_RX_SIZE / 2, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "Preparing DMA cyclic failed\n"); + goto chan_err; + } desc->callback = atmel_complete_rx_dma; desc->callback_param = port; atmel_port->desc_rx = desc; atmel_port->cookie_rx = dmaengine_submit(desc); + if (dma_submit_error(atmel_port->cookie_rx)) { + dev_err(port->dev, "dma_submit_error %d\n", + atmel_port->cookie_rx); + goto chan_err; + } + + dma_async_issue_pending(atmel_port->chan_rx); return 0; chan_err: dev_err(port->dev, "RX channel not available, switch to pio\n"); - atmel_port->use_dma_rx = 0; + atmel_port->use_dma_rx = false; if (atmel_port->chan_rx) atmel_release_rx_dma(port); return -EINVAL; @@ -1305,8 +1266,8 @@ chan_err: static void atmel_uart_timer_callback(struct timer_list *t) { - struct atmel_uart_port *atmel_port = from_timer(atmel_port, t, - uart_timer); + struct atmel_uart_port *atmel_port = timer_container_of(atmel_port, t, + uart_timer); struct uart_port *port = &atmel_port->uart; if (!atomic_read(&atmel_port->tasklet_shutdown)) { @@ -1376,9 +1337,19 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (pending & atmel_port->tx_done_mask) { - /* Either PDC or interrupt transmission */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); + + /* Start RX if flag was set and FIFO is empty */ + if (atmel_port->hd_start_rx) { + if (!(atmel_uart_readl(port, ATMEL_US_CSR) + & ATMEL_US_TXEMPTY)) + dev_warn(port->dev, "Should start RX, but TX fifo is not empty\n"); + + atmel_port->hd_start_rx = false; + atmel_start_rx(port); + } + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); } } @@ -1430,7 +1401,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) spin_lock(&atmel_port->lock_suspended); do { - status = atmel_get_lines_status(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); mask = atmel_uart_readl(port, ATMEL_US_IMR); pending = status & mask; if (!pending) @@ -1471,18 +1442,13 @@ static void atmel_release_tx_pdc(struct uart_port *port) static void atmel_tx_pdc(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - int count; /* nothing left to transmit? */ if (atmel_uart_readl(port, ATMEL_PDC_TCR)) return; - - xmit->tail += pdc->ofs; - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += pdc->ofs; + uart_xmit_advance(port, pdc->ofs); pdc->ofs = 0; /* more to transmit - setup next transfer */ @@ -1490,17 +1456,19 @@ static void atmel_tx_pdc(struct uart_port *port) /* disable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) { + unsigned int count, tail; + dma_sync_single_for_device(port->dev, pdc->dma_addr, pdc->dma_size, DMA_TO_DEVICE); - count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + count = kfifo_out_linear(&tport->xmit_fifo, &tail, + UART_XMIT_SIZE); pdc->ofs = count; - atmel_uart_writel(port, ATMEL_PDC_TPR, - pdc->dma_addr + xmit->tail); + atmel_uart_writel(port, ATMEL_PDC_TPR, pdc->dma_addr + tail); atmel_uart_writel(port, ATMEL_PDC_TCR, count); /* re-enable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); @@ -1508,15 +1476,13 @@ static void atmel_tx_pdc(struct uart_port *port) atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); } else { - if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) { + if (atmel_uart_is_half_duplex(port)) { /* DMA done, stop TX, start RX for RS485 */ atmel_start_rx(port); } } - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); } @@ -1524,9 +1490,9 @@ static int atmel_prepare_tx_pdc(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; - struct circ_buf *xmit = &port->state->xmit; + struct tty_port *tport = &port->state->port; - pdc->buf = xmit->buf; + pdc->buf = tport->xmit_buf; pdc->dma_addr = dma_map_single(port->dev, pdc->buf, UART_XMIT_SIZE, @@ -1541,8 +1507,8 @@ static void atmel_rx_from_ring(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct circ_buf *ring = &atmel_port->rx_ring; - unsigned int flg; unsigned int status; + u8 flg; while (ring->head != ring->tail) { struct atmel_uart_char c; @@ -1596,13 +1562,7 @@ static void atmel_rx_from_ring(struct uart_port *port) uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); } - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); } static void atmel_release_rx_pdc(struct uart_port *port) @@ -1687,13 +1647,7 @@ static void atmel_rx_from_pdc(struct uart_port *port) } } while (head >= pdc->dma_size); - /* - * Drop the lock here since it might end up calling - * uart_start(), which takes the lock. - */ - spin_unlock(&port->lock); tty_flip_buffer_push(tport); - spin_lock(&port->lock); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); @@ -1716,7 +1670,7 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) DMA_FROM_DEVICE); kfree(atmel_port->pdc_rx[0].buf); } - atmel_port->use_pdc_rx = 0; + atmel_port->use_pdc_rx = false; return -ENOMEM; } pdc->dma_addr = dma_map_single(port->dev, @@ -1742,26 +1696,28 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) /* * tasklet handling tty stuff outside the interrupt handler. */ -static void atmel_tasklet_rx_func(unsigned long data) +static void atmel_tasklet_rx_func(struct tasklet_struct *t) { - struct uart_port *port = (struct uart_port *)data; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, + tasklet_rx); + struct uart_port *port = &atmel_port->uart; /* The interrupt handler does not take the lock */ - spin_lock(&port->lock); + uart_port_lock(port); atmel_port->schedule_rx(port); - spin_unlock(&port->lock); + uart_port_unlock(port); } -static void atmel_tasklet_tx_func(unsigned long data) +static void atmel_tasklet_tx_func(struct tasklet_struct *t) { - struct uart_port *port = (struct uart_port *)data; - struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, + tasklet_tx); + struct uart_port *port = &atmel_port->uart; /* The interrupt handler does not take the lock */ - spin_lock(&port->lock); + uart_port_lock(port); atmel_port->schedule_tx(port); - spin_unlock(&port->lock); + uart_port_unlock(port); } static void atmel_init_property(struct atmel_uart_port *atmel_port, @@ -1771,26 +1727,16 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port, /* DMA/PDC usage specification */ if (of_property_read_bool(np, "atmel,use-dma-rx")) { - if (of_property_read_bool(np, "dmas")) { - atmel_port->use_dma_rx = true; - atmel_port->use_pdc_rx = false; - } else { - atmel_port->use_dma_rx = false; - atmel_port->use_pdc_rx = true; - } + atmel_port->use_dma_rx = of_property_present(np, "dmas"); + atmel_port->use_pdc_rx = !atmel_port->use_dma_rx; } else { atmel_port->use_dma_rx = false; atmel_port->use_pdc_rx = false; } if (of_property_read_bool(np, "atmel,use-dma-tx")) { - if (of_property_read_bool(np, "dmas")) { - atmel_port->use_dma_tx = true; - atmel_port->use_pdc_tx = false; - } else { - atmel_port->use_dma_tx = false; - atmel_port->use_pdc_tx = true; - } + atmel_port->use_dma_tx = of_property_present(np, "dmas"); + atmel_port->use_pdc_tx = !atmel_port->use_dma_tx; } else { atmel_port->use_dma_tx = false; atmel_port->use_pdc_tx = false; @@ -1852,6 +1798,7 @@ static void atmel_get_ip_name(struct uart_port *port) */ atmel_port->has_frac_baudrate = false; atmel_port->has_hw_timer = false; + atmel_port->is_usart = false; if (name == new_uart) { dev_dbg(port->dev, "Uart with hw timer"); @@ -1861,11 +1808,12 @@ static void atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "Usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; + atmel_port->is_usart = true; atmel_port->rtor = ATMEL_US_RTOR; version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { case 0x814: /* sama5d2 */ - /* fall through */ + fallthrough; case 0x701: /* sama5d4 */ atmel_port->fidi_min = 3; atmel_port->fidi_max = 65535; @@ -1890,6 +1838,7 @@ static void atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "This version is usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; + atmel_port->is_usart = true; atmel_port->rtor = ATMEL_US_RTOR; break; case 0x203: @@ -1931,10 +1880,8 @@ static int atmel_startup(struct uart_port *port) } atomic_set(&atmel_port->tasklet_shutdown, 0); - tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func, - (unsigned long)port); - tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func, - (unsigned long)port); + tasklet_setup(&atmel_port->tasklet_rx, atmel_tasklet_rx_func); + tasklet_setup(&atmel_port->tasklet_tx, atmel_tasklet_tx_func); /* * Initialize DMA (if necessary) @@ -1981,7 +1928,7 @@ static int atmel_startup(struct uart_port *port) } /* Save current CSR for comparison in atmel_tasklet_func() */ - atmel_port->irq_status_prev = atmel_get_lines_status(port); + atmel_port->irq_status_prev = atmel_uart_readl(port, ATMEL_US_CSR); /* * Finally, enable the serial port @@ -2070,7 +2017,7 @@ static void atmel_shutdown(struct uart_port *port) * Prevent any tasklets being scheduled during * cleanup */ - del_timer_sync(&atmel_port->uart_timer); + timer_delete_sync(&atmel_port->uart_timer); /* Make sure that no interrupt is on the fly */ synchronize_irq(port->irq); @@ -2122,7 +2069,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); switch (state) { - case 0: + case UART_PM_STATE_ON: /* * Enable the peripheral clock for this serial port. * This is called on uart_open() or a resume event. @@ -2132,7 +2079,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, /* re-enable interrupts if we disabled some on suspend */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); break; - case 3: + case UART_PM_STATE_OFF: /* Back up the interrupt mask and disable all interrupts */ atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); atmel_uart_writel(port, ATMEL_US_IDR, -1); @@ -2142,6 +2089,8 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, * This is called on uart_close() or a suspend event. */ clk_disable_unprepare(atmel_port->clk); + if (__clk_is_enabled(atmel_port->gclk)) + clk_disable_unprepare(atmel_port->gclk); break; default: dev_err(port->dev, "atmel_serial: unknown pm %d\n", state); @@ -2151,19 +2100,25 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, /* * Change the port parameters */ -static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +static void atmel_set_termios(struct uart_port *port, + struct ktermios *termios, + const struct ktermios *old) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; - unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0; + unsigned int old_mode, mode, imr, quot, div, cd, fp = 0; + unsigned int baud, actual_baud, gclk_rate; + int ret; /* save the current mode register */ mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); /* reset the mode, clock divisor, parity, stop bits and data size */ - mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | - ATMEL_US_PAR | ATMEL_US_USMODE); + if (atmel_port->is_usart) + mode &= ~(ATMEL_US_NBSTOP | ATMEL_US_PAR | ATMEL_US_CHRL | + ATMEL_US_USCLKS | ATMEL_US_USMODE); + else + mode &= ~(ATMEL_UA_BRSRCCK | ATMEL_US_PAR | ATMEL_UA_FILTER); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); @@ -2202,7 +2157,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, } else mode |= ATMEL_US_PAR_NONE; - spin_lock_irqsave(&port->lock, flags); + uart_port_lock_irqsave(port, &flags); port->read_status_mask = ATMEL_US_OVRE; if (termios->c_iflag & INPCK) @@ -2293,27 +2248,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, mode |= ATMEL_US_USMODE_NORMAL; } - /* set the mode, clock divisor, parity, stop bits and data size */ - atmel_uart_writel(port, ATMEL_US_MR, mode); - - /* - * when switching the mode, set the RTS line state according to the - * new mode, otherwise keep the former state - */ - if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) { - unsigned int rts_state; - - if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) { - /* let the hardware control the RTS line */ - rts_state = ATMEL_US_RTSDIS; - } else { - /* force RTS line to low level */ - rts_state = ATMEL_US_RTSEN; - } - - atmel_uart_writel(port, ATMEL_US_CR, rts_state); - } - /* * Set the baud rate: * Fractional baudrate allows to setup output frequency more @@ -2332,14 +2266,86 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, cd = uart_get_divisor(port, baud); } - if (cd > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + /* + * If the current value of the Clock Divisor surpasses the 16 bit + * ATMEL_US_CD mask and the IP is USART, switch to the Peripheral + * Clock implicitly divided by 8. + * If the IP is UART however, keep the highest possible value for + * the CD and avoid needless division of CD, since UART IP's do not + * support implicit division of the Peripheral Clock. + */ + if (atmel_port->is_usart && cd > ATMEL_US_CD) { cd /= 8; mode |= ATMEL_US_USCLKS_MCK_DIV8; + } else { + cd = min_t(unsigned int, cd, ATMEL_US_CD); + } + + /* + * If there is no Fractional Part, there is a high chance that + * we may be able to generate a baudrate closer to the desired one + * if we use the GCLK as the clock source driving the baudrate + * generator. + */ + if (!atmel_port->has_frac_baudrate) { + if (__clk_is_enabled(atmel_port->gclk)) + clk_disable_unprepare(atmel_port->gclk); + gclk_rate = clk_round_rate(atmel_port->gclk, 16 * baud); + actual_baud = clk_get_rate(atmel_port->clk) / (16 * cd); + if (gclk_rate && abs(atmel_error_rate(baud, actual_baud)) > + abs(atmel_error_rate(baud, gclk_rate / 16))) { + clk_set_rate(atmel_port->gclk, 16 * baud); + ret = clk_prepare_enable(atmel_port->gclk); + if (ret) + goto gclk_fail; + + if (atmel_port->is_usart) { + mode &= ~ATMEL_US_USCLKS; + mode |= ATMEL_US_USCLKS_GCLK; + } else { + mode |= ATMEL_UA_BRSRCCK; + } + + /* + * Set the Clock Divisor for GCLK to 1. + * Since we were able to generate the smallest + * multiple of the desired baudrate times 16, + * then we surely can generate a bigger multiple + * with the exact error rate for an equally increased + * CD. Thus no need to take into account + * a higher value for CD. + */ + cd = 1; + } } + +gclk_fail: quot = cd | fp << ATMEL_US_FP_OFFSET; if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) atmel_uart_writel(port, ATMEL_US_BRGR, quot); + + /* set the mode, clock divisor, parity, stop bits and data size */ + atmel_uart_writel(port, ATMEL_US_MR, mode); + + /* + * when switching the mode, set the RTS line state according to the + * new mode, otherwise keep the former state + */ + if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) { + unsigned int rts_state; + + if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) { + /* let the hardware control the RTS line */ + rts_state = ATMEL_US_RTSDIS; + } else { + /* force RTS line to low level */ + rts_state = ATMEL_US_RTSEN; + } + + atmel_uart_writel(port, ATMEL_US_CR, rts_state); + } + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); atmel_port->tx_stopped = false; @@ -2353,22 +2359,22 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, else atmel_disable_ms(port); - spin_unlock_irqrestore(&port->lock, flags); + uart_port_unlock_irqrestore(port, flags); } static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios) { if (termios->c_line == N_PPS) { port->flags |= UPF_HARDPPS_CD; - spin_lock_irq(&port->lock); + uart_port_lock_irq(port); atmel_enable_ms(port); - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); } else { port->flags &= ~UPF_HARDPPS_CD; if (!UART_ENABLE_MS(port, termios->c_cflag)) { - spin_lock_irq(&port->lock); + uart_port_lock_irq(port); atmel_disable_ms(port); - spin_unlock_irq(&port->lock); + uart_port_unlock_irq(port); } } } @@ -2403,17 +2409,11 @@ static void atmel_release_port(struct uart_port *port) static int atmel_request_port(struct uart_port *port) { struct platform_device *mpdev = to_platform_device(port->dev->parent); - int size = resource_size(mpdev->resource); - - if (!request_mem_region(port->mapbase, size, "atmel_serial")) - return -EBUSY; if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_mem_region(port->mapbase, size); - return -ENOMEM; - } + port->membase = devm_platform_ioremap_resource(mpdev, 0); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); } return 0; @@ -2497,6 +2497,12 @@ static const struct uart_ops atmel_pops = { #endif }; +static const struct serial_rs485 atmel_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX, + .delay_rts_before_send = 1, + .delay_rts_after_send = 1, +}; + /* * Configure the port from the platform device resource info. */ @@ -2510,46 +2516,31 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, atmel_init_property(atmel_port, pdev); atmel_set_ops(port); - uart_get_rs485_mode(&mpdev->dev, &port->rs485); - port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &atmel_pops; port->fifosize = 1; port->dev = &pdev->dev; port->mapbase = mpdev->resource[0].start; - port->irq = mpdev->resource[1].start; + port->irq = platform_get_irq(mpdev, 0); port->rs485_config = atmel_config_rs485; + port->rs485_supported = atmel_rs485_supported; port->iso7816_config = atmel_config_iso7816; port->membase = NULL; memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); - /* for console, the clock could already be configured */ - if (!atmel_port->clk) { - atmel_port->clk = clk_get(&mpdev->dev, "usart"); - if (IS_ERR(atmel_port->clk)) { - ret = PTR_ERR(atmel_port->clk); - atmel_port->clk = NULL; - return ret; - } - ret = clk_prepare_enable(atmel_port->clk); - if (ret) { - clk_put(atmel_port->clk); - atmel_port->clk = NULL; - return ret; - } - port->uartclk = clk_get_rate(atmel_port->clk); - clk_disable_unprepare(atmel_port->clk); - /* only enable clock when USART is in use */ - } + ret = uart_get_rs485_mode(port); + if (ret) + return ret; + + port->uartclk = clk_get_rate(atmel_port->clk); /* * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or * ENDTX|TXBUFE */ - if (port->rs485.flags & SER_RS485_ENABLED || - port->iso7816.flags & SER_ISO7816_ENABLED) + if (atmel_uart_is_half_duplex(port)) atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; else if (atmel_use_pdc_tx(port)) { port->fifosize = PDC_BUFFER_SIZE; @@ -2562,7 +2553,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, } #ifdef CONFIG_SERIAL_ATMEL_CONSOLE -static void atmel_console_putchar(struct uart_port *port, int ch) +static void atmel_console_putchar(struct uart_port *port, unsigned char ch) { while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); @@ -2641,18 +2632,11 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, else if (mr == ATMEL_US_PAR_ODD) *parity = 'o'; - /* - * The serial core only rounds down when matching this to a - * supported baud rate. Make sure we don't end up slightly - * lower than one of those, as it would make us fall through - * to a much lower baud rate than we really want. - */ - *baud = port->uartclk / (16 * (quot - 1)); + *baud = port->uartclk / (16 * quot); } static int __init atmel_console_setup(struct console *co, char *options) { - int ret; struct uart_port *port = &atmel_ports[co->index].uart; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int baud = 115200; @@ -2665,10 +2649,6 @@ static int __init atmel_console_setup(struct console *co, char *options) return -ENODEV; } - ret = clk_prepare_enable(atmel_ports[co->index].clk); - if (ret) - return ret; - atmel_uart_writel(port, ATMEL_US_IDR, -1); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); @@ -2694,20 +2674,34 @@ static struct console atmel_console = { .data = &atmel_uart, }; -#define ATMEL_CONSOLE_DEVICE (&atmel_console) +static void atmel_serial_early_write(struct console *con, const char *s, + unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, atmel_console_putchar); +} -static inline bool atmel_is_console_port(struct uart_port *port) +static int __init atmel_early_console_setup(struct earlycon_device *device, + const char *options) { - return port->cons && port->cons->index == port->line; + if (!device->port.membase) + return -ENODEV; + + device->con->write = atmel_serial_early_write; + + return 0; } +OF_EARLYCON_DECLARE(atmel_serial, "atmel,at91rm9200-usart", + atmel_early_console_setup); +OF_EARLYCON_DECLARE(atmel_serial, "atmel,at91sam9260-usart", + atmel_early_console_setup); + +#define ATMEL_CONSOLE_DEVICE (&atmel_console) + #else #define ATMEL_CONSOLE_DEVICE NULL - -static inline bool atmel_is_console_port(struct uart_port *port) -{ - return false; -} #endif static struct uart_driver atmel_uart = { @@ -2720,7 +2714,6 @@ static struct uart_driver atmel_uart = { .cons = ATMEL_CONSOLE_DEVICE, }; -#ifdef CONFIG_PM static bool atmel_serial_clk_will_stop(void) { #ifdef CONFIG_ARCH_AT91 @@ -2730,20 +2723,19 @@ static bool atmel_serial_clk_will_stop(void) #endif } -static int atmel_serial_suspend(struct platform_device *pdev, - pm_message_t state) +static int __maybe_unused atmel_serial_suspend(struct device *dev) { - struct uart_port *port = platform_get_drvdata(pdev); + struct uart_port *port = dev_get_drvdata(dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (atmel_is_console_port(port) && console_suspend_enabled) { + if (uart_console(port) && console_suspend_enabled) { /* Drain the TX shifter */ while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY)) cpu_relax(); } - if (atmel_is_console_port(port) && !console_suspend_enabled) { + if (uart_console(port) && !console_suspend_enabled) { /* Cache register values as we won't get a full shutdown/startup * cycle */ @@ -2758,14 +2750,14 @@ static int atmel_serial_suspend(struct platform_device *pdev, } /* we can not wake up if we're running on slow clock */ - atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); + atmel_port->may_wakeup = device_may_wakeup(dev); if (atmel_serial_clk_will_stop()) { unsigned long flags; spin_lock_irqsave(&atmel_port->lock_suspended, flags); atmel_port->suspended = true; spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); - device_set_wakeup_enable(&pdev->dev, 0); + device_set_wakeup_enable(dev, 0); } uart_suspend_port(&atmel_uart, port); @@ -2773,13 +2765,13 @@ static int atmel_serial_suspend(struct platform_device *pdev, return 0; } -static int atmel_serial_resume(struct platform_device *pdev) +static int __maybe_unused atmel_serial_resume(struct device *dev) { - struct uart_port *port = platform_get_drvdata(pdev); + struct uart_port *port = dev_get_drvdata(dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned long flags; - if (atmel_is_console_port(port) && !console_suspend_enabled) { + if (uart_console(port) && !console_suspend_enabled) { atmel_uart_writel(port, ATMEL_US_MR, atmel_port->cache.mr); atmel_uart_writel(port, ATMEL_US_IER, atmel_port->cache.imr); atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->cache.brgr); @@ -2810,14 +2802,10 @@ static int atmel_serial_resume(struct platform_device *pdev) spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); uart_resume_port(&atmel_uart, port); - device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); + device_set_wakeup_enable(dev, atmel_port->may_wakeup); return 0; } -#else -#define atmel_serial_suspend NULL -#define atmel_serial_resume NULL -#endif static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, struct platform_device *pdev) @@ -2866,7 +2854,7 @@ static int atmel_serial_probe(struct platform_device *pdev) struct atmel_uart_port *atmel_port; struct device_node *np = pdev->dev.parent->of_node; void *data; - int ret = -ENODEV; + int ret; bool rs485_enabled; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); @@ -2900,28 +2888,42 @@ static int atmel_serial_probe(struct platform_device *pdev) atmel_port = &atmel_ports[ret]; atmel_port->backup_imr = 0; atmel_port->uart.line = ret; + atmel_port->uart.has_sysrq = IS_ENABLED(CONFIG_SERIAL_ATMEL_CONSOLE); atmel_serial_probe_fifos(atmel_port, pdev); atomic_set(&atmel_port->tasklet_shutdown, 0); spin_lock_init(&atmel_port->lock_suspended); + atmel_port->clk = devm_clk_get(&pdev->dev, "usart"); + if (IS_ERR(atmel_port->clk)) { + ret = PTR_ERR(atmel_port->clk); + goto err; + } + ret = clk_prepare_enable(atmel_port->clk); + if (ret) + goto err; + + atmel_port->gclk = devm_clk_get_optional(&pdev->dev, "gclk"); + if (IS_ERR(atmel_port->gclk)) { + ret = PTR_ERR(atmel_port->gclk); + goto err_clk_disable_unprepare; + } + ret = atmel_init_port(atmel_port, pdev); if (ret) - goto err_clear_bit; + goto err_clk_disable_unprepare; atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0); if (IS_ERR(atmel_port->gpios)) { ret = PTR_ERR(atmel_port->gpios); - goto err_clear_bit; + goto err_clk_disable_unprepare; } if (!atmel_use_pdc_rx(&atmel_port->uart)) { ret = -ENOMEM; - data = kmalloc_array(ATMEL_SERIAL_RINGSIZE, - sizeof(struct atmel_uart_char), - GFP_KERNEL); + data = kmalloc(ATMEL_SERIAL_RX_SIZE, GFP_KERNEL); if (!data) - goto err_alloc_ring; + goto err_clk_disable_unprepare; atmel_port->rx_ring.buf = data; } @@ -2931,26 +2933,9 @@ static int atmel_serial_probe(struct platform_device *pdev) if (ret) goto err_add_port; -#ifdef CONFIG_SERIAL_ATMEL_CONSOLE - if (atmel_is_console_port(&atmel_port->uart) - && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { - /* - * The serial core enabled the clock for us, so undo - * the clk_prepare_enable() in atmel_console_setup() - */ - clk_disable_unprepare(atmel_port->clk); - } -#endif - device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, atmel_port); - /* - * The peripheral clock has been disabled by atmel_init_port(): - * enable it before accessing I/O registers - */ - clk_prepare_enable(atmel_port->clk); - if (rs485_enabled) { atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR, ATMEL_US_USMODE_NORMAL); @@ -2974,12 +2959,8 @@ static int atmel_serial_probe(struct platform_device *pdev) err_add_port: kfree(atmel_port->rx_ring.buf); atmel_port->rx_ring.buf = NULL; -err_alloc_ring: - if (!atmel_is_console_port(&atmel_port->uart)) { - clk_put(atmel_port->clk); - atmel_port->clk = NULL; - } -err_clear_bit: +err_clk_disable_unprepare: + clk_disable_unprepare(atmel_port->clk); clear_bit(atmel_port->uart.line, atmel_ports_in_use); err: return ret; @@ -2994,18 +2975,17 @@ err: * protocol that needs bitbanging on IO lines, but use the regular serial * port in the normal case. */ -static int atmel_serial_remove(struct platform_device *pdev) +static void atmel_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - int ret = 0; tasklet_kill(&atmel_port->tasklet_rx); tasklet_kill(&atmel_port->tasklet_tx); device_init_wakeup(&pdev->dev, 0); - ret = uart_remove_one_port(&atmel_uart, port); + uart_remove_one_port(&atmel_uart, port); kfree(atmel_port->rx_ring.buf); @@ -3013,21 +2993,19 @@ static int atmel_serial_remove(struct platform_device *pdev) clear_bit(port->line, atmel_ports_in_use); - clk_put(atmel_port->clk); - atmel_port->clk = NULL; pdev->dev.of_node = NULL; - - return ret; } +static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend, + atmel_serial_resume); + static struct platform_driver atmel_serial_driver = { .probe = atmel_serial_probe, .remove = atmel_serial_remove, - .suspend = atmel_serial_suspend, - .resume = atmel_serial_resume, .driver = { .name = "atmel_usart_serial", .of_match_table = of_match_ptr(atmel_serial_dt_ids), + .pm = pm_ptr(&atmel_serial_pm_ops), }, }; |
