18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Atmel AT91 Serial ports 48c2ecf20Sopenharmony_ci * Copyright (C) 2003 Rick Bronson 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. 78c2ecf20Sopenharmony_ci * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * DMA support added by Chip Coldwell. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/tty.h> 128c2ecf20Sopenharmony_ci#include <linux/ioport.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/serial.h> 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <linux/console.h> 188c2ecf20Sopenharmony_ci#include <linux/sysrq.h> 198c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 208c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/of_device.h> 238c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 248c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 258c2ecf20Sopenharmony_ci#include <linux/atmel_pdc.h> 268c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 278c2ecf20Sopenharmony_ci#include <linux/platform_data/atmel.h> 288c2ecf20Sopenharmony_ci#include <linux/timer.h> 298c2ecf20Sopenharmony_ci#include <linux/err.h> 308c2ecf20Sopenharmony_ci#include <linux/irq.h> 318c2ecf20Sopenharmony_ci#include <linux/suspend.h> 328c2ecf20Sopenharmony_ci#include <linux/mm.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <asm/div64.h> 358c2ecf20Sopenharmony_ci#include <asm/io.h> 368c2ecf20Sopenharmony_ci#include <asm/ioctls.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define PDC_BUFFER_SIZE 512 398c2ecf20Sopenharmony_ci/* Revisit: We should calculate this based on the actual port settings */ 408c2ecf20Sopenharmony_ci#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* The minium number of data FIFOs should be able to contain */ 438c2ecf20Sopenharmony_ci#define ATMEL_MIN_FIFO_SIZE 8 448c2ecf20Sopenharmony_ci/* 458c2ecf20Sopenharmony_ci * These two offsets are substracted from the RX FIFO size to define the RTS 468c2ecf20Sopenharmony_ci * high and low thresholds 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci#define ATMEL_RTS_HIGH_OFFSET 16 498c2ecf20Sopenharmony_ci#define ATMEL_RTS_LOW_OFFSET 20 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <linux/serial_core.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include "serial_mctrl_gpio.h" 548c2ecf20Sopenharmony_ci#include "atmel_serial.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void atmel_start_rx(struct uart_port *port); 578c2ecf20Sopenharmony_cistatic void atmel_stop_rx(struct uart_port *port); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_ATMEL_TTYAT 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we 628c2ecf20Sopenharmony_ci * should coexist with the 8250 driver, such as if we have an external 16C550 638c2ecf20Sopenharmony_ci * UART. */ 648c2ecf20Sopenharmony_ci#define SERIAL_ATMEL_MAJOR 204 658c2ecf20Sopenharmony_ci#define MINOR_START 154 668c2ecf20Sopenharmony_ci#define ATMEL_DEVICENAME "ttyAT" 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#else 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port 718c2ecf20Sopenharmony_ci * name, but it is legally reserved for the 8250 driver. */ 728c2ecf20Sopenharmony_ci#define SERIAL_ATMEL_MAJOR TTY_MAJOR 738c2ecf20Sopenharmony_ci#define MINOR_START 64 748c2ecf20Sopenharmony_ci#define ATMEL_DEVICENAME "ttyS" 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#endif 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define ATMEL_ISR_PASS_LIMIT 256 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct atmel_dma_buffer { 818c2ecf20Sopenharmony_ci unsigned char *buf; 828c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 838c2ecf20Sopenharmony_ci unsigned int dma_size; 848c2ecf20Sopenharmony_ci unsigned int ofs; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct atmel_uart_char { 888c2ecf20Sopenharmony_ci u16 status; 898c2ecf20Sopenharmony_ci u16 ch; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * Be careful, the real size of the ring buffer is 948c2ecf20Sopenharmony_ci * sizeof(atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. It means that ring buffer 958c2ecf20Sopenharmony_ci * can contain up to 1024 characters in PIO mode and up to 4096 characters in 968c2ecf20Sopenharmony_ci * DMA mode. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci#define ATMEL_SERIAL_RINGSIZE 1024 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * at91: 6 USARTs and one DBGU port (SAM9260) 1028c2ecf20Sopenharmony_ci * samx7: 3 USARTs and 5 UARTs 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ci#define ATMEL_MAX_UART 8 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * We wrap our port structure around the generic uart_port. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistruct atmel_uart_port { 1108c2ecf20Sopenharmony_ci struct uart_port uart; /* uart */ 1118c2ecf20Sopenharmony_ci struct clk *clk; /* uart clock */ 1128c2ecf20Sopenharmony_ci int may_wakeup; /* cached value of device_may_wakeup for times we need to disable it */ 1138c2ecf20Sopenharmony_ci u32 backup_imr; /* IMR saved during suspend */ 1148c2ecf20Sopenharmony_ci int break_active; /* break being received */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci bool use_dma_rx; /* enable DMA receiver */ 1178c2ecf20Sopenharmony_ci bool use_pdc_rx; /* enable PDC receiver */ 1188c2ecf20Sopenharmony_ci short pdc_rx_idx; /* current PDC RX buffer */ 1198c2ecf20Sopenharmony_ci struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci bool use_dma_tx; /* enable DMA transmitter */ 1228c2ecf20Sopenharmony_ci bool use_pdc_tx; /* enable PDC transmitter */ 1238c2ecf20Sopenharmony_ci struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci spinlock_t lock_tx; /* port lock */ 1268c2ecf20Sopenharmony_ci spinlock_t lock_rx; /* port lock */ 1278c2ecf20Sopenharmony_ci struct dma_chan *chan_tx; 1288c2ecf20Sopenharmony_ci struct dma_chan *chan_rx; 1298c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *desc_tx; 1308c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *desc_rx; 1318c2ecf20Sopenharmony_ci dma_cookie_t cookie_tx; 1328c2ecf20Sopenharmony_ci dma_cookie_t cookie_rx; 1338c2ecf20Sopenharmony_ci struct scatterlist sg_tx; 1348c2ecf20Sopenharmony_ci struct scatterlist sg_rx; 1358c2ecf20Sopenharmony_ci struct tasklet_struct tasklet_rx; 1368c2ecf20Sopenharmony_ci struct tasklet_struct tasklet_tx; 1378c2ecf20Sopenharmony_ci atomic_t tasklet_shutdown; 1388c2ecf20Sopenharmony_ci unsigned int irq_status_prev; 1398c2ecf20Sopenharmony_ci unsigned int tx_len; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci struct circ_buf rx_ring; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci struct mctrl_gpios *gpios; 1448c2ecf20Sopenharmony_ci u32 backup_mode; /* MR saved during iso7816 operations */ 1458c2ecf20Sopenharmony_ci u32 backup_brgr; /* BRGR saved during iso7816 operations */ 1468c2ecf20Sopenharmony_ci unsigned int tx_done_mask; 1478c2ecf20Sopenharmony_ci u32 fifo_size; 1488c2ecf20Sopenharmony_ci u32 rts_high; 1498c2ecf20Sopenharmony_ci u32 rts_low; 1508c2ecf20Sopenharmony_ci bool ms_irq_enabled; 1518c2ecf20Sopenharmony_ci u32 rtor; /* address of receiver timeout register if it exists */ 1528c2ecf20Sopenharmony_ci bool has_frac_baudrate; 1538c2ecf20Sopenharmony_ci bool has_hw_timer; 1548c2ecf20Sopenharmony_ci struct timer_list uart_timer; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci bool tx_stopped; 1578c2ecf20Sopenharmony_ci bool suspended; 1588c2ecf20Sopenharmony_ci unsigned int pending; 1598c2ecf20Sopenharmony_ci unsigned int pending_status; 1608c2ecf20Sopenharmony_ci spinlock_t lock_suspended; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci bool hd_start_rx; /* can start RX during half-duplex operation */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* ISO7816 */ 1658c2ecf20Sopenharmony_ci unsigned int fidi_min; 1668c2ecf20Sopenharmony_ci unsigned int fidi_max; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1698c2ecf20Sopenharmony_ci struct { 1708c2ecf20Sopenharmony_ci u32 cr; 1718c2ecf20Sopenharmony_ci u32 mr; 1728c2ecf20Sopenharmony_ci u32 imr; 1738c2ecf20Sopenharmony_ci u32 brgr; 1748c2ecf20Sopenharmony_ci u32 rtor; 1758c2ecf20Sopenharmony_ci u32 ttgr; 1768c2ecf20Sopenharmony_ci u32 fmr; 1778c2ecf20Sopenharmony_ci u32 fimr; 1788c2ecf20Sopenharmony_ci } cache; 1798c2ecf20Sopenharmony_ci#endif 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci int (*prepare_rx)(struct uart_port *port); 1828c2ecf20Sopenharmony_ci int (*prepare_tx)(struct uart_port *port); 1838c2ecf20Sopenharmony_ci void (*schedule_rx)(struct uart_port *port); 1848c2ecf20Sopenharmony_ci void (*schedule_tx)(struct uart_port *port); 1858c2ecf20Sopenharmony_ci void (*release_rx)(struct uart_port *port); 1868c2ecf20Sopenharmony_ci void (*release_tx)(struct uart_port *port); 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; 1908c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 1938c2ecf20Sopenharmony_cistatic const struct of_device_id atmel_serial_dt_ids[] = { 1948c2ecf20Sopenharmony_ci { .compatible = "atmel,at91rm9200-usart-serial" }, 1958c2ecf20Sopenharmony_ci { /* sentinel */ } 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic inline struct atmel_uart_port * 2008c2ecf20Sopenharmony_cito_atmel_uart_port(struct uart_port *uart) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci return container_of(uart, struct atmel_uart_port, uart); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic inline u32 atmel_uart_readl(struct uart_port *port, u32 reg) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci return __raw_readl(port->membase + reg); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci __raw_writel(value, port->membase + reg); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic inline u8 atmel_uart_read_char(struct uart_port *port) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return __raw_readb(port->membase + ATMEL_US_RHR); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic inline void atmel_uart_write_char(struct uart_port *port, u8 value) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci __raw_writeb(value, port->membase + ATMEL_US_THR); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic inline int atmel_uart_is_half_duplex(struct uart_port *port) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci return ((port->rs485.flags & SER_RS485_ENABLED) && 2288c2ecf20Sopenharmony_ci !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || 2298c2ecf20Sopenharmony_ci (port->iso7816.flags & SER_ISO7816_ENABLED); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_ATMEL_PDC 2338c2ecf20Sopenharmony_cistatic bool atmel_use_pdc_rx(struct uart_port *port) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return atmel_port->use_pdc_rx; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic bool atmel_use_pdc_tx(struct uart_port *port) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return atmel_port->use_pdc_tx; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci#else 2478c2ecf20Sopenharmony_cistatic bool atmel_use_pdc_rx(struct uart_port *port) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci return false; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic bool atmel_use_pdc_tx(struct uart_port *port) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci return false; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci#endif 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic bool atmel_use_dma_tx(struct uart_port *port) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return atmel_port->use_dma_tx; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic bool atmel_use_dma_rx(struct uart_port *port) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return atmel_port->use_dma_rx; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic bool atmel_use_fifo(struct uart_port *port) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return atmel_port->fifo_size; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port, 2808c2ecf20Sopenharmony_ci struct tasklet_struct *t) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci if (!atomic_read(&atmel_port->tasklet_shutdown)) 2838c2ecf20Sopenharmony_ci tasklet_schedule(t); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* Enable or disable the rs485 support */ 2878c2ecf20Sopenharmony_cistatic int atmel_config_rs485(struct uart_port *port, 2888c2ecf20Sopenharmony_ci struct serial_rs485 *rs485conf) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 2918c2ecf20Sopenharmony_ci unsigned int mode; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Disable interrupts */ 2948c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci mode = atmel_uart_readl(port, ATMEL_US_MR); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (rs485conf->flags & SER_RS485_ENABLED) { 2998c2ecf20Sopenharmony_ci dev_dbg(port->dev, "Setting UART to RS485\n"); 3008c2ecf20Sopenharmony_ci if (rs485conf->flags & SER_RS485_RX_DURING_TX) 3018c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_TXRDY; 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_TTGR, 3068c2ecf20Sopenharmony_ci rs485conf->delay_rts_after_send); 3078c2ecf20Sopenharmony_ci mode &= ~ATMEL_US_USMODE; 3088c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_RS485; 3098c2ecf20Sopenharmony_ci } else { 3108c2ecf20Sopenharmony_ci dev_dbg(port->dev, "Setting UART to RS232\n"); 3118c2ecf20Sopenharmony_ci if (atmel_use_pdc_tx(port)) 3128c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_ENDTX | 3138c2ecf20Sopenharmony_ci ATMEL_US_TXBUFE; 3148c2ecf20Sopenharmony_ci else 3158c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_TXRDY; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_MR, mode); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Enable interrupts */ 3208c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic unsigned int atmel_calc_cd(struct uart_port *port, 3268c2ecf20Sopenharmony_ci struct serial_iso7816 *iso7816conf) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 3298c2ecf20Sopenharmony_ci unsigned int cd; 3308c2ecf20Sopenharmony_ci u64 mck_rate; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci mck_rate = (u64)clk_get_rate(atmel_port->clk); 3338c2ecf20Sopenharmony_ci do_div(mck_rate, iso7816conf->clk); 3348c2ecf20Sopenharmony_ci cd = mck_rate; 3358c2ecf20Sopenharmony_ci return cd; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic unsigned int atmel_calc_fidi(struct uart_port *port, 3398c2ecf20Sopenharmony_ci struct serial_iso7816 *iso7816conf) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci u64 fidi = 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (iso7816conf->sc_fi && iso7816conf->sc_di) { 3448c2ecf20Sopenharmony_ci fidi = (u64)iso7816conf->sc_fi; 3458c2ecf20Sopenharmony_ci do_div(fidi, iso7816conf->sc_di); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci return (u32)fidi; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* Enable or disable the iso7816 support */ 3518c2ecf20Sopenharmony_ci/* Called with interrupts disabled */ 3528c2ecf20Sopenharmony_cistatic int atmel_config_iso7816(struct uart_port *port, 3538c2ecf20Sopenharmony_ci struct serial_iso7816 *iso7816conf) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 3568c2ecf20Sopenharmony_ci unsigned int mode; 3578c2ecf20Sopenharmony_ci unsigned int cd, fidi; 3588c2ecf20Sopenharmony_ci int ret = 0; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Disable interrupts */ 3618c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci mode = atmel_uart_readl(port, ATMEL_US_MR); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (iso7816conf->flags & SER_ISO7816_ENABLED) { 3668c2ecf20Sopenharmony_ci mode &= ~ATMEL_US_USMODE; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (iso7816conf->tg > 255) { 3698c2ecf20Sopenharmony_ci dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n"); 3708c2ecf20Sopenharmony_ci memset(iso7816conf, 0, sizeof(struct serial_iso7816)); 3718c2ecf20Sopenharmony_ci ret = -EINVAL; 3728c2ecf20Sopenharmony_ci goto err_out; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if ((iso7816conf->flags & SER_ISO7816_T_PARAM) 3768c2ecf20Sopenharmony_ci == SER_ISO7816_T(0)) { 3778c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK; 3788c2ecf20Sopenharmony_ci } else if ((iso7816conf->flags & SER_ISO7816_T_PARAM) 3798c2ecf20Sopenharmony_ci == SER_ISO7816_T(1)) { 3808c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK; 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci dev_err(port->dev, "ISO7816: Type not supported\n"); 3838c2ecf20Sopenharmony_ci memset(iso7816conf, 0, sizeof(struct serial_iso7816)); 3848c2ecf20Sopenharmony_ci ret = -EINVAL; 3858c2ecf20Sopenharmony_ci goto err_out; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* select mck clock, and output */ 3918c2ecf20Sopenharmony_ci mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO; 3928c2ecf20Sopenharmony_ci /* set parity for normal/inverse mode + max iterations */ 3938c2ecf20Sopenharmony_ci mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci cd = atmel_calc_cd(port, iso7816conf); 3968c2ecf20Sopenharmony_ci fidi = atmel_calc_fidi(port, iso7816conf); 3978c2ecf20Sopenharmony_ci if (fidi == 0) { 3988c2ecf20Sopenharmony_ci dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n"); 3998c2ecf20Sopenharmony_ci } else if (fidi < atmel_port->fidi_min 4008c2ecf20Sopenharmony_ci || fidi > atmel_port->fidi_max) { 4018c2ecf20Sopenharmony_ci dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi); 4028c2ecf20Sopenharmony_ci memset(iso7816conf, 0, sizeof(struct serial_iso7816)); 4038c2ecf20Sopenharmony_ci ret = -EINVAL; 4048c2ecf20Sopenharmony_ci goto err_out; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) { 4088c2ecf20Sopenharmony_ci /* port not yet in iso7816 mode: store configuration */ 4098c2ecf20Sopenharmony_ci atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR); 4108c2ecf20Sopenharmony_ci atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg); 4148c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_BRGR, cd); 4158c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_FIDI, fidi); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN); 4188c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION; 4198c2ecf20Sopenharmony_ci } else { 4208c2ecf20Sopenharmony_ci dev_dbg(port->dev, "Setting UART back to RS232\n"); 4218c2ecf20Sopenharmony_ci /* back to last RS232 settings */ 4228c2ecf20Sopenharmony_ci mode = atmel_port->backup_mode; 4238c2ecf20Sopenharmony_ci memset(iso7816conf, 0, sizeof(struct serial_iso7816)); 4248c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_TTGR, 0); 4258c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr); 4268c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_FIDI, 0x174); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (atmel_use_pdc_tx(port)) 4298c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_ENDTX | 4308c2ecf20Sopenharmony_ci ATMEL_US_TXBUFE; 4318c2ecf20Sopenharmony_ci else 4328c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_TXRDY; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci port->iso7816 = *iso7816conf; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_MR, mode); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cierr_out: 4408c2ecf20Sopenharmony_ci /* Enable interrupts */ 4418c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return ret; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* 4478c2ecf20Sopenharmony_ci * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_cistatic u_int atmel_tx_empty(struct uart_port *port) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (atmel_port->tx_stopped) 4548c2ecf20Sopenharmony_ci return TIOCSER_TEMT; 4558c2ecf20Sopenharmony_ci return (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY) ? 4568c2ecf20Sopenharmony_ci TIOCSER_TEMT : 4578c2ecf20Sopenharmony_ci 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci/* 4618c2ecf20Sopenharmony_ci * Set state of the modem control output lines 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_cistatic void atmel_set_mctrl(struct uart_port *port, u_int mctrl) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci unsigned int control = 0; 4668c2ecf20Sopenharmony_ci unsigned int mode = atmel_uart_readl(port, ATMEL_US_MR); 4678c2ecf20Sopenharmony_ci unsigned int rts_paused, rts_ready; 4688c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* override mode to RS485 if needed, otherwise keep the current mode */ 4718c2ecf20Sopenharmony_ci if (port->rs485.flags & SER_RS485_ENABLED) { 4728c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_TTGR, 4738c2ecf20Sopenharmony_ci port->rs485.delay_rts_after_send); 4748c2ecf20Sopenharmony_ci mode &= ~ATMEL_US_USMODE; 4758c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_RS485; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* set the RTS line state according to the mode */ 4798c2ecf20Sopenharmony_ci if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) { 4808c2ecf20Sopenharmony_ci /* force RTS line to high level */ 4818c2ecf20Sopenharmony_ci rts_paused = ATMEL_US_RTSEN; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* give the control of the RTS line back to the hardware */ 4848c2ecf20Sopenharmony_ci rts_ready = ATMEL_US_RTSDIS; 4858c2ecf20Sopenharmony_ci } else { 4868c2ecf20Sopenharmony_ci /* force RTS line to high level */ 4878c2ecf20Sopenharmony_ci rts_paused = ATMEL_US_RTSDIS; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* force RTS line to low level */ 4908c2ecf20Sopenharmony_ci rts_ready = ATMEL_US_RTSEN; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (mctrl & TIOCM_RTS) 4948c2ecf20Sopenharmony_ci control |= rts_ready; 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci control |= rts_paused; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (mctrl & TIOCM_DTR) 4998c2ecf20Sopenharmony_ci control |= ATMEL_US_DTREN; 5008c2ecf20Sopenharmony_ci else 5018c2ecf20Sopenharmony_ci control |= ATMEL_US_DTRDIS; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, control); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci mctrl_gpio_set(atmel_port->gpios, mctrl); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Local loopback mode? */ 5088c2ecf20Sopenharmony_ci mode &= ~ATMEL_US_CHMODE; 5098c2ecf20Sopenharmony_ci if (mctrl & TIOCM_LOOP) 5108c2ecf20Sopenharmony_ci mode |= ATMEL_US_CHMODE_LOC_LOOP; 5118c2ecf20Sopenharmony_ci else 5128c2ecf20Sopenharmony_ci mode |= ATMEL_US_CHMODE_NORMAL; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_MR, mode); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* 5188c2ecf20Sopenharmony_ci * Get state of the modem control input lines 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_cistatic u_int atmel_get_mctrl(struct uart_port *port) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 5238c2ecf20Sopenharmony_ci unsigned int ret = 0, status; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci status = atmel_uart_readl(port, ATMEL_US_CSR); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* 5288c2ecf20Sopenharmony_ci * The control signals are active low. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_ci if (!(status & ATMEL_US_DCD)) 5318c2ecf20Sopenharmony_ci ret |= TIOCM_CD; 5328c2ecf20Sopenharmony_ci if (!(status & ATMEL_US_CTS)) 5338c2ecf20Sopenharmony_ci ret |= TIOCM_CTS; 5348c2ecf20Sopenharmony_ci if (!(status & ATMEL_US_DSR)) 5358c2ecf20Sopenharmony_ci ret |= TIOCM_DSR; 5368c2ecf20Sopenharmony_ci if (!(status & ATMEL_US_RI)) 5378c2ecf20Sopenharmony_ci ret |= TIOCM_RI; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return mctrl_gpio_get(atmel_port->gpios, &ret); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* 5438c2ecf20Sopenharmony_ci * Stop transmitting. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic void atmel_stop_tx(struct uart_port *port) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (atmel_use_pdc_tx(port)) { 5508c2ecf20Sopenharmony_ci /* disable PDC transmit */ 5518c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci * Disable the transmitter. 5568c2ecf20Sopenharmony_ci * This is mandatory when DMA is used, otherwise the DMA buffer 5578c2ecf20Sopenharmony_ci * is fully transmitted. 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS); 5608c2ecf20Sopenharmony_ci atmel_port->tx_stopped = true; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Disable interrupts */ 5638c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (atmel_uart_is_half_duplex(port)) 5668c2ecf20Sopenharmony_ci if (!atomic_read(&atmel_port->tasklet_shutdown)) 5678c2ecf20Sopenharmony_ci atmel_start_rx(port); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci/* 5728c2ecf20Sopenharmony_ci * Start transmitting. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_cistatic void atmel_start_tx(struct uart_port *port) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR) 5798c2ecf20Sopenharmony_ci & ATMEL_PDC_TXTEN)) 5808c2ecf20Sopenharmony_ci /* The transmitter is already running. Yes, we 5818c2ecf20Sopenharmony_ci really need this.*/ 5828c2ecf20Sopenharmony_ci return; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) 5858c2ecf20Sopenharmony_ci if (atmel_uart_is_half_duplex(port)) 5868c2ecf20Sopenharmony_ci atmel_stop_rx(port); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (atmel_use_pdc_tx(port)) 5898c2ecf20Sopenharmony_ci /* re-enable PDC transmit */ 5908c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Enable interrupts */ 5938c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* re-enable the transmitter */ 5968c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); 5978c2ecf20Sopenharmony_ci atmel_port->tx_stopped = false; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci/* 6018c2ecf20Sopenharmony_ci * start receiving - port is in process of being opened. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_cistatic void atmel_start_rx(struct uart_port *port) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci /* reset status and receiver */ 6068c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXEN); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (atmel_use_pdc_rx(port)) { 6118c2ecf20Sopenharmony_ci /* enable PDC controller */ 6128c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 6138c2ecf20Sopenharmony_ci ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | 6148c2ecf20Sopenharmony_ci port->read_status_mask); 6158c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); 6168c2ecf20Sopenharmony_ci } else { 6178c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci/* 6228c2ecf20Sopenharmony_ci * Stop receiving - port is in process of being closed. 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_cistatic void atmel_stop_rx(struct uart_port *port) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXDIS); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (atmel_use_pdc_rx(port)) { 6298c2ecf20Sopenharmony_ci /* disable PDC receive */ 6308c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS); 6318c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, 6328c2ecf20Sopenharmony_ci ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | 6338c2ecf20Sopenharmony_ci port->read_status_mask); 6348c2ecf20Sopenharmony_ci } else { 6358c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXRDY); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci/* 6408c2ecf20Sopenharmony_ci * Enable modem status interrupts 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_cistatic void atmel_enable_ms(struct uart_port *port) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 6458c2ecf20Sopenharmony_ci uint32_t ier = 0; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Interrupt should not be enabled twice 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_ci if (atmel_port->ms_irq_enabled) 6518c2ecf20Sopenharmony_ci return; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci atmel_port->ms_irq_enabled = true; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) 6568c2ecf20Sopenharmony_ci ier |= ATMEL_US_CTSIC; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR)) 6598c2ecf20Sopenharmony_ci ier |= ATMEL_US_DSRIC; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI)) 6628c2ecf20Sopenharmony_ci ier |= ATMEL_US_RIIC; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD)) 6658c2ecf20Sopenharmony_ci ier |= ATMEL_US_DCDIC; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, ier); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci mctrl_gpio_enable_ms(atmel_port->gpios); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/* 6738c2ecf20Sopenharmony_ci * Disable modem status interrupts 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_cistatic void atmel_disable_ms(struct uart_port *port) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 6788c2ecf20Sopenharmony_ci uint32_t idr = 0; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* 6818c2ecf20Sopenharmony_ci * Interrupt should not be disabled twice 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_ci if (!atmel_port->ms_irq_enabled) 6848c2ecf20Sopenharmony_ci return; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci atmel_port->ms_irq_enabled = false; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci mctrl_gpio_disable_ms(atmel_port->gpios); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) 6918c2ecf20Sopenharmony_ci idr |= ATMEL_US_CTSIC; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR)) 6948c2ecf20Sopenharmony_ci idr |= ATMEL_US_DSRIC; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI)) 6978c2ecf20Sopenharmony_ci idr |= ATMEL_US_RIIC; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD)) 7008c2ecf20Sopenharmony_ci idr |= ATMEL_US_DCDIC; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, idr); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/* 7068c2ecf20Sopenharmony_ci * Control the transmission of a break signal 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_cistatic void atmel_break_ctl(struct uart_port *port, int break_state) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci if (break_state != 0) 7118c2ecf20Sopenharmony_ci /* start break */ 7128c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTBRK); 7138c2ecf20Sopenharmony_ci else 7148c2ecf20Sopenharmony_ci /* stop break */ 7158c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STPBRK); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci/* 7198c2ecf20Sopenharmony_ci * Stores the incoming character in the ring buffer 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_cistatic void 7228c2ecf20Sopenharmony_ciatmel_buffer_rx_char(struct uart_port *port, unsigned int status, 7238c2ecf20Sopenharmony_ci unsigned int ch) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 7268c2ecf20Sopenharmony_ci struct circ_buf *ring = &atmel_port->rx_ring; 7278c2ecf20Sopenharmony_ci struct atmel_uart_char *c; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE)) 7308c2ecf20Sopenharmony_ci /* Buffer overflow, ignore char */ 7318c2ecf20Sopenharmony_ci return; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci c = &((struct atmel_uart_char *)ring->buf)[ring->head]; 7348c2ecf20Sopenharmony_ci c->status = status; 7358c2ecf20Sopenharmony_ci c->ch = ch; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Make sure the character is stored before we update head. */ 7388c2ecf20Sopenharmony_ci smp_wmb(); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* 7448c2ecf20Sopenharmony_ci * Deal with parity, framing and overrun errors. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_cistatic void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci /* clear error */ 7498c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (status & ATMEL_US_RXBRK) { 7528c2ecf20Sopenharmony_ci /* ignore side-effect */ 7538c2ecf20Sopenharmony_ci status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); 7548c2ecf20Sopenharmony_ci port->icount.brk++; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci if (status & ATMEL_US_PARE) 7578c2ecf20Sopenharmony_ci port->icount.parity++; 7588c2ecf20Sopenharmony_ci if (status & ATMEL_US_FRAME) 7598c2ecf20Sopenharmony_ci port->icount.frame++; 7608c2ecf20Sopenharmony_ci if (status & ATMEL_US_OVRE) 7618c2ecf20Sopenharmony_ci port->icount.overrun++; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci/* 7658c2ecf20Sopenharmony_ci * Characters received (called from interrupt handler) 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_cistatic void atmel_rx_chars(struct uart_port *port) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 7708c2ecf20Sopenharmony_ci unsigned int status, ch; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci status = atmel_uart_readl(port, ATMEL_US_CSR); 7738c2ecf20Sopenharmony_ci while (status & ATMEL_US_RXRDY) { 7748c2ecf20Sopenharmony_ci ch = atmel_uart_read_char(port); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* 7778c2ecf20Sopenharmony_ci * note that the error handling code is 7788c2ecf20Sopenharmony_ci * out of the main execution path 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_ci if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME 7818c2ecf20Sopenharmony_ci | ATMEL_US_OVRE | ATMEL_US_RXBRK) 7828c2ecf20Sopenharmony_ci || atmel_port->break_active)) { 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* clear error */ 7858c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (status & ATMEL_US_RXBRK 7888c2ecf20Sopenharmony_ci && !atmel_port->break_active) { 7898c2ecf20Sopenharmony_ci atmel_port->break_active = 1; 7908c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 7918c2ecf20Sopenharmony_ci ATMEL_US_RXBRK); 7928c2ecf20Sopenharmony_ci } else { 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * This is either the end-of-break 7958c2ecf20Sopenharmony_ci * condition or we've received at 7968c2ecf20Sopenharmony_ci * least one character without RXBRK 7978c2ecf20Sopenharmony_ci * being set. In both cases, the next 7988c2ecf20Sopenharmony_ci * RXBRK will indicate start-of-break. 7998c2ecf20Sopenharmony_ci */ 8008c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, 8018c2ecf20Sopenharmony_ci ATMEL_US_RXBRK); 8028c2ecf20Sopenharmony_ci status &= ~ATMEL_US_RXBRK; 8038c2ecf20Sopenharmony_ci atmel_port->break_active = 0; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci atmel_buffer_rx_char(port, status, ch); 8088c2ecf20Sopenharmony_ci status = atmel_uart_readl(port, ATMEL_US_CSR); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci/* 8158c2ecf20Sopenharmony_ci * Transmit characters (called from tasklet with TXRDY interrupt 8168c2ecf20Sopenharmony_ci * disabled) 8178c2ecf20Sopenharmony_ci */ 8188c2ecf20Sopenharmony_cistatic void atmel_tx_chars(struct uart_port *port) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct circ_buf *xmit = &port->state->xmit; 8218c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (port->x_char && 8248c2ecf20Sopenharmony_ci (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) { 8258c2ecf20Sopenharmony_ci atmel_uart_write_char(port, port->x_char); 8268c2ecf20Sopenharmony_ci port->icount.tx++; 8278c2ecf20Sopenharmony_ci port->x_char = 0; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci if (uart_circ_empty(xmit) || uart_tx_stopped(port)) 8308c2ecf20Sopenharmony_ci return; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci while (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY) { 8338c2ecf20Sopenharmony_ci atmel_uart_write_char(port, xmit->buf[xmit->tail]); 8348c2ecf20Sopenharmony_ci xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 8358c2ecf20Sopenharmony_ci port->icount.tx++; 8368c2ecf20Sopenharmony_ci if (uart_circ_empty(xmit)) 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 8418c2ecf20Sopenharmony_ci uart_write_wakeup(port); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (!uart_circ_empty(xmit)) { 8448c2ecf20Sopenharmony_ci /* we still have characters to transmit, so we should continue 8458c2ecf20Sopenharmony_ci * transmitting them when TX is ready, regardless of 8468c2ecf20Sopenharmony_ci * mode or duplexity 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci atmel_port->tx_done_mask |= ATMEL_US_TXRDY; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Enable interrupts */ 8518c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 8528c2ecf20Sopenharmony_ci atmel_port->tx_done_mask); 8538c2ecf20Sopenharmony_ci } else { 8548c2ecf20Sopenharmony_ci if (atmel_uart_is_half_duplex(port)) 8558c2ecf20Sopenharmony_ci atmel_port->tx_done_mask &= ~ATMEL_US_TXRDY; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic void atmel_complete_tx_dma(void *arg) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = arg; 8628c2ecf20Sopenharmony_ci struct uart_port *port = &atmel_port->uart; 8638c2ecf20Sopenharmony_ci struct circ_buf *xmit = &port->state->xmit; 8648c2ecf20Sopenharmony_ci struct dma_chan *chan = atmel_port->chan_tx; 8658c2ecf20Sopenharmony_ci unsigned long flags; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (chan) 8708c2ecf20Sopenharmony_ci dmaengine_terminate_all(chan); 8718c2ecf20Sopenharmony_ci xmit->tail += atmel_port->tx_len; 8728c2ecf20Sopenharmony_ci xmit->tail &= UART_XMIT_SIZE - 1; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci port->icount.tx += atmel_port->tx_len; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci spin_lock(&atmel_port->lock_tx); 8778c2ecf20Sopenharmony_ci async_tx_ack(atmel_port->desc_tx); 8788c2ecf20Sopenharmony_ci atmel_port->cookie_tx = -EINVAL; 8798c2ecf20Sopenharmony_ci atmel_port->desc_tx = NULL; 8808c2ecf20Sopenharmony_ci spin_unlock(&atmel_port->lock_tx); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 8838c2ecf20Sopenharmony_ci uart_write_wakeup(port); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* 8868c2ecf20Sopenharmony_ci * xmit is a circular buffer so, if we have just send data from 8878c2ecf20Sopenharmony_ci * xmit->tail to the end of xmit->buf, now we have to transmit the 8888c2ecf20Sopenharmony_ci * remaining data from the beginning of xmit->buf to xmit->head. 8898c2ecf20Sopenharmony_ci */ 8908c2ecf20Sopenharmony_ci if (!uart_circ_empty(xmit)) 8918c2ecf20Sopenharmony_ci atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); 8928c2ecf20Sopenharmony_ci else if (atmel_uart_is_half_duplex(port)) { 8938c2ecf20Sopenharmony_ci /* 8948c2ecf20Sopenharmony_ci * DMA done, re-enable TXEMPTY and signal that we can stop 8958c2ecf20Sopenharmony_ci * TX and start RX for RS485 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_ci atmel_port->hd_start_rx = true; 8988c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 8998c2ecf20Sopenharmony_ci atmel_port->tx_done_mask); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic void atmel_release_tx_dma(struct uart_port *port) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 9088c2ecf20Sopenharmony_ci struct dma_chan *chan = atmel_port->chan_tx; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (chan) { 9118c2ecf20Sopenharmony_ci dmaengine_terminate_all(chan); 9128c2ecf20Sopenharmony_ci dma_release_channel(chan); 9138c2ecf20Sopenharmony_ci dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1, 9148c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci atmel_port->desc_tx = NULL; 9188c2ecf20Sopenharmony_ci atmel_port->chan_tx = NULL; 9198c2ecf20Sopenharmony_ci atmel_port->cookie_tx = -EINVAL; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/* 9238c2ecf20Sopenharmony_ci * Called from tasklet with TXRDY interrupt is disabled. 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_cistatic void atmel_tx_dma(struct uart_port *port) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 9288c2ecf20Sopenharmony_ci struct circ_buf *xmit = &port->state->xmit; 9298c2ecf20Sopenharmony_ci struct dma_chan *chan = atmel_port->chan_tx; 9308c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *desc; 9318c2ecf20Sopenharmony_ci struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; 9328c2ecf20Sopenharmony_ci unsigned int tx_len, part1_len, part2_len, sg_len; 9338c2ecf20Sopenharmony_ci dma_addr_t phys_addr; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Make sure we have an idle channel */ 9368c2ecf20Sopenharmony_ci if (atmel_port->desc_tx != NULL) 9378c2ecf20Sopenharmony_ci return; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { 9408c2ecf20Sopenharmony_ci /* 9418c2ecf20Sopenharmony_ci * DMA is idle now. 9428c2ecf20Sopenharmony_ci * Port xmit buffer is already mapped, 9438c2ecf20Sopenharmony_ci * and it is one page... Just adjust 9448c2ecf20Sopenharmony_ci * offsets and lengths. Since it is a circular buffer, 9458c2ecf20Sopenharmony_ci * we have to transmit till the end, and then the rest. 9468c2ecf20Sopenharmony_ci * Take the port lock to get a 9478c2ecf20Sopenharmony_ci * consistent xmit buffer state. 9488c2ecf20Sopenharmony_ci */ 9498c2ecf20Sopenharmony_ci tx_len = CIRC_CNT_TO_END(xmit->head, 9508c2ecf20Sopenharmony_ci xmit->tail, 9518c2ecf20Sopenharmony_ci UART_XMIT_SIZE); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (atmel_port->fifo_size) { 9548c2ecf20Sopenharmony_ci /* multi data mode */ 9558c2ecf20Sopenharmony_ci part1_len = (tx_len & ~0x3); /* DWORD access */ 9568c2ecf20Sopenharmony_ci part2_len = (tx_len & 0x3); /* BYTE access */ 9578c2ecf20Sopenharmony_ci } else { 9588c2ecf20Sopenharmony_ci /* single data (legacy) mode */ 9598c2ecf20Sopenharmony_ci part1_len = 0; 9608c2ecf20Sopenharmony_ci part2_len = tx_len; /* BYTE access only */ 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci sg_init_table(sgl, 2); 9648c2ecf20Sopenharmony_ci sg_len = 0; 9658c2ecf20Sopenharmony_ci phys_addr = sg_dma_address(sg_tx) + xmit->tail; 9668c2ecf20Sopenharmony_ci if (part1_len) { 9678c2ecf20Sopenharmony_ci sg = &sgl[sg_len++]; 9688c2ecf20Sopenharmony_ci sg_dma_address(sg) = phys_addr; 9698c2ecf20Sopenharmony_ci sg_dma_len(sg) = part1_len; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci phys_addr += part1_len; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (part2_len) { 9758c2ecf20Sopenharmony_ci sg = &sgl[sg_len++]; 9768c2ecf20Sopenharmony_ci sg_dma_address(sg) = phys_addr; 9778c2ecf20Sopenharmony_ci sg_dma_len(sg) = part2_len; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* 9818c2ecf20Sopenharmony_ci * save tx_len so atmel_complete_tx_dma() will increase 9828c2ecf20Sopenharmony_ci * xmit->tail correctly 9838c2ecf20Sopenharmony_ci */ 9848c2ecf20Sopenharmony_ci atmel_port->tx_len = tx_len; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci desc = dmaengine_prep_slave_sg(chan, 9878c2ecf20Sopenharmony_ci sgl, 9888c2ecf20Sopenharmony_ci sg_len, 9898c2ecf20Sopenharmony_ci DMA_MEM_TO_DEV, 9908c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | 9918c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 9928c2ecf20Sopenharmony_ci if (!desc) { 9938c2ecf20Sopenharmony_ci dev_err(port->dev, "Failed to send via dma!\n"); 9948c2ecf20Sopenharmony_ci return; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci atmel_port->desc_tx = desc; 10008c2ecf20Sopenharmony_ci desc->callback = atmel_complete_tx_dma; 10018c2ecf20Sopenharmony_ci desc->callback_param = atmel_port; 10028c2ecf20Sopenharmony_ci atmel_port->cookie_tx = dmaengine_submit(desc); 10038c2ecf20Sopenharmony_ci if (dma_submit_error(atmel_port->cookie_tx)) { 10048c2ecf20Sopenharmony_ci dev_err(port->dev, "dma_submit_error %d\n", 10058c2ecf20Sopenharmony_ci atmel_port->cookie_tx); 10068c2ecf20Sopenharmony_ci return; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci dma_async_issue_pending(chan); 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 10138c2ecf20Sopenharmony_ci uart_write_wakeup(port); 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_cistatic int atmel_prepare_tx_dma(struct uart_port *port) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 10198c2ecf20Sopenharmony_ci struct device *mfd_dev = port->dev->parent; 10208c2ecf20Sopenharmony_ci dma_cap_mask_t mask; 10218c2ecf20Sopenharmony_ci struct dma_slave_config config; 10228c2ecf20Sopenharmony_ci int ret, nent; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci dma_cap_zero(mask); 10258c2ecf20Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx"); 10288c2ecf20Sopenharmony_ci if (atmel_port->chan_tx == NULL) 10298c2ecf20Sopenharmony_ci goto chan_err; 10308c2ecf20Sopenharmony_ci dev_info(port->dev, "using %s for tx DMA transfers\n", 10318c2ecf20Sopenharmony_ci dma_chan_name(atmel_port->chan_tx)); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci spin_lock_init(&atmel_port->lock_tx); 10348c2ecf20Sopenharmony_ci sg_init_table(&atmel_port->sg_tx, 1); 10358c2ecf20Sopenharmony_ci /* UART circular tx buffer is an aligned page. */ 10368c2ecf20Sopenharmony_ci BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf)); 10378c2ecf20Sopenharmony_ci sg_set_page(&atmel_port->sg_tx, 10388c2ecf20Sopenharmony_ci virt_to_page(port->state->xmit.buf), 10398c2ecf20Sopenharmony_ci UART_XMIT_SIZE, 10408c2ecf20Sopenharmony_ci offset_in_page(port->state->xmit.buf)); 10418c2ecf20Sopenharmony_ci nent = dma_map_sg(port->dev, 10428c2ecf20Sopenharmony_ci &atmel_port->sg_tx, 10438c2ecf20Sopenharmony_ci 1, 10448c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (!nent) { 10478c2ecf20Sopenharmony_ci dev_dbg(port->dev, "need to release resource of dma\n"); 10488c2ecf20Sopenharmony_ci goto chan_err; 10498c2ecf20Sopenharmony_ci } else { 10508c2ecf20Sopenharmony_ci dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, 10518c2ecf20Sopenharmony_ci sg_dma_len(&atmel_port->sg_tx), 10528c2ecf20Sopenharmony_ci port->state->xmit.buf, 10538c2ecf20Sopenharmony_ci &sg_dma_address(&atmel_port->sg_tx)); 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* Configure the slave DMA */ 10578c2ecf20Sopenharmony_ci memset(&config, 0, sizeof(config)); 10588c2ecf20Sopenharmony_ci config.direction = DMA_MEM_TO_DEV; 10598c2ecf20Sopenharmony_ci config.dst_addr_width = (atmel_port->fifo_size) ? 10608c2ecf20Sopenharmony_ci DMA_SLAVE_BUSWIDTH_4_BYTES : 10618c2ecf20Sopenharmony_ci DMA_SLAVE_BUSWIDTH_1_BYTE; 10628c2ecf20Sopenharmony_ci config.dst_addr = port->mapbase + ATMEL_US_THR; 10638c2ecf20Sopenharmony_ci config.dst_maxburst = 1; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci ret = dmaengine_slave_config(atmel_port->chan_tx, 10668c2ecf20Sopenharmony_ci &config); 10678c2ecf20Sopenharmony_ci if (ret) { 10688c2ecf20Sopenharmony_ci dev_err(port->dev, "DMA tx slave configuration failed\n"); 10698c2ecf20Sopenharmony_ci goto chan_err; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci return 0; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cichan_err: 10758c2ecf20Sopenharmony_ci dev_err(port->dev, "TX channel not available, switch to pio\n"); 10768c2ecf20Sopenharmony_ci atmel_port->use_dma_tx = false; 10778c2ecf20Sopenharmony_ci if (atmel_port->chan_tx) 10788c2ecf20Sopenharmony_ci atmel_release_tx_dma(port); 10798c2ecf20Sopenharmony_ci return -EINVAL; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic void atmel_complete_rx_dma(void *arg) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct uart_port *port = arg; 10858c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic void atmel_release_rx_dma(struct uart_port *port) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 10938c2ecf20Sopenharmony_ci struct dma_chan *chan = atmel_port->chan_rx; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (chan) { 10968c2ecf20Sopenharmony_ci dmaengine_terminate_all(chan); 10978c2ecf20Sopenharmony_ci dma_release_channel(chan); 10988c2ecf20Sopenharmony_ci dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1, 10998c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci atmel_port->desc_rx = NULL; 11038c2ecf20Sopenharmony_ci atmel_port->chan_rx = NULL; 11048c2ecf20Sopenharmony_ci atmel_port->cookie_rx = -EINVAL; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic void atmel_rx_from_dma(struct uart_port *port) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 11108c2ecf20Sopenharmony_ci struct tty_port *tport = &port->state->port; 11118c2ecf20Sopenharmony_ci struct circ_buf *ring = &atmel_port->rx_ring; 11128c2ecf20Sopenharmony_ci struct dma_chan *chan = atmel_port->chan_rx; 11138c2ecf20Sopenharmony_ci struct dma_tx_state state; 11148c2ecf20Sopenharmony_ci enum dma_status dmastat; 11158c2ecf20Sopenharmony_ci size_t count; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* Reset the UART timeout early so that we don't miss one */ 11198c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); 11208c2ecf20Sopenharmony_ci dmastat = dmaengine_tx_status(chan, 11218c2ecf20Sopenharmony_ci atmel_port->cookie_rx, 11228c2ecf20Sopenharmony_ci &state); 11238c2ecf20Sopenharmony_ci /* Restart a new tasklet if DMA status is error */ 11248c2ecf20Sopenharmony_ci if (dmastat == DMA_ERROR) { 11258c2ecf20Sopenharmony_ci dev_dbg(port->dev, "Get residue error, restart tasklet\n"); 11268c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); 11278c2ecf20Sopenharmony_ci atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx); 11288c2ecf20Sopenharmony_ci return; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* CPU claims ownership of RX DMA buffer */ 11328c2ecf20Sopenharmony_ci dma_sync_sg_for_cpu(port->dev, 11338c2ecf20Sopenharmony_ci &atmel_port->sg_rx, 11348c2ecf20Sopenharmony_ci 1, 11358c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* 11388c2ecf20Sopenharmony_ci * ring->head points to the end of data already written by the DMA. 11398c2ecf20Sopenharmony_ci * ring->tail points to the beginning of data to be read by the 11408c2ecf20Sopenharmony_ci * framework. 11418c2ecf20Sopenharmony_ci * The current transfer size should not be larger than the dma buffer 11428c2ecf20Sopenharmony_ci * length. 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_ci ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue; 11458c2ecf20Sopenharmony_ci BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx)); 11468c2ecf20Sopenharmony_ci /* 11478c2ecf20Sopenharmony_ci * At this point ring->head may point to the first byte right after the 11488c2ecf20Sopenharmony_ci * last byte of the dma buffer: 11498c2ecf20Sopenharmony_ci * 0 <= ring->head <= sg_dma_len(&atmel_port->sg_rx) 11508c2ecf20Sopenharmony_ci * 11518c2ecf20Sopenharmony_ci * However ring->tail must always points inside the dma buffer: 11528c2ecf20Sopenharmony_ci * 0 <= ring->tail <= sg_dma_len(&atmel_port->sg_rx) - 1 11538c2ecf20Sopenharmony_ci * 11548c2ecf20Sopenharmony_ci * Since we use a ring buffer, we have to handle the case 11558c2ecf20Sopenharmony_ci * where head is lower than tail. In such a case, we first read from 11568c2ecf20Sopenharmony_ci * tail to the end of the buffer then reset tail. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci if (ring->head < ring->tail) { 11598c2ecf20Sopenharmony_ci count = sg_dma_len(&atmel_port->sg_rx) - ring->tail; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci tty_insert_flip_string(tport, ring->buf + ring->tail, count); 11628c2ecf20Sopenharmony_ci ring->tail = 0; 11638c2ecf20Sopenharmony_ci port->icount.rx += count; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* Finally we read data from tail to head */ 11678c2ecf20Sopenharmony_ci if (ring->tail < ring->head) { 11688c2ecf20Sopenharmony_ci count = ring->head - ring->tail; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci tty_insert_flip_string(tport, ring->buf + ring->tail, count); 11718c2ecf20Sopenharmony_ci /* Wrap ring->head if needed */ 11728c2ecf20Sopenharmony_ci if (ring->head >= sg_dma_len(&atmel_port->sg_rx)) 11738c2ecf20Sopenharmony_ci ring->head = 0; 11748c2ecf20Sopenharmony_ci ring->tail = ring->head; 11758c2ecf20Sopenharmony_ci port->icount.rx += count; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* USART retreives ownership of RX DMA buffer */ 11798c2ecf20Sopenharmony_ci dma_sync_sg_for_device(port->dev, 11808c2ecf20Sopenharmony_ci &atmel_port->sg_rx, 11818c2ecf20Sopenharmony_ci 1, 11828c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* 11858c2ecf20Sopenharmony_ci * Drop the lock here since it might end up calling 11868c2ecf20Sopenharmony_ci * uart_start(), which takes the lock. 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_ci spin_unlock(&port->lock); 11898c2ecf20Sopenharmony_ci tty_flip_buffer_push(tport); 11908c2ecf20Sopenharmony_ci spin_lock(&port->lock); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic int atmel_prepare_rx_dma(struct uart_port *port) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 11988c2ecf20Sopenharmony_ci struct device *mfd_dev = port->dev->parent; 11998c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *desc; 12008c2ecf20Sopenharmony_ci dma_cap_mask_t mask; 12018c2ecf20Sopenharmony_ci struct dma_slave_config config; 12028c2ecf20Sopenharmony_ci struct circ_buf *ring; 12038c2ecf20Sopenharmony_ci int ret, nent; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci ring = &atmel_port->rx_ring; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci dma_cap_zero(mask); 12088c2ecf20Sopenharmony_ci dma_cap_set(DMA_CYCLIC, mask); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx"); 12118c2ecf20Sopenharmony_ci if (atmel_port->chan_rx == NULL) 12128c2ecf20Sopenharmony_ci goto chan_err; 12138c2ecf20Sopenharmony_ci dev_info(port->dev, "using %s for rx DMA transfers\n", 12148c2ecf20Sopenharmony_ci dma_chan_name(atmel_port->chan_rx)); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci spin_lock_init(&atmel_port->lock_rx); 12178c2ecf20Sopenharmony_ci sg_init_table(&atmel_port->sg_rx, 1); 12188c2ecf20Sopenharmony_ci /* UART circular rx buffer is an aligned page. */ 12198c2ecf20Sopenharmony_ci BUG_ON(!PAGE_ALIGNED(ring->buf)); 12208c2ecf20Sopenharmony_ci sg_set_page(&atmel_port->sg_rx, 12218c2ecf20Sopenharmony_ci virt_to_page(ring->buf), 12228c2ecf20Sopenharmony_ci sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, 12238c2ecf20Sopenharmony_ci offset_in_page(ring->buf)); 12248c2ecf20Sopenharmony_ci nent = dma_map_sg(port->dev, 12258c2ecf20Sopenharmony_ci &atmel_port->sg_rx, 12268c2ecf20Sopenharmony_ci 1, 12278c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (!nent) { 12308c2ecf20Sopenharmony_ci dev_dbg(port->dev, "need to release resource of dma\n"); 12318c2ecf20Sopenharmony_ci goto chan_err; 12328c2ecf20Sopenharmony_ci } else { 12338c2ecf20Sopenharmony_ci dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, 12348c2ecf20Sopenharmony_ci sg_dma_len(&atmel_port->sg_rx), 12358c2ecf20Sopenharmony_ci ring->buf, 12368c2ecf20Sopenharmony_ci &sg_dma_address(&atmel_port->sg_rx)); 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* Configure the slave DMA */ 12408c2ecf20Sopenharmony_ci memset(&config, 0, sizeof(config)); 12418c2ecf20Sopenharmony_ci config.direction = DMA_DEV_TO_MEM; 12428c2ecf20Sopenharmony_ci config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 12438c2ecf20Sopenharmony_ci config.src_addr = port->mapbase + ATMEL_US_RHR; 12448c2ecf20Sopenharmony_ci config.src_maxburst = 1; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci ret = dmaengine_slave_config(atmel_port->chan_rx, 12478c2ecf20Sopenharmony_ci &config); 12488c2ecf20Sopenharmony_ci if (ret) { 12498c2ecf20Sopenharmony_ci dev_err(port->dev, "DMA rx slave configuration failed\n"); 12508c2ecf20Sopenharmony_ci goto chan_err; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci /* 12538c2ecf20Sopenharmony_ci * Prepare a cyclic dma transfer, assign 2 descriptors, 12548c2ecf20Sopenharmony_ci * each one is half ring buffer size 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx, 12578c2ecf20Sopenharmony_ci sg_dma_address(&atmel_port->sg_rx), 12588c2ecf20Sopenharmony_ci sg_dma_len(&atmel_port->sg_rx), 12598c2ecf20Sopenharmony_ci sg_dma_len(&atmel_port->sg_rx)/2, 12608c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 12618c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT); 12628c2ecf20Sopenharmony_ci if (!desc) { 12638c2ecf20Sopenharmony_ci dev_err(port->dev, "Preparing DMA cyclic failed\n"); 12648c2ecf20Sopenharmony_ci goto chan_err; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci desc->callback = atmel_complete_rx_dma; 12678c2ecf20Sopenharmony_ci desc->callback_param = port; 12688c2ecf20Sopenharmony_ci atmel_port->desc_rx = desc; 12698c2ecf20Sopenharmony_ci atmel_port->cookie_rx = dmaengine_submit(desc); 12708c2ecf20Sopenharmony_ci if (dma_submit_error(atmel_port->cookie_rx)) { 12718c2ecf20Sopenharmony_ci dev_err(port->dev, "dma_submit_error %d\n", 12728c2ecf20Sopenharmony_ci atmel_port->cookie_rx); 12738c2ecf20Sopenharmony_ci goto chan_err; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci dma_async_issue_pending(atmel_port->chan_rx); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci return 0; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cichan_err: 12818c2ecf20Sopenharmony_ci dev_err(port->dev, "RX channel not available, switch to pio\n"); 12828c2ecf20Sopenharmony_ci atmel_port->use_dma_rx = false; 12838c2ecf20Sopenharmony_ci if (atmel_port->chan_rx) 12848c2ecf20Sopenharmony_ci atmel_release_rx_dma(port); 12858c2ecf20Sopenharmony_ci return -EINVAL; 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic void atmel_uart_timer_callback(struct timer_list *t) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = from_timer(atmel_port, t, 12918c2ecf20Sopenharmony_ci uart_timer); 12928c2ecf20Sopenharmony_ci struct uart_port *port = &atmel_port->uart; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (!atomic_read(&atmel_port->tasklet_shutdown)) { 12958c2ecf20Sopenharmony_ci tasklet_schedule(&atmel_port->tasklet_rx); 12968c2ecf20Sopenharmony_ci mod_timer(&atmel_port->uart_timer, 12978c2ecf20Sopenharmony_ci jiffies + uart_poll_timeout(port)); 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci/* 13028c2ecf20Sopenharmony_ci * receive interrupt handler. 13038c2ecf20Sopenharmony_ci */ 13048c2ecf20Sopenharmony_cistatic void 13058c2ecf20Sopenharmony_ciatmel_handle_receive(struct uart_port *port, unsigned int pending) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (atmel_use_pdc_rx(port)) { 13108c2ecf20Sopenharmony_ci /* 13118c2ecf20Sopenharmony_ci * PDC receive. Just schedule the tasklet and let it 13128c2ecf20Sopenharmony_ci * figure out the details. 13138c2ecf20Sopenharmony_ci * 13148c2ecf20Sopenharmony_ci * TODO: We're not handling error flags correctly at 13158c2ecf20Sopenharmony_ci * the moment. 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ci if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { 13188c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, 13198c2ecf20Sopenharmony_ci (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); 13208c2ecf20Sopenharmony_ci atmel_tasklet_schedule(atmel_port, 13218c2ecf20Sopenharmony_ci &atmel_port->tasklet_rx); 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | 13258c2ecf20Sopenharmony_ci ATMEL_US_FRAME | ATMEL_US_PARE)) 13268c2ecf20Sopenharmony_ci atmel_pdc_rxerr(port, pending); 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (atmel_use_dma_rx(port)) { 13308c2ecf20Sopenharmony_ci if (pending & ATMEL_US_TIMEOUT) { 13318c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, 13328c2ecf20Sopenharmony_ci ATMEL_US_TIMEOUT); 13338c2ecf20Sopenharmony_ci atmel_tasklet_schedule(atmel_port, 13348c2ecf20Sopenharmony_ci &atmel_port->tasklet_rx); 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* Interrupt receive */ 13398c2ecf20Sopenharmony_ci if (pending & ATMEL_US_RXRDY) 13408c2ecf20Sopenharmony_ci atmel_rx_chars(port); 13418c2ecf20Sopenharmony_ci else if (pending & ATMEL_US_RXBRK) { 13428c2ecf20Sopenharmony_ci /* 13438c2ecf20Sopenharmony_ci * End of break detected. If it came along with a 13448c2ecf20Sopenharmony_ci * character, atmel_rx_chars will handle it. 13458c2ecf20Sopenharmony_ci */ 13468c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); 13478c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXBRK); 13488c2ecf20Sopenharmony_ci atmel_port->break_active = 0; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci/* 13538c2ecf20Sopenharmony_ci * transmit interrupt handler. (Transmit is IRQF_NODELAY safe) 13548c2ecf20Sopenharmony_ci */ 13558c2ecf20Sopenharmony_cistatic void 13568c2ecf20Sopenharmony_ciatmel_handle_transmit(struct uart_port *port, unsigned int pending) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (pending & atmel_port->tx_done_mask) { 13618c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, 13628c2ecf20Sopenharmony_ci atmel_port->tx_done_mask); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* Start RX if flag was set and FIFO is empty */ 13658c2ecf20Sopenharmony_ci if (atmel_port->hd_start_rx) { 13668c2ecf20Sopenharmony_ci if (!(atmel_uart_readl(port, ATMEL_US_CSR) 13678c2ecf20Sopenharmony_ci & ATMEL_US_TXEMPTY)) 13688c2ecf20Sopenharmony_ci dev_warn(port->dev, "Should start RX, but TX fifo is not empty\n"); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci atmel_port->hd_start_rx = false; 13718c2ecf20Sopenharmony_ci atmel_start_rx(port); 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci} 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci/* 13798c2ecf20Sopenharmony_ci * status flags interrupt handler. 13808c2ecf20Sopenharmony_ci */ 13818c2ecf20Sopenharmony_cistatic void 13828c2ecf20Sopenharmony_ciatmel_handle_status(struct uart_port *port, unsigned int pending, 13838c2ecf20Sopenharmony_ci unsigned int status) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 13868c2ecf20Sopenharmony_ci unsigned int status_change; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC 13898c2ecf20Sopenharmony_ci | ATMEL_US_CTSIC)) { 13908c2ecf20Sopenharmony_ci status_change = status ^ atmel_port->irq_status_prev; 13918c2ecf20Sopenharmony_ci atmel_port->irq_status_prev = status; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci if (status_change & (ATMEL_US_RI | ATMEL_US_DSR 13948c2ecf20Sopenharmony_ci | ATMEL_US_DCD | ATMEL_US_CTS)) { 13958c2ecf20Sopenharmony_ci /* TODO: All reads to CSR will clear these interrupts! */ 13968c2ecf20Sopenharmony_ci if (status_change & ATMEL_US_RI) 13978c2ecf20Sopenharmony_ci port->icount.rng++; 13988c2ecf20Sopenharmony_ci if (status_change & ATMEL_US_DSR) 13998c2ecf20Sopenharmony_ci port->icount.dsr++; 14008c2ecf20Sopenharmony_ci if (status_change & ATMEL_US_DCD) 14018c2ecf20Sopenharmony_ci uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); 14028c2ecf20Sopenharmony_ci if (status_change & ATMEL_US_CTS) 14038c2ecf20Sopenharmony_ci uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci wake_up_interruptible(&port->state->port.delta_msr_wait); 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION)) 14108c2ecf20Sopenharmony_ci dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending); 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci/* 14148c2ecf20Sopenharmony_ci * Interrupt handler 14158c2ecf20Sopenharmony_ci */ 14168c2ecf20Sopenharmony_cistatic irqreturn_t atmel_interrupt(int irq, void *dev_id) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct uart_port *port = dev_id; 14198c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 14208c2ecf20Sopenharmony_ci unsigned int status, pending, mask, pass_counter = 0; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci spin_lock(&atmel_port->lock_suspended); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci do { 14258c2ecf20Sopenharmony_ci status = atmel_uart_readl(port, ATMEL_US_CSR); 14268c2ecf20Sopenharmony_ci mask = atmel_uart_readl(port, ATMEL_US_IMR); 14278c2ecf20Sopenharmony_ci pending = status & mask; 14288c2ecf20Sopenharmony_ci if (!pending) 14298c2ecf20Sopenharmony_ci break; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (atmel_port->suspended) { 14328c2ecf20Sopenharmony_ci atmel_port->pending |= pending; 14338c2ecf20Sopenharmony_ci atmel_port->pending_status = status; 14348c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, mask); 14358c2ecf20Sopenharmony_ci pm_system_wakeup(); 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci atmel_handle_receive(port, pending); 14408c2ecf20Sopenharmony_ci atmel_handle_status(port, pending, status); 14418c2ecf20Sopenharmony_ci atmel_handle_transmit(port, pending); 14428c2ecf20Sopenharmony_ci } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci spin_unlock(&atmel_port->lock_suspended); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci return pass_counter ? IRQ_HANDLED : IRQ_NONE; 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_cistatic void atmel_release_tx_pdc(struct uart_port *port) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 14528c2ecf20Sopenharmony_ci struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci dma_unmap_single(port->dev, 14558c2ecf20Sopenharmony_ci pdc->dma_addr, 14568c2ecf20Sopenharmony_ci pdc->dma_size, 14578c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci/* 14618c2ecf20Sopenharmony_ci * Called from tasklet with ENDTX and TXBUFE interrupts disabled. 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_cistatic void atmel_tx_pdc(struct uart_port *port) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 14668c2ecf20Sopenharmony_ci struct circ_buf *xmit = &port->state->xmit; 14678c2ecf20Sopenharmony_ci struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; 14688c2ecf20Sopenharmony_ci int count; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* nothing left to transmit? */ 14718c2ecf20Sopenharmony_ci if (atmel_uart_readl(port, ATMEL_PDC_TCR)) 14728c2ecf20Sopenharmony_ci return; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci xmit->tail += pdc->ofs; 14758c2ecf20Sopenharmony_ci xmit->tail &= UART_XMIT_SIZE - 1; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci port->icount.tx += pdc->ofs; 14788c2ecf20Sopenharmony_ci pdc->ofs = 0; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* more to transmit - setup next transfer */ 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* disable PDC transmit */ 14838c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { 14868c2ecf20Sopenharmony_ci dma_sync_single_for_device(port->dev, 14878c2ecf20Sopenharmony_ci pdc->dma_addr, 14888c2ecf20Sopenharmony_ci pdc->dma_size, 14898c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); 14928c2ecf20Sopenharmony_ci pdc->ofs = count; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_TPR, 14958c2ecf20Sopenharmony_ci pdc->dma_addr + xmit->tail); 14968c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_TCR, count); 14978c2ecf20Sopenharmony_ci /* re-enable PDC transmit */ 14988c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); 14998c2ecf20Sopenharmony_ci /* Enable interrupts */ 15008c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 15018c2ecf20Sopenharmony_ci atmel_port->tx_done_mask); 15028c2ecf20Sopenharmony_ci } else { 15038c2ecf20Sopenharmony_ci if (atmel_uart_is_half_duplex(port)) { 15048c2ecf20Sopenharmony_ci /* DMA done, stop TX, start RX for RS485 */ 15058c2ecf20Sopenharmony_ci atmel_start_rx(port); 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 15108c2ecf20Sopenharmony_ci uart_write_wakeup(port); 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_cistatic int atmel_prepare_tx_pdc(struct uart_port *port) 15148c2ecf20Sopenharmony_ci{ 15158c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 15168c2ecf20Sopenharmony_ci struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; 15178c2ecf20Sopenharmony_ci struct circ_buf *xmit = &port->state->xmit; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci pdc->buf = xmit->buf; 15208c2ecf20Sopenharmony_ci pdc->dma_addr = dma_map_single(port->dev, 15218c2ecf20Sopenharmony_ci pdc->buf, 15228c2ecf20Sopenharmony_ci UART_XMIT_SIZE, 15238c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 15248c2ecf20Sopenharmony_ci pdc->dma_size = UART_XMIT_SIZE; 15258c2ecf20Sopenharmony_ci pdc->ofs = 0; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci return 0; 15288c2ecf20Sopenharmony_ci} 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cistatic void atmel_rx_from_ring(struct uart_port *port) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 15338c2ecf20Sopenharmony_ci struct circ_buf *ring = &atmel_port->rx_ring; 15348c2ecf20Sopenharmony_ci unsigned int flg; 15358c2ecf20Sopenharmony_ci unsigned int status; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci while (ring->head != ring->tail) { 15388c2ecf20Sopenharmony_ci struct atmel_uart_char c; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci /* Make sure c is loaded after head. */ 15418c2ecf20Sopenharmony_ci smp_rmb(); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci c = ((struct atmel_uart_char *)ring->buf)[ring->tail]; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci port->icount.rx++; 15488c2ecf20Sopenharmony_ci status = c.status; 15498c2ecf20Sopenharmony_ci flg = TTY_NORMAL; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci /* 15528c2ecf20Sopenharmony_ci * note that the error handling code is 15538c2ecf20Sopenharmony_ci * out of the main execution path 15548c2ecf20Sopenharmony_ci */ 15558c2ecf20Sopenharmony_ci if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME 15568c2ecf20Sopenharmony_ci | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { 15578c2ecf20Sopenharmony_ci if (status & ATMEL_US_RXBRK) { 15588c2ecf20Sopenharmony_ci /* ignore side-effect */ 15598c2ecf20Sopenharmony_ci status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci port->icount.brk++; 15628c2ecf20Sopenharmony_ci if (uart_handle_break(port)) 15638c2ecf20Sopenharmony_ci continue; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci if (status & ATMEL_US_PARE) 15668c2ecf20Sopenharmony_ci port->icount.parity++; 15678c2ecf20Sopenharmony_ci if (status & ATMEL_US_FRAME) 15688c2ecf20Sopenharmony_ci port->icount.frame++; 15698c2ecf20Sopenharmony_ci if (status & ATMEL_US_OVRE) 15708c2ecf20Sopenharmony_ci port->icount.overrun++; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci status &= port->read_status_mask; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if (status & ATMEL_US_RXBRK) 15758c2ecf20Sopenharmony_ci flg = TTY_BREAK; 15768c2ecf20Sopenharmony_ci else if (status & ATMEL_US_PARE) 15778c2ecf20Sopenharmony_ci flg = TTY_PARITY; 15788c2ecf20Sopenharmony_ci else if (status & ATMEL_US_FRAME) 15798c2ecf20Sopenharmony_ci flg = TTY_FRAME; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci if (uart_handle_sysrq_char(port, c.ch)) 15848c2ecf20Sopenharmony_ci continue; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci /* 15908c2ecf20Sopenharmony_ci * Drop the lock here since it might end up calling 15918c2ecf20Sopenharmony_ci * uart_start(), which takes the lock. 15928c2ecf20Sopenharmony_ci */ 15938c2ecf20Sopenharmony_ci spin_unlock(&port->lock); 15948c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->state->port); 15958c2ecf20Sopenharmony_ci spin_lock(&port->lock); 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic void atmel_release_rx_pdc(struct uart_port *port) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 16018c2ecf20Sopenharmony_ci int i; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 16048c2ecf20Sopenharmony_ci struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci dma_unmap_single(port->dev, 16078c2ecf20Sopenharmony_ci pdc->dma_addr, 16088c2ecf20Sopenharmony_ci pdc->dma_size, 16098c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 16108c2ecf20Sopenharmony_ci kfree(pdc->buf); 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic void atmel_rx_from_pdc(struct uart_port *port) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 16178c2ecf20Sopenharmony_ci struct tty_port *tport = &port->state->port; 16188c2ecf20Sopenharmony_ci struct atmel_dma_buffer *pdc; 16198c2ecf20Sopenharmony_ci int rx_idx = atmel_port->pdc_rx_idx; 16208c2ecf20Sopenharmony_ci unsigned int head; 16218c2ecf20Sopenharmony_ci unsigned int tail; 16228c2ecf20Sopenharmony_ci unsigned int count; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci do { 16258c2ecf20Sopenharmony_ci /* Reset the UART timeout early so that we don't miss one */ 16268c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci pdc = &atmel_port->pdc_rx[rx_idx]; 16298c2ecf20Sopenharmony_ci head = atmel_uart_readl(port, ATMEL_PDC_RPR) - pdc->dma_addr; 16308c2ecf20Sopenharmony_ci tail = pdc->ofs; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci /* If the PDC has switched buffers, RPR won't contain 16338c2ecf20Sopenharmony_ci * any address within the current buffer. Since head 16348c2ecf20Sopenharmony_ci * is unsigned, we just need a one-way comparison to 16358c2ecf20Sopenharmony_ci * find out. 16368c2ecf20Sopenharmony_ci * 16378c2ecf20Sopenharmony_ci * In this case, we just need to consume the entire 16388c2ecf20Sopenharmony_ci * buffer and resubmit it for DMA. This will clear the 16398c2ecf20Sopenharmony_ci * ENDRX bit as well, so that we can safely re-enable 16408c2ecf20Sopenharmony_ci * all interrupts below. 16418c2ecf20Sopenharmony_ci */ 16428c2ecf20Sopenharmony_ci head = min(head, pdc->dma_size); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (likely(head != tail)) { 16458c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(port->dev, pdc->dma_addr, 16468c2ecf20Sopenharmony_ci pdc->dma_size, DMA_FROM_DEVICE); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* 16498c2ecf20Sopenharmony_ci * head will only wrap around when we recycle 16508c2ecf20Sopenharmony_ci * the DMA buffer, and when that happens, we 16518c2ecf20Sopenharmony_ci * explicitly set tail to 0. So head will 16528c2ecf20Sopenharmony_ci * always be greater than tail. 16538c2ecf20Sopenharmony_ci */ 16548c2ecf20Sopenharmony_ci count = head - tail; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci tty_insert_flip_string(tport, pdc->buf + pdc->ofs, 16578c2ecf20Sopenharmony_ci count); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci dma_sync_single_for_device(port->dev, pdc->dma_addr, 16608c2ecf20Sopenharmony_ci pdc->dma_size, DMA_FROM_DEVICE); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci port->icount.rx += count; 16638c2ecf20Sopenharmony_ci pdc->ofs = head; 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci /* 16678c2ecf20Sopenharmony_ci * If the current buffer is full, we need to check if 16688c2ecf20Sopenharmony_ci * the next one contains any additional data. 16698c2ecf20Sopenharmony_ci */ 16708c2ecf20Sopenharmony_ci if (head >= pdc->dma_size) { 16718c2ecf20Sopenharmony_ci pdc->ofs = 0; 16728c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_RNPR, pdc->dma_addr); 16738c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_RNCR, pdc->dma_size); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci rx_idx = !rx_idx; 16768c2ecf20Sopenharmony_ci atmel_port->pdc_rx_idx = rx_idx; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci } while (head >= pdc->dma_size); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* 16818c2ecf20Sopenharmony_ci * Drop the lock here since it might end up calling 16828c2ecf20Sopenharmony_ci * uart_start(), which takes the lock. 16838c2ecf20Sopenharmony_ci */ 16848c2ecf20Sopenharmony_ci spin_unlock(&port->lock); 16858c2ecf20Sopenharmony_ci tty_flip_buffer_push(tport); 16868c2ecf20Sopenharmony_ci spin_lock(&port->lock); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 16898c2ecf20Sopenharmony_ci ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic int atmel_prepare_rx_pdc(struct uart_port *port) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 16958c2ecf20Sopenharmony_ci int i; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 16988c2ecf20Sopenharmony_ci struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); 17018c2ecf20Sopenharmony_ci if (pdc->buf == NULL) { 17028c2ecf20Sopenharmony_ci if (i != 0) { 17038c2ecf20Sopenharmony_ci dma_unmap_single(port->dev, 17048c2ecf20Sopenharmony_ci atmel_port->pdc_rx[0].dma_addr, 17058c2ecf20Sopenharmony_ci PDC_BUFFER_SIZE, 17068c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 17078c2ecf20Sopenharmony_ci kfree(atmel_port->pdc_rx[0].buf); 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci atmel_port->use_pdc_rx = false; 17108c2ecf20Sopenharmony_ci return -ENOMEM; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci pdc->dma_addr = dma_map_single(port->dev, 17138c2ecf20Sopenharmony_ci pdc->buf, 17148c2ecf20Sopenharmony_ci PDC_BUFFER_SIZE, 17158c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 17168c2ecf20Sopenharmony_ci pdc->dma_size = PDC_BUFFER_SIZE; 17178c2ecf20Sopenharmony_ci pdc->ofs = 0; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci atmel_port->pdc_rx_idx = 0; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_RPR, atmel_port->pdc_rx[0].dma_addr); 17238c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_RCR, PDC_BUFFER_SIZE); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_RNPR, 17268c2ecf20Sopenharmony_ci atmel_port->pdc_rx[1].dma_addr); 17278c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_RNCR, PDC_BUFFER_SIZE); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci return 0; 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci/* 17338c2ecf20Sopenharmony_ci * tasklet handling tty stuff outside the interrupt handler. 17348c2ecf20Sopenharmony_ci */ 17358c2ecf20Sopenharmony_cistatic void atmel_tasklet_rx_func(struct tasklet_struct *t) 17368c2ecf20Sopenharmony_ci{ 17378c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, 17388c2ecf20Sopenharmony_ci tasklet_rx); 17398c2ecf20Sopenharmony_ci struct uart_port *port = &atmel_port->uart; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci /* The interrupt handler does not take the lock */ 17428c2ecf20Sopenharmony_ci spin_lock(&port->lock); 17438c2ecf20Sopenharmony_ci atmel_port->schedule_rx(port); 17448c2ecf20Sopenharmony_ci spin_unlock(&port->lock); 17458c2ecf20Sopenharmony_ci} 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cistatic void atmel_tasklet_tx_func(struct tasklet_struct *t) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = from_tasklet(atmel_port, t, 17508c2ecf20Sopenharmony_ci tasklet_tx); 17518c2ecf20Sopenharmony_ci struct uart_port *port = &atmel_port->uart; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci /* The interrupt handler does not take the lock */ 17548c2ecf20Sopenharmony_ci spin_lock(&port->lock); 17558c2ecf20Sopenharmony_ci atmel_port->schedule_tx(port); 17568c2ecf20Sopenharmony_ci spin_unlock(&port->lock); 17578c2ecf20Sopenharmony_ci} 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_cistatic void atmel_init_property(struct atmel_uart_port *atmel_port, 17608c2ecf20Sopenharmony_ci struct platform_device *pdev) 17618c2ecf20Sopenharmony_ci{ 17628c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci /* DMA/PDC usage specification */ 17658c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "atmel,use-dma-rx")) { 17668c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "dmas")) { 17678c2ecf20Sopenharmony_ci atmel_port->use_dma_rx = true; 17688c2ecf20Sopenharmony_ci atmel_port->use_pdc_rx = false; 17698c2ecf20Sopenharmony_ci } else { 17708c2ecf20Sopenharmony_ci atmel_port->use_dma_rx = false; 17718c2ecf20Sopenharmony_ci atmel_port->use_pdc_rx = true; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci } else { 17748c2ecf20Sopenharmony_ci atmel_port->use_dma_rx = false; 17758c2ecf20Sopenharmony_ci atmel_port->use_pdc_rx = false; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "atmel,use-dma-tx")) { 17798c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "dmas")) { 17808c2ecf20Sopenharmony_ci atmel_port->use_dma_tx = true; 17818c2ecf20Sopenharmony_ci atmel_port->use_pdc_tx = false; 17828c2ecf20Sopenharmony_ci } else { 17838c2ecf20Sopenharmony_ci atmel_port->use_dma_tx = false; 17848c2ecf20Sopenharmony_ci atmel_port->use_pdc_tx = true; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci } else { 17878c2ecf20Sopenharmony_ci atmel_port->use_dma_tx = false; 17888c2ecf20Sopenharmony_ci atmel_port->use_pdc_tx = false; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_cistatic void atmel_set_ops(struct uart_port *port) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (atmel_use_dma_rx(port)) { 17978c2ecf20Sopenharmony_ci atmel_port->prepare_rx = &atmel_prepare_rx_dma; 17988c2ecf20Sopenharmony_ci atmel_port->schedule_rx = &atmel_rx_from_dma; 17998c2ecf20Sopenharmony_ci atmel_port->release_rx = &atmel_release_rx_dma; 18008c2ecf20Sopenharmony_ci } else if (atmel_use_pdc_rx(port)) { 18018c2ecf20Sopenharmony_ci atmel_port->prepare_rx = &atmel_prepare_rx_pdc; 18028c2ecf20Sopenharmony_ci atmel_port->schedule_rx = &atmel_rx_from_pdc; 18038c2ecf20Sopenharmony_ci atmel_port->release_rx = &atmel_release_rx_pdc; 18048c2ecf20Sopenharmony_ci } else { 18058c2ecf20Sopenharmony_ci atmel_port->prepare_rx = NULL; 18068c2ecf20Sopenharmony_ci atmel_port->schedule_rx = &atmel_rx_from_ring; 18078c2ecf20Sopenharmony_ci atmel_port->release_rx = NULL; 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if (atmel_use_dma_tx(port)) { 18118c2ecf20Sopenharmony_ci atmel_port->prepare_tx = &atmel_prepare_tx_dma; 18128c2ecf20Sopenharmony_ci atmel_port->schedule_tx = &atmel_tx_dma; 18138c2ecf20Sopenharmony_ci atmel_port->release_tx = &atmel_release_tx_dma; 18148c2ecf20Sopenharmony_ci } else if (atmel_use_pdc_tx(port)) { 18158c2ecf20Sopenharmony_ci atmel_port->prepare_tx = &atmel_prepare_tx_pdc; 18168c2ecf20Sopenharmony_ci atmel_port->schedule_tx = &atmel_tx_pdc; 18178c2ecf20Sopenharmony_ci atmel_port->release_tx = &atmel_release_tx_pdc; 18188c2ecf20Sopenharmony_ci } else { 18198c2ecf20Sopenharmony_ci atmel_port->prepare_tx = NULL; 18208c2ecf20Sopenharmony_ci atmel_port->schedule_tx = &atmel_tx_chars; 18218c2ecf20Sopenharmony_ci atmel_port->release_tx = NULL; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci} 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci/* 18268c2ecf20Sopenharmony_ci * Get ip name usart or uart 18278c2ecf20Sopenharmony_ci */ 18288c2ecf20Sopenharmony_cistatic void atmel_get_ip_name(struct uart_port *port) 18298c2ecf20Sopenharmony_ci{ 18308c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 18318c2ecf20Sopenharmony_ci int name = atmel_uart_readl(port, ATMEL_US_NAME); 18328c2ecf20Sopenharmony_ci u32 version; 18338c2ecf20Sopenharmony_ci u32 usart, dbgu_uart, new_uart; 18348c2ecf20Sopenharmony_ci /* ASCII decoding for IP version */ 18358c2ecf20Sopenharmony_ci usart = 0x55534152; /* USAR(T) */ 18368c2ecf20Sopenharmony_ci dbgu_uart = 0x44424755; /* DBGU */ 18378c2ecf20Sopenharmony_ci new_uart = 0x55415254; /* UART */ 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci /* 18408c2ecf20Sopenharmony_ci * Only USART devices from at91sam9260 SOC implement fractional 18418c2ecf20Sopenharmony_ci * baudrate. It is available for all asynchronous modes, with the 18428c2ecf20Sopenharmony_ci * following restriction: the sampling clock's duty cycle is not 18438c2ecf20Sopenharmony_ci * constant. 18448c2ecf20Sopenharmony_ci */ 18458c2ecf20Sopenharmony_ci atmel_port->has_frac_baudrate = false; 18468c2ecf20Sopenharmony_ci atmel_port->has_hw_timer = false; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci if (name == new_uart) { 18498c2ecf20Sopenharmony_ci dev_dbg(port->dev, "Uart with hw timer"); 18508c2ecf20Sopenharmony_ci atmel_port->has_hw_timer = true; 18518c2ecf20Sopenharmony_ci atmel_port->rtor = ATMEL_UA_RTOR; 18528c2ecf20Sopenharmony_ci } else if (name == usart) { 18538c2ecf20Sopenharmony_ci dev_dbg(port->dev, "Usart\n"); 18548c2ecf20Sopenharmony_ci atmel_port->has_frac_baudrate = true; 18558c2ecf20Sopenharmony_ci atmel_port->has_hw_timer = true; 18568c2ecf20Sopenharmony_ci atmel_port->rtor = ATMEL_US_RTOR; 18578c2ecf20Sopenharmony_ci version = atmel_uart_readl(port, ATMEL_US_VERSION); 18588c2ecf20Sopenharmony_ci switch (version) { 18598c2ecf20Sopenharmony_ci case 0x814: /* sama5d2 */ 18608c2ecf20Sopenharmony_ci fallthrough; 18618c2ecf20Sopenharmony_ci case 0x701: /* sama5d4 */ 18628c2ecf20Sopenharmony_ci atmel_port->fidi_min = 3; 18638c2ecf20Sopenharmony_ci atmel_port->fidi_max = 65535; 18648c2ecf20Sopenharmony_ci break; 18658c2ecf20Sopenharmony_ci case 0x502: /* sam9x5, sama5d3 */ 18668c2ecf20Sopenharmony_ci atmel_port->fidi_min = 3; 18678c2ecf20Sopenharmony_ci atmel_port->fidi_max = 2047; 18688c2ecf20Sopenharmony_ci break; 18698c2ecf20Sopenharmony_ci default: 18708c2ecf20Sopenharmony_ci atmel_port->fidi_min = 1; 18718c2ecf20Sopenharmony_ci atmel_port->fidi_max = 2047; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci } else if (name == dbgu_uart) { 18748c2ecf20Sopenharmony_ci dev_dbg(port->dev, "Dbgu or uart without hw timer\n"); 18758c2ecf20Sopenharmony_ci } else { 18768c2ecf20Sopenharmony_ci /* fallback for older SoCs: use version field */ 18778c2ecf20Sopenharmony_ci version = atmel_uart_readl(port, ATMEL_US_VERSION); 18788c2ecf20Sopenharmony_ci switch (version) { 18798c2ecf20Sopenharmony_ci case 0x302: 18808c2ecf20Sopenharmony_ci case 0x10213: 18818c2ecf20Sopenharmony_ci case 0x10302: 18828c2ecf20Sopenharmony_ci dev_dbg(port->dev, "This version is usart\n"); 18838c2ecf20Sopenharmony_ci atmel_port->has_frac_baudrate = true; 18848c2ecf20Sopenharmony_ci atmel_port->has_hw_timer = true; 18858c2ecf20Sopenharmony_ci atmel_port->rtor = ATMEL_US_RTOR; 18868c2ecf20Sopenharmony_ci break; 18878c2ecf20Sopenharmony_ci case 0x203: 18888c2ecf20Sopenharmony_ci case 0x10202: 18898c2ecf20Sopenharmony_ci dev_dbg(port->dev, "This version is uart\n"); 18908c2ecf20Sopenharmony_ci break; 18918c2ecf20Sopenharmony_ci default: 18928c2ecf20Sopenharmony_ci dev_err(port->dev, "Not supported ip name nor version, set to uart\n"); 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci} 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci/* 18988c2ecf20Sopenharmony_ci * Perform initialization and enable port for reception 18998c2ecf20Sopenharmony_ci */ 19008c2ecf20Sopenharmony_cistatic int atmel_startup(struct uart_port *port) 19018c2ecf20Sopenharmony_ci{ 19028c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(port->dev); 19038c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 19048c2ecf20Sopenharmony_ci int retval; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci /* 19078c2ecf20Sopenharmony_ci * Ensure that no interrupts are enabled otherwise when 19088c2ecf20Sopenharmony_ci * request_irq() is called we could get stuck trying to 19098c2ecf20Sopenharmony_ci * handle an unexpected interrupt 19108c2ecf20Sopenharmony_ci */ 19118c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, -1); 19128c2ecf20Sopenharmony_ci atmel_port->ms_irq_enabled = false; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci /* 19158c2ecf20Sopenharmony_ci * Allocate the IRQ 19168c2ecf20Sopenharmony_ci */ 19178c2ecf20Sopenharmony_ci retval = request_irq(port->irq, atmel_interrupt, 19188c2ecf20Sopenharmony_ci IRQF_SHARED | IRQF_COND_SUSPEND, 19198c2ecf20Sopenharmony_ci dev_name(&pdev->dev), port); 19208c2ecf20Sopenharmony_ci if (retval) { 19218c2ecf20Sopenharmony_ci dev_err(port->dev, "atmel_startup - Can't get irq\n"); 19228c2ecf20Sopenharmony_ci return retval; 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci atomic_set(&atmel_port->tasklet_shutdown, 0); 19268c2ecf20Sopenharmony_ci tasklet_setup(&atmel_port->tasklet_rx, atmel_tasklet_rx_func); 19278c2ecf20Sopenharmony_ci tasklet_setup(&atmel_port->tasklet_tx, atmel_tasklet_tx_func); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci /* 19308c2ecf20Sopenharmony_ci * Initialize DMA (if necessary) 19318c2ecf20Sopenharmony_ci */ 19328c2ecf20Sopenharmony_ci atmel_init_property(atmel_port, pdev); 19338c2ecf20Sopenharmony_ci atmel_set_ops(port); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci if (atmel_port->prepare_rx) { 19368c2ecf20Sopenharmony_ci retval = atmel_port->prepare_rx(port); 19378c2ecf20Sopenharmony_ci if (retval < 0) 19388c2ecf20Sopenharmony_ci atmel_set_ops(port); 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci if (atmel_port->prepare_tx) { 19428c2ecf20Sopenharmony_ci retval = atmel_port->prepare_tx(port); 19438c2ecf20Sopenharmony_ci if (retval < 0) 19448c2ecf20Sopenharmony_ci atmel_set_ops(port); 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci /* 19488c2ecf20Sopenharmony_ci * Enable FIFO when available 19498c2ecf20Sopenharmony_ci */ 19508c2ecf20Sopenharmony_ci if (atmel_port->fifo_size) { 19518c2ecf20Sopenharmony_ci unsigned int txrdym = ATMEL_US_ONE_DATA; 19528c2ecf20Sopenharmony_ci unsigned int rxrdym = ATMEL_US_ONE_DATA; 19538c2ecf20Sopenharmony_ci unsigned int fmr; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, 19568c2ecf20Sopenharmony_ci ATMEL_US_FIFOEN | 19578c2ecf20Sopenharmony_ci ATMEL_US_RXFCLR | 19588c2ecf20Sopenharmony_ci ATMEL_US_TXFLCLR); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci if (atmel_use_dma_tx(port)) 19618c2ecf20Sopenharmony_ci txrdym = ATMEL_US_FOUR_DATA; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci fmr = ATMEL_US_TXRDYM(txrdym) | ATMEL_US_RXRDYM(rxrdym); 19648c2ecf20Sopenharmony_ci if (atmel_port->rts_high && 19658c2ecf20Sopenharmony_ci atmel_port->rts_low) 19668c2ecf20Sopenharmony_ci fmr |= ATMEL_US_FRTSC | 19678c2ecf20Sopenharmony_ci ATMEL_US_RXFTHRES(atmel_port->rts_high) | 19688c2ecf20Sopenharmony_ci ATMEL_US_RXFTHRES2(atmel_port->rts_low); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_FMR, fmr); 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* Save current CSR for comparison in atmel_tasklet_func() */ 19748c2ecf20Sopenharmony_ci atmel_port->irq_status_prev = atmel_uart_readl(port, ATMEL_US_CSR); 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci /* 19778c2ecf20Sopenharmony_ci * Finally, enable the serial port 19788c2ecf20Sopenharmony_ci */ 19798c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); 19808c2ecf20Sopenharmony_ci /* enable xmit & rcvr */ 19818c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); 19828c2ecf20Sopenharmony_ci atmel_port->tx_stopped = false; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci timer_setup(&atmel_port->uart_timer, atmel_uart_timer_callback, 0); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (atmel_use_pdc_rx(port)) { 19878c2ecf20Sopenharmony_ci /* set UART timeout */ 19888c2ecf20Sopenharmony_ci if (!atmel_port->has_hw_timer) { 19898c2ecf20Sopenharmony_ci mod_timer(&atmel_port->uart_timer, 19908c2ecf20Sopenharmony_ci jiffies + uart_poll_timeout(port)); 19918c2ecf20Sopenharmony_ci /* set USART timeout */ 19928c2ecf20Sopenharmony_ci } else { 19938c2ecf20Sopenharmony_ci atmel_uart_writel(port, atmel_port->rtor, 19948c2ecf20Sopenharmony_ci PDC_RX_TIMEOUT); 19958c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 19988c2ecf20Sopenharmony_ci ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci /* enable PDC controller */ 20018c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); 20028c2ecf20Sopenharmony_ci } else if (atmel_use_dma_rx(port)) { 20038c2ecf20Sopenharmony_ci /* set UART timeout */ 20048c2ecf20Sopenharmony_ci if (!atmel_port->has_hw_timer) { 20058c2ecf20Sopenharmony_ci mod_timer(&atmel_port->uart_timer, 20068c2ecf20Sopenharmony_ci jiffies + uart_poll_timeout(port)); 20078c2ecf20Sopenharmony_ci /* set USART timeout */ 20088c2ecf20Sopenharmony_ci } else { 20098c2ecf20Sopenharmony_ci atmel_uart_writel(port, atmel_port->rtor, 20108c2ecf20Sopenharmony_ci PDC_RX_TIMEOUT); 20118c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, 20148c2ecf20Sopenharmony_ci ATMEL_US_TIMEOUT); 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci } else { 20178c2ecf20Sopenharmony_ci /* enable receive only */ 20188c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci return 0; 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci/* 20258c2ecf20Sopenharmony_ci * Flush any TX data submitted for DMA. Called when the TX circular 20268c2ecf20Sopenharmony_ci * buffer is reset. 20278c2ecf20Sopenharmony_ci */ 20288c2ecf20Sopenharmony_cistatic void atmel_flush_buffer(struct uart_port *port) 20298c2ecf20Sopenharmony_ci{ 20308c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci if (atmel_use_pdc_tx(port)) { 20338c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_TCR, 0); 20348c2ecf20Sopenharmony_ci atmel_port->pdc_tx.ofs = 0; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci /* 20378c2ecf20Sopenharmony_ci * in uart_flush_buffer(), the xmit circular buffer has just 20388c2ecf20Sopenharmony_ci * been cleared, so we have to reset tx_len accordingly. 20398c2ecf20Sopenharmony_ci */ 20408c2ecf20Sopenharmony_ci atmel_port->tx_len = 0; 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci/* 20448c2ecf20Sopenharmony_ci * Disable the port 20458c2ecf20Sopenharmony_ci */ 20468c2ecf20Sopenharmony_cistatic void atmel_shutdown(struct uart_port *port) 20478c2ecf20Sopenharmony_ci{ 20488c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci /* Disable modem control lines interrupts */ 20518c2ecf20Sopenharmony_ci atmel_disable_ms(port); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* Disable interrupts at device level */ 20548c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, -1); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci /* Prevent spurious interrupts from scheduling the tasklet */ 20578c2ecf20Sopenharmony_ci atomic_inc(&atmel_port->tasklet_shutdown); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci /* 20608c2ecf20Sopenharmony_ci * Prevent any tasklets being scheduled during 20618c2ecf20Sopenharmony_ci * cleanup 20628c2ecf20Sopenharmony_ci */ 20638c2ecf20Sopenharmony_ci del_timer_sync(&atmel_port->uart_timer); 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci /* Make sure that no interrupt is on the fly */ 20668c2ecf20Sopenharmony_ci synchronize_irq(port->irq); 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci /* 20698c2ecf20Sopenharmony_ci * Clear out any scheduled tasklets before 20708c2ecf20Sopenharmony_ci * we destroy the buffers 20718c2ecf20Sopenharmony_ci */ 20728c2ecf20Sopenharmony_ci tasklet_kill(&atmel_port->tasklet_rx); 20738c2ecf20Sopenharmony_ci tasklet_kill(&atmel_port->tasklet_tx); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci /* 20768c2ecf20Sopenharmony_ci * Ensure everything is stopped and 20778c2ecf20Sopenharmony_ci * disable port and break condition. 20788c2ecf20Sopenharmony_ci */ 20798c2ecf20Sopenharmony_ci atmel_stop_rx(port); 20808c2ecf20Sopenharmony_ci atmel_stop_tx(port); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci /* 20858c2ecf20Sopenharmony_ci * Shut-down the DMA. 20868c2ecf20Sopenharmony_ci */ 20878c2ecf20Sopenharmony_ci if (atmel_port->release_rx) 20888c2ecf20Sopenharmony_ci atmel_port->release_rx(port); 20898c2ecf20Sopenharmony_ci if (atmel_port->release_tx) 20908c2ecf20Sopenharmony_ci atmel_port->release_tx(port); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci /* 20938c2ecf20Sopenharmony_ci * Reset ring buffer pointers 20948c2ecf20Sopenharmony_ci */ 20958c2ecf20Sopenharmony_ci atmel_port->rx_ring.head = 0; 20968c2ecf20Sopenharmony_ci atmel_port->rx_ring.tail = 0; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci /* 20998c2ecf20Sopenharmony_ci * Free the interrupts 21008c2ecf20Sopenharmony_ci */ 21018c2ecf20Sopenharmony_ci free_irq(port->irq, port); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci atmel_flush_buffer(port); 21048c2ecf20Sopenharmony_ci} 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci/* 21078c2ecf20Sopenharmony_ci * Power / Clock management. 21088c2ecf20Sopenharmony_ci */ 21098c2ecf20Sopenharmony_cistatic void atmel_serial_pm(struct uart_port *port, unsigned int state, 21108c2ecf20Sopenharmony_ci unsigned int oldstate) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci switch (state) { 21158c2ecf20Sopenharmony_ci case 0: 21168c2ecf20Sopenharmony_ci /* 21178c2ecf20Sopenharmony_ci * Enable the peripheral clock for this serial port. 21188c2ecf20Sopenharmony_ci * This is called on uart_open() or a resume event. 21198c2ecf20Sopenharmony_ci */ 21208c2ecf20Sopenharmony_ci clk_prepare_enable(atmel_port->clk); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci /* re-enable interrupts if we disabled some on suspend */ 21238c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); 21248c2ecf20Sopenharmony_ci break; 21258c2ecf20Sopenharmony_ci case 3: 21268c2ecf20Sopenharmony_ci /* Back up the interrupt mask and disable all interrupts */ 21278c2ecf20Sopenharmony_ci atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); 21288c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, -1); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci /* 21318c2ecf20Sopenharmony_ci * Disable the peripheral clock for this serial port. 21328c2ecf20Sopenharmony_ci * This is called on uart_close() or a suspend event. 21338c2ecf20Sopenharmony_ci */ 21348c2ecf20Sopenharmony_ci clk_disable_unprepare(atmel_port->clk); 21358c2ecf20Sopenharmony_ci break; 21368c2ecf20Sopenharmony_ci default: 21378c2ecf20Sopenharmony_ci dev_err(port->dev, "atmel_serial: unknown pm %d\n", state); 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci} 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci/* 21428c2ecf20Sopenharmony_ci * Change the port parameters 21438c2ecf20Sopenharmony_ci */ 21448c2ecf20Sopenharmony_cistatic void atmel_set_termios(struct uart_port *port, struct ktermios *termios, 21458c2ecf20Sopenharmony_ci struct ktermios *old) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 21488c2ecf20Sopenharmony_ci unsigned long flags; 21498c2ecf20Sopenharmony_ci unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci /* save the current mode register */ 21528c2ecf20Sopenharmony_ci mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci /* reset the mode, clock divisor, parity, stop bits and data size */ 21558c2ecf20Sopenharmony_ci mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | 21568c2ecf20Sopenharmony_ci ATMEL_US_PAR | ATMEL_US_USMODE); 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* byte size */ 21618c2ecf20Sopenharmony_ci switch (termios->c_cflag & CSIZE) { 21628c2ecf20Sopenharmony_ci case CS5: 21638c2ecf20Sopenharmony_ci mode |= ATMEL_US_CHRL_5; 21648c2ecf20Sopenharmony_ci break; 21658c2ecf20Sopenharmony_ci case CS6: 21668c2ecf20Sopenharmony_ci mode |= ATMEL_US_CHRL_6; 21678c2ecf20Sopenharmony_ci break; 21688c2ecf20Sopenharmony_ci case CS7: 21698c2ecf20Sopenharmony_ci mode |= ATMEL_US_CHRL_7; 21708c2ecf20Sopenharmony_ci break; 21718c2ecf20Sopenharmony_ci default: 21728c2ecf20Sopenharmony_ci mode |= ATMEL_US_CHRL_8; 21738c2ecf20Sopenharmony_ci break; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci /* stop bits */ 21778c2ecf20Sopenharmony_ci if (termios->c_cflag & CSTOPB) 21788c2ecf20Sopenharmony_ci mode |= ATMEL_US_NBSTOP_2; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* parity */ 21818c2ecf20Sopenharmony_ci if (termios->c_cflag & PARENB) { 21828c2ecf20Sopenharmony_ci /* Mark or Space parity */ 21838c2ecf20Sopenharmony_ci if (termios->c_cflag & CMSPAR) { 21848c2ecf20Sopenharmony_ci if (termios->c_cflag & PARODD) 21858c2ecf20Sopenharmony_ci mode |= ATMEL_US_PAR_MARK; 21868c2ecf20Sopenharmony_ci else 21878c2ecf20Sopenharmony_ci mode |= ATMEL_US_PAR_SPACE; 21888c2ecf20Sopenharmony_ci } else if (termios->c_cflag & PARODD) 21898c2ecf20Sopenharmony_ci mode |= ATMEL_US_PAR_ODD; 21908c2ecf20Sopenharmony_ci else 21918c2ecf20Sopenharmony_ci mode |= ATMEL_US_PAR_EVEN; 21928c2ecf20Sopenharmony_ci } else 21938c2ecf20Sopenharmony_ci mode |= ATMEL_US_PAR_NONE; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci port->read_status_mask = ATMEL_US_OVRE; 21988c2ecf20Sopenharmony_ci if (termios->c_iflag & INPCK) 21998c2ecf20Sopenharmony_ci port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); 22008c2ecf20Sopenharmony_ci if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 22018c2ecf20Sopenharmony_ci port->read_status_mask |= ATMEL_US_RXBRK; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (atmel_use_pdc_rx(port)) 22048c2ecf20Sopenharmony_ci /* need to enable error interrupts */ 22058c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, port->read_status_mask); 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci /* 22088c2ecf20Sopenharmony_ci * Characters to ignore 22098c2ecf20Sopenharmony_ci */ 22108c2ecf20Sopenharmony_ci port->ignore_status_mask = 0; 22118c2ecf20Sopenharmony_ci if (termios->c_iflag & IGNPAR) 22128c2ecf20Sopenharmony_ci port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE); 22138c2ecf20Sopenharmony_ci if (termios->c_iflag & IGNBRK) { 22148c2ecf20Sopenharmony_ci port->ignore_status_mask |= ATMEL_US_RXBRK; 22158c2ecf20Sopenharmony_ci /* 22168c2ecf20Sopenharmony_ci * If we're ignoring parity and break indicators, 22178c2ecf20Sopenharmony_ci * ignore overruns too (for real raw support). 22188c2ecf20Sopenharmony_ci */ 22198c2ecf20Sopenharmony_ci if (termios->c_iflag & IGNPAR) 22208c2ecf20Sopenharmony_ci port->ignore_status_mask |= ATMEL_US_OVRE; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci /* TODO: Ignore all characters if CREAD is set.*/ 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci /* update the per-port timeout */ 22258c2ecf20Sopenharmony_ci uart_update_timeout(port, termios->c_cflag, baud); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci /* 22288c2ecf20Sopenharmony_ci * save/disable interrupts. The tty layer will ensure that the 22298c2ecf20Sopenharmony_ci * transmitter is empty if requested by the caller, so there's 22308c2ecf20Sopenharmony_ci * no need to wait for it here. 22318c2ecf20Sopenharmony_ci */ 22328c2ecf20Sopenharmony_ci imr = atmel_uart_readl(port, ATMEL_US_IMR); 22338c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, -1); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci /* disable receiver and transmitter */ 22368c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXDIS); 22378c2ecf20Sopenharmony_ci atmel_port->tx_stopped = true; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci /* mode */ 22408c2ecf20Sopenharmony_ci if (port->rs485.flags & SER_RS485_ENABLED) { 22418c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_TTGR, 22428c2ecf20Sopenharmony_ci port->rs485.delay_rts_after_send); 22438c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_RS485; 22448c2ecf20Sopenharmony_ci } else if (port->iso7816.flags & SER_ISO7816_ENABLED) { 22458c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg); 22468c2ecf20Sopenharmony_ci /* select mck clock, and output */ 22478c2ecf20Sopenharmony_ci mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO; 22488c2ecf20Sopenharmony_ci /* set max iterations */ 22498c2ecf20Sopenharmony_ci mode |= ATMEL_US_MAX_ITER(3); 22508c2ecf20Sopenharmony_ci if ((port->iso7816.flags & SER_ISO7816_T_PARAM) 22518c2ecf20Sopenharmony_ci == SER_ISO7816_T(0)) 22528c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_ISO7816_T0; 22538c2ecf20Sopenharmony_ci else 22548c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_ISO7816_T1; 22558c2ecf20Sopenharmony_ci } else if (termios->c_cflag & CRTSCTS) { 22568c2ecf20Sopenharmony_ci /* RS232 with hardware handshake (RTS/CTS) */ 22578c2ecf20Sopenharmony_ci if (atmel_use_fifo(port) && 22588c2ecf20Sopenharmony_ci !mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS)) { 22598c2ecf20Sopenharmony_ci /* 22608c2ecf20Sopenharmony_ci * with ATMEL_US_USMODE_HWHS set, the controller will 22618c2ecf20Sopenharmony_ci * be able to drive the RTS pin high/low when the RX 22628c2ecf20Sopenharmony_ci * FIFO is above RXFTHRES/below RXFTHRES2. 22638c2ecf20Sopenharmony_ci * It will also disable the transmitter when the CTS 22648c2ecf20Sopenharmony_ci * pin is high. 22658c2ecf20Sopenharmony_ci * This mode is not activated if CTS pin is a GPIO 22668c2ecf20Sopenharmony_ci * because in this case, the transmitter is always 22678c2ecf20Sopenharmony_ci * disabled (there must be an internal pull-up 22688c2ecf20Sopenharmony_ci * responsible for this behaviour). 22698c2ecf20Sopenharmony_ci * If the RTS pin is a GPIO, the controller won't be 22708c2ecf20Sopenharmony_ci * able to drive it according to the FIFO thresholds, 22718c2ecf20Sopenharmony_ci * but it will be handled by the driver. 22728c2ecf20Sopenharmony_ci */ 22738c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_HWHS; 22748c2ecf20Sopenharmony_ci } else { 22758c2ecf20Sopenharmony_ci /* 22768c2ecf20Sopenharmony_ci * For platforms without FIFO, the flow control is 22778c2ecf20Sopenharmony_ci * handled by the driver. 22788c2ecf20Sopenharmony_ci */ 22798c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_NORMAL; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci } else { 22828c2ecf20Sopenharmony_ci /* RS232 without hadware handshake */ 22838c2ecf20Sopenharmony_ci mode |= ATMEL_US_USMODE_NORMAL; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci /* 22878c2ecf20Sopenharmony_ci * Set the baud rate: 22888c2ecf20Sopenharmony_ci * Fractional baudrate allows to setup output frequency more 22898c2ecf20Sopenharmony_ci * accurately. This feature is enabled only when using normal mode. 22908c2ecf20Sopenharmony_ci * baudrate = selected clock / (8 * (2 - OVER) * (CD + FP / 8)) 22918c2ecf20Sopenharmony_ci * Currently, OVER is always set to 0 so we get 22928c2ecf20Sopenharmony_ci * baudrate = selected clock / (16 * (CD + FP / 8)) 22938c2ecf20Sopenharmony_ci * then 22948c2ecf20Sopenharmony_ci * 8 CD + FP = selected clock / (2 * baudrate) 22958c2ecf20Sopenharmony_ci */ 22968c2ecf20Sopenharmony_ci if (atmel_port->has_frac_baudrate) { 22978c2ecf20Sopenharmony_ci div = DIV_ROUND_CLOSEST(port->uartclk, baud * 2); 22988c2ecf20Sopenharmony_ci cd = div >> 3; 22998c2ecf20Sopenharmony_ci fp = div & ATMEL_US_FP_MASK; 23008c2ecf20Sopenharmony_ci } else { 23018c2ecf20Sopenharmony_ci cd = uart_get_divisor(port, baud); 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (cd > 65535) { /* BRGR is 16-bit, so switch to slower clock */ 23058c2ecf20Sopenharmony_ci cd /= 8; 23068c2ecf20Sopenharmony_ci mode |= ATMEL_US_USCLKS_MCK_DIV8; 23078c2ecf20Sopenharmony_ci } 23088c2ecf20Sopenharmony_ci quot = cd | fp << ATMEL_US_FP_OFFSET; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) 23118c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_BRGR, quot); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci /* set the mode, clock divisor, parity, stop bits and data size */ 23148c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_MR, mode); 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci /* 23178c2ecf20Sopenharmony_ci * when switching the mode, set the RTS line state according to the 23188c2ecf20Sopenharmony_ci * new mode, otherwise keep the former state 23198c2ecf20Sopenharmony_ci */ 23208c2ecf20Sopenharmony_ci if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) { 23218c2ecf20Sopenharmony_ci unsigned int rts_state; 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) { 23248c2ecf20Sopenharmony_ci /* let the hardware control the RTS line */ 23258c2ecf20Sopenharmony_ci rts_state = ATMEL_US_RTSDIS; 23268c2ecf20Sopenharmony_ci } else { 23278c2ecf20Sopenharmony_ci /* force RTS line to low level */ 23288c2ecf20Sopenharmony_ci rts_state = ATMEL_US_RTSEN; 23298c2ecf20Sopenharmony_ci } 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, rts_state); 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); 23358c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); 23368c2ecf20Sopenharmony_ci atmel_port->tx_stopped = false; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci /* restore interrupts */ 23398c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, imr); 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci /* CTS flow-control and modem-status interrupts */ 23428c2ecf20Sopenharmony_ci if (UART_ENABLE_MS(port, termios->c_cflag)) 23438c2ecf20Sopenharmony_ci atmel_enable_ms(port); 23448c2ecf20Sopenharmony_ci else 23458c2ecf20Sopenharmony_ci atmel_disable_ms(port); 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 23488c2ecf20Sopenharmony_ci} 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_cistatic void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios) 23518c2ecf20Sopenharmony_ci{ 23528c2ecf20Sopenharmony_ci if (termios->c_line == N_PPS) { 23538c2ecf20Sopenharmony_ci port->flags |= UPF_HARDPPS_CD; 23548c2ecf20Sopenharmony_ci spin_lock_irq(&port->lock); 23558c2ecf20Sopenharmony_ci atmel_enable_ms(port); 23568c2ecf20Sopenharmony_ci spin_unlock_irq(&port->lock); 23578c2ecf20Sopenharmony_ci } else { 23588c2ecf20Sopenharmony_ci port->flags &= ~UPF_HARDPPS_CD; 23598c2ecf20Sopenharmony_ci if (!UART_ENABLE_MS(port, termios->c_cflag)) { 23608c2ecf20Sopenharmony_ci spin_lock_irq(&port->lock); 23618c2ecf20Sopenharmony_ci atmel_disable_ms(port); 23628c2ecf20Sopenharmony_ci spin_unlock_irq(&port->lock); 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci} 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci/* 23688c2ecf20Sopenharmony_ci * Return string describing the specified port 23698c2ecf20Sopenharmony_ci */ 23708c2ecf20Sopenharmony_cistatic const char *atmel_type(struct uart_port *port) 23718c2ecf20Sopenharmony_ci{ 23728c2ecf20Sopenharmony_ci return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL; 23738c2ecf20Sopenharmony_ci} 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci/* 23768c2ecf20Sopenharmony_ci * Release the memory region(s) being used by 'port'. 23778c2ecf20Sopenharmony_ci */ 23788c2ecf20Sopenharmony_cistatic void atmel_release_port(struct uart_port *port) 23798c2ecf20Sopenharmony_ci{ 23808c2ecf20Sopenharmony_ci struct platform_device *mpdev = to_platform_device(port->dev->parent); 23818c2ecf20Sopenharmony_ci int size = resource_size(mpdev->resource); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci release_mem_region(port->mapbase, size); 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci if (port->flags & UPF_IOREMAP) { 23868c2ecf20Sopenharmony_ci iounmap(port->membase); 23878c2ecf20Sopenharmony_ci port->membase = NULL; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci} 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci/* 23928c2ecf20Sopenharmony_ci * Request the memory region(s) being used by 'port'. 23938c2ecf20Sopenharmony_ci */ 23948c2ecf20Sopenharmony_cistatic int atmel_request_port(struct uart_port *port) 23958c2ecf20Sopenharmony_ci{ 23968c2ecf20Sopenharmony_ci struct platform_device *mpdev = to_platform_device(port->dev->parent); 23978c2ecf20Sopenharmony_ci int size = resource_size(mpdev->resource); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci if (!request_mem_region(port->mapbase, size, "atmel_serial")) 24008c2ecf20Sopenharmony_ci return -EBUSY; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci if (port->flags & UPF_IOREMAP) { 24038c2ecf20Sopenharmony_ci port->membase = ioremap(port->mapbase, size); 24048c2ecf20Sopenharmony_ci if (port->membase == NULL) { 24058c2ecf20Sopenharmony_ci release_mem_region(port->mapbase, size); 24068c2ecf20Sopenharmony_ci return -ENOMEM; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci return 0; 24118c2ecf20Sopenharmony_ci} 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci/* 24148c2ecf20Sopenharmony_ci * Configure/autoconfigure the port. 24158c2ecf20Sopenharmony_ci */ 24168c2ecf20Sopenharmony_cistatic void atmel_config_port(struct uart_port *port, int flags) 24178c2ecf20Sopenharmony_ci{ 24188c2ecf20Sopenharmony_ci if (flags & UART_CONFIG_TYPE) { 24198c2ecf20Sopenharmony_ci port->type = PORT_ATMEL; 24208c2ecf20Sopenharmony_ci atmel_request_port(port); 24218c2ecf20Sopenharmony_ci } 24228c2ecf20Sopenharmony_ci} 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci/* 24258c2ecf20Sopenharmony_ci * Verify the new serial_struct (for TIOCSSERIAL). 24268c2ecf20Sopenharmony_ci */ 24278c2ecf20Sopenharmony_cistatic int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) 24288c2ecf20Sopenharmony_ci{ 24298c2ecf20Sopenharmony_ci int ret = 0; 24308c2ecf20Sopenharmony_ci if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL) 24318c2ecf20Sopenharmony_ci ret = -EINVAL; 24328c2ecf20Sopenharmony_ci if (port->irq != ser->irq) 24338c2ecf20Sopenharmony_ci ret = -EINVAL; 24348c2ecf20Sopenharmony_ci if (ser->io_type != SERIAL_IO_MEM) 24358c2ecf20Sopenharmony_ci ret = -EINVAL; 24368c2ecf20Sopenharmony_ci if (port->uartclk / 16 != ser->baud_base) 24378c2ecf20Sopenharmony_ci ret = -EINVAL; 24388c2ecf20Sopenharmony_ci if (port->mapbase != (unsigned long)ser->iomem_base) 24398c2ecf20Sopenharmony_ci ret = -EINVAL; 24408c2ecf20Sopenharmony_ci if (port->iobase != ser->port) 24418c2ecf20Sopenharmony_ci ret = -EINVAL; 24428c2ecf20Sopenharmony_ci if (ser->hub6 != 0) 24438c2ecf20Sopenharmony_ci ret = -EINVAL; 24448c2ecf20Sopenharmony_ci return ret; 24458c2ecf20Sopenharmony_ci} 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci#ifdef CONFIG_CONSOLE_POLL 24488c2ecf20Sopenharmony_cistatic int atmel_poll_get_char(struct uart_port *port) 24498c2ecf20Sopenharmony_ci{ 24508c2ecf20Sopenharmony_ci while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) 24518c2ecf20Sopenharmony_ci cpu_relax(); 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci return atmel_uart_read_char(port); 24548c2ecf20Sopenharmony_ci} 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_cistatic void atmel_poll_put_char(struct uart_port *port, unsigned char ch) 24578c2ecf20Sopenharmony_ci{ 24588c2ecf20Sopenharmony_ci while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) 24598c2ecf20Sopenharmony_ci cpu_relax(); 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci atmel_uart_write_char(port, ch); 24628c2ecf20Sopenharmony_ci} 24638c2ecf20Sopenharmony_ci#endif 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_cistatic const struct uart_ops atmel_pops = { 24668c2ecf20Sopenharmony_ci .tx_empty = atmel_tx_empty, 24678c2ecf20Sopenharmony_ci .set_mctrl = atmel_set_mctrl, 24688c2ecf20Sopenharmony_ci .get_mctrl = atmel_get_mctrl, 24698c2ecf20Sopenharmony_ci .stop_tx = atmel_stop_tx, 24708c2ecf20Sopenharmony_ci .start_tx = atmel_start_tx, 24718c2ecf20Sopenharmony_ci .stop_rx = atmel_stop_rx, 24728c2ecf20Sopenharmony_ci .enable_ms = atmel_enable_ms, 24738c2ecf20Sopenharmony_ci .break_ctl = atmel_break_ctl, 24748c2ecf20Sopenharmony_ci .startup = atmel_startup, 24758c2ecf20Sopenharmony_ci .shutdown = atmel_shutdown, 24768c2ecf20Sopenharmony_ci .flush_buffer = atmel_flush_buffer, 24778c2ecf20Sopenharmony_ci .set_termios = atmel_set_termios, 24788c2ecf20Sopenharmony_ci .set_ldisc = atmel_set_ldisc, 24798c2ecf20Sopenharmony_ci .type = atmel_type, 24808c2ecf20Sopenharmony_ci .release_port = atmel_release_port, 24818c2ecf20Sopenharmony_ci .request_port = atmel_request_port, 24828c2ecf20Sopenharmony_ci .config_port = atmel_config_port, 24838c2ecf20Sopenharmony_ci .verify_port = atmel_verify_port, 24848c2ecf20Sopenharmony_ci .pm = atmel_serial_pm, 24858c2ecf20Sopenharmony_ci#ifdef CONFIG_CONSOLE_POLL 24868c2ecf20Sopenharmony_ci .poll_get_char = atmel_poll_get_char, 24878c2ecf20Sopenharmony_ci .poll_put_char = atmel_poll_put_char, 24888c2ecf20Sopenharmony_ci#endif 24898c2ecf20Sopenharmony_ci}; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci/* 24928c2ecf20Sopenharmony_ci * Configure the port from the platform device resource info. 24938c2ecf20Sopenharmony_ci */ 24948c2ecf20Sopenharmony_cistatic int atmel_init_port(struct atmel_uart_port *atmel_port, 24958c2ecf20Sopenharmony_ci struct platform_device *pdev) 24968c2ecf20Sopenharmony_ci{ 24978c2ecf20Sopenharmony_ci int ret; 24988c2ecf20Sopenharmony_ci struct uart_port *port = &atmel_port->uart; 24998c2ecf20Sopenharmony_ci struct platform_device *mpdev = to_platform_device(pdev->dev.parent); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci atmel_init_property(atmel_port, pdev); 25028c2ecf20Sopenharmony_ci atmel_set_ops(port); 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci port->iotype = UPIO_MEM; 25058c2ecf20Sopenharmony_ci port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; 25068c2ecf20Sopenharmony_ci port->ops = &atmel_pops; 25078c2ecf20Sopenharmony_ci port->fifosize = 1; 25088c2ecf20Sopenharmony_ci port->dev = &pdev->dev; 25098c2ecf20Sopenharmony_ci port->mapbase = mpdev->resource[0].start; 25108c2ecf20Sopenharmony_ci port->irq = mpdev->resource[1].start; 25118c2ecf20Sopenharmony_ci port->rs485_config = atmel_config_rs485; 25128c2ecf20Sopenharmony_ci port->iso7816_config = atmel_config_iso7816; 25138c2ecf20Sopenharmony_ci port->membase = NULL; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci ret = uart_get_rs485_mode(port); 25188c2ecf20Sopenharmony_ci if (ret) 25198c2ecf20Sopenharmony_ci return ret; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci /* for console, the clock could already be configured */ 25228c2ecf20Sopenharmony_ci if (!atmel_port->clk) { 25238c2ecf20Sopenharmony_ci atmel_port->clk = clk_get(&mpdev->dev, "usart"); 25248c2ecf20Sopenharmony_ci if (IS_ERR(atmel_port->clk)) { 25258c2ecf20Sopenharmony_ci ret = PTR_ERR(atmel_port->clk); 25268c2ecf20Sopenharmony_ci atmel_port->clk = NULL; 25278c2ecf20Sopenharmony_ci return ret; 25288c2ecf20Sopenharmony_ci } 25298c2ecf20Sopenharmony_ci ret = clk_prepare_enable(atmel_port->clk); 25308c2ecf20Sopenharmony_ci if (ret) { 25318c2ecf20Sopenharmony_ci clk_put(atmel_port->clk); 25328c2ecf20Sopenharmony_ci atmel_port->clk = NULL; 25338c2ecf20Sopenharmony_ci return ret; 25348c2ecf20Sopenharmony_ci } 25358c2ecf20Sopenharmony_ci port->uartclk = clk_get_rate(atmel_port->clk); 25368c2ecf20Sopenharmony_ci clk_disable_unprepare(atmel_port->clk); 25378c2ecf20Sopenharmony_ci /* only enable clock when USART is in use */ 25388c2ecf20Sopenharmony_ci } 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci /* 25418c2ecf20Sopenharmony_ci * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or 25428c2ecf20Sopenharmony_ci * ENDTX|TXBUFE 25438c2ecf20Sopenharmony_ci */ 25448c2ecf20Sopenharmony_ci if (atmel_uart_is_half_duplex(port)) 25458c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; 25468c2ecf20Sopenharmony_ci else if (atmel_use_pdc_tx(port)) { 25478c2ecf20Sopenharmony_ci port->fifosize = PDC_BUFFER_SIZE; 25488c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE; 25498c2ecf20Sopenharmony_ci } else { 25508c2ecf20Sopenharmony_ci atmel_port->tx_done_mask = ATMEL_US_TXRDY; 25518c2ecf20Sopenharmony_ci } 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci return 0; 25548c2ecf20Sopenharmony_ci} 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_ATMEL_CONSOLE 25578c2ecf20Sopenharmony_cistatic void atmel_console_putchar(struct uart_port *port, int ch) 25588c2ecf20Sopenharmony_ci{ 25598c2ecf20Sopenharmony_ci while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) 25608c2ecf20Sopenharmony_ci cpu_relax(); 25618c2ecf20Sopenharmony_ci atmel_uart_write_char(port, ch); 25628c2ecf20Sopenharmony_ci} 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci/* 25658c2ecf20Sopenharmony_ci * Interrupts are disabled on entering 25668c2ecf20Sopenharmony_ci */ 25678c2ecf20Sopenharmony_cistatic void atmel_console_write(struct console *co, const char *s, u_int count) 25688c2ecf20Sopenharmony_ci{ 25698c2ecf20Sopenharmony_ci struct uart_port *port = &atmel_ports[co->index].uart; 25708c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 25718c2ecf20Sopenharmony_ci unsigned int status, imr; 25728c2ecf20Sopenharmony_ci unsigned int pdc_tx; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci /* 25758c2ecf20Sopenharmony_ci * First, save IMR and then disable interrupts 25768c2ecf20Sopenharmony_ci */ 25778c2ecf20Sopenharmony_ci imr = atmel_uart_readl(port, ATMEL_US_IMR); 25788c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, 25798c2ecf20Sopenharmony_ci ATMEL_US_RXRDY | atmel_port->tx_done_mask); 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci /* Store PDC transmit status and disable it */ 25828c2ecf20Sopenharmony_ci pdc_tx = atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN; 25838c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci /* Make sure that tx path is actually able to send characters */ 25868c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); 25878c2ecf20Sopenharmony_ci atmel_port->tx_stopped = false; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci uart_console_write(port, s, count, atmel_console_putchar); 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci /* 25928c2ecf20Sopenharmony_ci * Finally, wait for transmitter to become empty 25938c2ecf20Sopenharmony_ci * and restore IMR 25948c2ecf20Sopenharmony_ci */ 25958c2ecf20Sopenharmony_ci do { 25968c2ecf20Sopenharmony_ci status = atmel_uart_readl(port, ATMEL_US_CSR); 25978c2ecf20Sopenharmony_ci } while (!(status & ATMEL_US_TXRDY)); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci /* Restore PDC transmit status */ 26008c2ecf20Sopenharmony_ci if (pdc_tx) 26018c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci /* set interrupts back the way they were */ 26048c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, imr); 26058c2ecf20Sopenharmony_ci} 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci/* 26088c2ecf20Sopenharmony_ci * If the port was already initialised (eg, by a boot loader), 26098c2ecf20Sopenharmony_ci * try to determine the current setup. 26108c2ecf20Sopenharmony_ci */ 26118c2ecf20Sopenharmony_cistatic void __init atmel_console_get_options(struct uart_port *port, int *baud, 26128c2ecf20Sopenharmony_ci int *parity, int *bits) 26138c2ecf20Sopenharmony_ci{ 26148c2ecf20Sopenharmony_ci unsigned int mr, quot; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci /* 26178c2ecf20Sopenharmony_ci * If the baud rate generator isn't running, the port wasn't 26188c2ecf20Sopenharmony_ci * initialized by the boot loader. 26198c2ecf20Sopenharmony_ci */ 26208c2ecf20Sopenharmony_ci quot = atmel_uart_readl(port, ATMEL_US_BRGR) & ATMEL_US_CD; 26218c2ecf20Sopenharmony_ci if (!quot) 26228c2ecf20Sopenharmony_ci return; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_CHRL; 26258c2ecf20Sopenharmony_ci if (mr == ATMEL_US_CHRL_8) 26268c2ecf20Sopenharmony_ci *bits = 8; 26278c2ecf20Sopenharmony_ci else 26288c2ecf20Sopenharmony_ci *bits = 7; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_PAR; 26318c2ecf20Sopenharmony_ci if (mr == ATMEL_US_PAR_EVEN) 26328c2ecf20Sopenharmony_ci *parity = 'e'; 26338c2ecf20Sopenharmony_ci else if (mr == ATMEL_US_PAR_ODD) 26348c2ecf20Sopenharmony_ci *parity = 'o'; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci *baud = port->uartclk / (16 * quot); 26378c2ecf20Sopenharmony_ci} 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_cistatic int __init atmel_console_setup(struct console *co, char *options) 26408c2ecf20Sopenharmony_ci{ 26418c2ecf20Sopenharmony_ci int ret; 26428c2ecf20Sopenharmony_ci struct uart_port *port = &atmel_ports[co->index].uart; 26438c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 26448c2ecf20Sopenharmony_ci int baud = 115200; 26458c2ecf20Sopenharmony_ci int bits = 8; 26468c2ecf20Sopenharmony_ci int parity = 'n'; 26478c2ecf20Sopenharmony_ci int flow = 'n'; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci if (port->membase == NULL) { 26508c2ecf20Sopenharmony_ci /* Port not initialized yet - delay setup */ 26518c2ecf20Sopenharmony_ci return -ENODEV; 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci ret = clk_prepare_enable(atmel_ports[co->index].clk); 26558c2ecf20Sopenharmony_ci if (ret) 26568c2ecf20Sopenharmony_ci return ret; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IDR, -1); 26598c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); 26608c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); 26618c2ecf20Sopenharmony_ci atmel_port->tx_stopped = false; 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci if (options) 26648c2ecf20Sopenharmony_ci uart_parse_options(options, &baud, &parity, &bits, &flow); 26658c2ecf20Sopenharmony_ci else 26668c2ecf20Sopenharmony_ci atmel_console_get_options(port, &baud, &parity, &bits); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci return uart_set_options(port, co, baud, parity, bits, flow); 26698c2ecf20Sopenharmony_ci} 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_cistatic struct uart_driver atmel_uart; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_cistatic struct console atmel_console = { 26748c2ecf20Sopenharmony_ci .name = ATMEL_DEVICENAME, 26758c2ecf20Sopenharmony_ci .write = atmel_console_write, 26768c2ecf20Sopenharmony_ci .device = uart_console_device, 26778c2ecf20Sopenharmony_ci .setup = atmel_console_setup, 26788c2ecf20Sopenharmony_ci .flags = CON_PRINTBUFFER, 26798c2ecf20Sopenharmony_ci .index = -1, 26808c2ecf20Sopenharmony_ci .data = &atmel_uart, 26818c2ecf20Sopenharmony_ci}; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci#define ATMEL_CONSOLE_DEVICE (&atmel_console) 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci#else 26868c2ecf20Sopenharmony_ci#define ATMEL_CONSOLE_DEVICE NULL 26878c2ecf20Sopenharmony_ci#endif 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_cistatic struct uart_driver atmel_uart = { 26908c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 26918c2ecf20Sopenharmony_ci .driver_name = "atmel_serial", 26928c2ecf20Sopenharmony_ci .dev_name = ATMEL_DEVICENAME, 26938c2ecf20Sopenharmony_ci .major = SERIAL_ATMEL_MAJOR, 26948c2ecf20Sopenharmony_ci .minor = MINOR_START, 26958c2ecf20Sopenharmony_ci .nr = ATMEL_MAX_UART, 26968c2ecf20Sopenharmony_ci .cons = ATMEL_CONSOLE_DEVICE, 26978c2ecf20Sopenharmony_ci}; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 27008c2ecf20Sopenharmony_cistatic bool atmel_serial_clk_will_stop(void) 27018c2ecf20Sopenharmony_ci{ 27028c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_AT91 27038c2ecf20Sopenharmony_ci return at91_suspend_entering_slow_clock(); 27048c2ecf20Sopenharmony_ci#else 27058c2ecf20Sopenharmony_ci return false; 27068c2ecf20Sopenharmony_ci#endif 27078c2ecf20Sopenharmony_ci} 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_cistatic int atmel_serial_suspend(struct platform_device *pdev, 27108c2ecf20Sopenharmony_ci pm_message_t state) 27118c2ecf20Sopenharmony_ci{ 27128c2ecf20Sopenharmony_ci struct uart_port *port = platform_get_drvdata(pdev); 27138c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci if (uart_console(port) && console_suspend_enabled) { 27168c2ecf20Sopenharmony_ci /* Drain the TX shifter */ 27178c2ecf20Sopenharmony_ci while (!(atmel_uart_readl(port, ATMEL_US_CSR) & 27188c2ecf20Sopenharmony_ci ATMEL_US_TXEMPTY)) 27198c2ecf20Sopenharmony_ci cpu_relax(); 27208c2ecf20Sopenharmony_ci } 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci if (uart_console(port) && !console_suspend_enabled) { 27238c2ecf20Sopenharmony_ci /* Cache register values as we won't get a full shutdown/startup 27248c2ecf20Sopenharmony_ci * cycle 27258c2ecf20Sopenharmony_ci */ 27268c2ecf20Sopenharmony_ci atmel_port->cache.mr = atmel_uart_readl(port, ATMEL_US_MR); 27278c2ecf20Sopenharmony_ci atmel_port->cache.imr = atmel_uart_readl(port, ATMEL_US_IMR); 27288c2ecf20Sopenharmony_ci atmel_port->cache.brgr = atmel_uart_readl(port, ATMEL_US_BRGR); 27298c2ecf20Sopenharmony_ci atmel_port->cache.rtor = atmel_uart_readl(port, 27308c2ecf20Sopenharmony_ci atmel_port->rtor); 27318c2ecf20Sopenharmony_ci atmel_port->cache.ttgr = atmel_uart_readl(port, ATMEL_US_TTGR); 27328c2ecf20Sopenharmony_ci atmel_port->cache.fmr = atmel_uart_readl(port, ATMEL_US_FMR); 27338c2ecf20Sopenharmony_ci atmel_port->cache.fimr = atmel_uart_readl(port, ATMEL_US_FIMR); 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci /* we can not wake up if we're running on slow clock */ 27378c2ecf20Sopenharmony_ci atmel_port->may_wakeup = device_may_wakeup(&pdev->dev); 27388c2ecf20Sopenharmony_ci if (atmel_serial_clk_will_stop()) { 27398c2ecf20Sopenharmony_ci unsigned long flags; 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci spin_lock_irqsave(&atmel_port->lock_suspended, flags); 27428c2ecf20Sopenharmony_ci atmel_port->suspended = true; 27438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); 27448c2ecf20Sopenharmony_ci device_set_wakeup_enable(&pdev->dev, 0); 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci uart_suspend_port(&atmel_uart, port); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci return 0; 27508c2ecf20Sopenharmony_ci} 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_cistatic int atmel_serial_resume(struct platform_device *pdev) 27538c2ecf20Sopenharmony_ci{ 27548c2ecf20Sopenharmony_ci struct uart_port *port = platform_get_drvdata(pdev); 27558c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 27568c2ecf20Sopenharmony_ci unsigned long flags; 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci if (uart_console(port) && !console_suspend_enabled) { 27598c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_MR, atmel_port->cache.mr); 27608c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_IER, atmel_port->cache.imr); 27618c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->cache.brgr); 27628c2ecf20Sopenharmony_ci atmel_uart_writel(port, atmel_port->rtor, 27638c2ecf20Sopenharmony_ci atmel_port->cache.rtor); 27648c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_TTGR, atmel_port->cache.ttgr); 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci if (atmel_port->fifo_size) { 27678c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_FIFOEN | 27688c2ecf20Sopenharmony_ci ATMEL_US_RXFCLR | ATMEL_US_TXFLCLR); 27698c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_FMR, 27708c2ecf20Sopenharmony_ci atmel_port->cache.fmr); 27718c2ecf20Sopenharmony_ci atmel_uart_writel(port, ATMEL_US_FIER, 27728c2ecf20Sopenharmony_ci atmel_port->cache.fimr); 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci atmel_start_rx(port); 27758c2ecf20Sopenharmony_ci } 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci spin_lock_irqsave(&atmel_port->lock_suspended, flags); 27788c2ecf20Sopenharmony_ci if (atmel_port->pending) { 27798c2ecf20Sopenharmony_ci atmel_handle_receive(port, atmel_port->pending); 27808c2ecf20Sopenharmony_ci atmel_handle_status(port, atmel_port->pending, 27818c2ecf20Sopenharmony_ci atmel_port->pending_status); 27828c2ecf20Sopenharmony_ci atmel_handle_transmit(port, atmel_port->pending); 27838c2ecf20Sopenharmony_ci atmel_port->pending = 0; 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci atmel_port->suspended = false; 27868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&atmel_port->lock_suspended, flags); 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci uart_resume_port(&atmel_uart, port); 27898c2ecf20Sopenharmony_ci device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup); 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci return 0; 27928c2ecf20Sopenharmony_ci} 27938c2ecf20Sopenharmony_ci#else 27948c2ecf20Sopenharmony_ci#define atmel_serial_suspend NULL 27958c2ecf20Sopenharmony_ci#define atmel_serial_resume NULL 27968c2ecf20Sopenharmony_ci#endif 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_cistatic void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port, 27998c2ecf20Sopenharmony_ci struct platform_device *pdev) 28008c2ecf20Sopenharmony_ci{ 28018c2ecf20Sopenharmony_ci atmel_port->fifo_size = 0; 28028c2ecf20Sopenharmony_ci atmel_port->rts_low = 0; 28038c2ecf20Sopenharmony_ci atmel_port->rts_high = 0; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, 28068c2ecf20Sopenharmony_ci "atmel,fifo-size", 28078c2ecf20Sopenharmony_ci &atmel_port->fifo_size)) 28088c2ecf20Sopenharmony_ci return; 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci if (!atmel_port->fifo_size) 28118c2ecf20Sopenharmony_ci return; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci if (atmel_port->fifo_size < ATMEL_MIN_FIFO_SIZE) { 28148c2ecf20Sopenharmony_ci atmel_port->fifo_size = 0; 28158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Invalid FIFO size\n"); 28168c2ecf20Sopenharmony_ci return; 28178c2ecf20Sopenharmony_ci } 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci /* 28208c2ecf20Sopenharmony_ci * 0 <= rts_low <= rts_high <= fifo_size 28218c2ecf20Sopenharmony_ci * Once their CTS line asserted by the remote peer, some x86 UARTs tend 28228c2ecf20Sopenharmony_ci * to flush their internal TX FIFO, commonly up to 16 data, before 28238c2ecf20Sopenharmony_ci * actually stopping to send new data. So we try to set the RTS High 28248c2ecf20Sopenharmony_ci * Threshold to a reasonably high value respecting this 16 data 28258c2ecf20Sopenharmony_ci * empirical rule when possible. 28268c2ecf20Sopenharmony_ci */ 28278c2ecf20Sopenharmony_ci atmel_port->rts_high = max_t(int, atmel_port->fifo_size >> 1, 28288c2ecf20Sopenharmony_ci atmel_port->fifo_size - ATMEL_RTS_HIGH_OFFSET); 28298c2ecf20Sopenharmony_ci atmel_port->rts_low = max_t(int, atmel_port->fifo_size >> 2, 28308c2ecf20Sopenharmony_ci atmel_port->fifo_size - ATMEL_RTS_LOW_OFFSET); 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Using FIFO (%u data)\n", 28338c2ecf20Sopenharmony_ci atmel_port->fifo_size); 28348c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n", 28358c2ecf20Sopenharmony_ci atmel_port->rts_high); 28368c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n", 28378c2ecf20Sopenharmony_ci atmel_port->rts_low); 28388c2ecf20Sopenharmony_ci} 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_cistatic int atmel_serial_probe(struct platform_device *pdev) 28418c2ecf20Sopenharmony_ci{ 28428c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port; 28438c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.parent->of_node; 28448c2ecf20Sopenharmony_ci void *data; 28458c2ecf20Sopenharmony_ci int ret; 28468c2ecf20Sopenharmony_ci bool rs485_enabled; 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci /* 28518c2ecf20Sopenharmony_ci * In device tree there is no node with "atmel,at91rm9200-usart-serial" 28528c2ecf20Sopenharmony_ci * as compatible string. This driver is probed by at91-usart mfd driver 28538c2ecf20Sopenharmony_ci * which is just a wrapper over the atmel_serial driver and 28548c2ecf20Sopenharmony_ci * spi-at91-usart driver. All attributes needed by this driver are 28558c2ecf20Sopenharmony_ci * found in of_node of parent. 28568c2ecf20Sopenharmony_ci */ 28578c2ecf20Sopenharmony_ci pdev->dev.of_node = np; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci ret = of_alias_get_id(np, "serial"); 28608c2ecf20Sopenharmony_ci if (ret < 0) 28618c2ecf20Sopenharmony_ci /* port id not found in platform data nor device-tree aliases: 28628c2ecf20Sopenharmony_ci * auto-enumerate it */ 28638c2ecf20Sopenharmony_ci ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci if (ret >= ATMEL_MAX_UART) { 28668c2ecf20Sopenharmony_ci ret = -ENODEV; 28678c2ecf20Sopenharmony_ci goto err; 28688c2ecf20Sopenharmony_ci } 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci if (test_and_set_bit(ret, atmel_ports_in_use)) { 28718c2ecf20Sopenharmony_ci /* port already in use */ 28728c2ecf20Sopenharmony_ci ret = -EBUSY; 28738c2ecf20Sopenharmony_ci goto err; 28748c2ecf20Sopenharmony_ci } 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci atmel_port = &atmel_ports[ret]; 28778c2ecf20Sopenharmony_ci atmel_port->backup_imr = 0; 28788c2ecf20Sopenharmony_ci atmel_port->uart.line = ret; 28798c2ecf20Sopenharmony_ci atmel_port->uart.has_sysrq = IS_ENABLED(CONFIG_SERIAL_ATMEL_CONSOLE); 28808c2ecf20Sopenharmony_ci atmel_serial_probe_fifos(atmel_port, pdev); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci atomic_set(&atmel_port->tasklet_shutdown, 0); 28838c2ecf20Sopenharmony_ci spin_lock_init(&atmel_port->lock_suspended); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci ret = atmel_init_port(atmel_port, pdev); 28868c2ecf20Sopenharmony_ci if (ret) 28878c2ecf20Sopenharmony_ci goto err_clear_bit; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0); 28908c2ecf20Sopenharmony_ci if (IS_ERR(atmel_port->gpios)) { 28918c2ecf20Sopenharmony_ci ret = PTR_ERR(atmel_port->gpios); 28928c2ecf20Sopenharmony_ci goto err_clear_bit; 28938c2ecf20Sopenharmony_ci } 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci if (!atmel_use_pdc_rx(&atmel_port->uart)) { 28968c2ecf20Sopenharmony_ci ret = -ENOMEM; 28978c2ecf20Sopenharmony_ci data = kmalloc_array(ATMEL_SERIAL_RINGSIZE, 28988c2ecf20Sopenharmony_ci sizeof(struct atmel_uart_char), 28998c2ecf20Sopenharmony_ci GFP_KERNEL); 29008c2ecf20Sopenharmony_ci if (!data) 29018c2ecf20Sopenharmony_ci goto err_alloc_ring; 29028c2ecf20Sopenharmony_ci atmel_port->rx_ring.buf = data; 29038c2ecf20Sopenharmony_ci } 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci rs485_enabled = atmel_port->uart.rs485.flags & SER_RS485_ENABLED; 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci ret = uart_add_one_port(&atmel_uart, &atmel_port->uart); 29088c2ecf20Sopenharmony_ci if (ret) 29098c2ecf20Sopenharmony_ci goto err_add_port; 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_ATMEL_CONSOLE 29128c2ecf20Sopenharmony_ci if (uart_console(&atmel_port->uart) 29138c2ecf20Sopenharmony_ci && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { 29148c2ecf20Sopenharmony_ci /* 29158c2ecf20Sopenharmony_ci * The serial core enabled the clock for us, so undo 29168c2ecf20Sopenharmony_ci * the clk_prepare_enable() in atmel_console_setup() 29178c2ecf20Sopenharmony_ci */ 29188c2ecf20Sopenharmony_ci clk_disable_unprepare(atmel_port->clk); 29198c2ecf20Sopenharmony_ci } 29208c2ecf20Sopenharmony_ci#endif 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, 1); 29238c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, atmel_port); 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci /* 29268c2ecf20Sopenharmony_ci * The peripheral clock has been disabled by atmel_init_port(): 29278c2ecf20Sopenharmony_ci * enable it before accessing I/O registers 29288c2ecf20Sopenharmony_ci */ 29298c2ecf20Sopenharmony_ci clk_prepare_enable(atmel_port->clk); 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci if (rs485_enabled) { 29328c2ecf20Sopenharmony_ci atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR, 29338c2ecf20Sopenharmony_ci ATMEL_US_USMODE_NORMAL); 29348c2ecf20Sopenharmony_ci atmel_uart_writel(&atmel_port->uart, ATMEL_US_CR, 29358c2ecf20Sopenharmony_ci ATMEL_US_RTSEN); 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci /* 29398c2ecf20Sopenharmony_ci * Get port name of usart or uart 29408c2ecf20Sopenharmony_ci */ 29418c2ecf20Sopenharmony_ci atmel_get_ip_name(&atmel_port->uart); 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci /* 29448c2ecf20Sopenharmony_ci * The peripheral clock can now safely be disabled till the port 29458c2ecf20Sopenharmony_ci * is used 29468c2ecf20Sopenharmony_ci */ 29478c2ecf20Sopenharmony_ci clk_disable_unprepare(atmel_port->clk); 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci return 0; 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_cierr_add_port: 29528c2ecf20Sopenharmony_ci kfree(atmel_port->rx_ring.buf); 29538c2ecf20Sopenharmony_ci atmel_port->rx_ring.buf = NULL; 29548c2ecf20Sopenharmony_cierr_alloc_ring: 29558c2ecf20Sopenharmony_ci if (!uart_console(&atmel_port->uart)) { 29568c2ecf20Sopenharmony_ci clk_put(atmel_port->clk); 29578c2ecf20Sopenharmony_ci atmel_port->clk = NULL; 29588c2ecf20Sopenharmony_ci } 29598c2ecf20Sopenharmony_cierr_clear_bit: 29608c2ecf20Sopenharmony_ci clear_bit(atmel_port->uart.line, atmel_ports_in_use); 29618c2ecf20Sopenharmony_cierr: 29628c2ecf20Sopenharmony_ci return ret; 29638c2ecf20Sopenharmony_ci} 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci/* 29668c2ecf20Sopenharmony_ci * Even if the driver is not modular, it makes sense to be able to 29678c2ecf20Sopenharmony_ci * unbind a device: there can be many bound devices, and there are 29688c2ecf20Sopenharmony_ci * situations where dynamic binding and unbinding can be useful. 29698c2ecf20Sopenharmony_ci * 29708c2ecf20Sopenharmony_ci * For example, a connected device can require a specific firmware update 29718c2ecf20Sopenharmony_ci * protocol that needs bitbanging on IO lines, but use the regular serial 29728c2ecf20Sopenharmony_ci * port in the normal case. 29738c2ecf20Sopenharmony_ci */ 29748c2ecf20Sopenharmony_cistatic int atmel_serial_remove(struct platform_device *pdev) 29758c2ecf20Sopenharmony_ci{ 29768c2ecf20Sopenharmony_ci struct uart_port *port = platform_get_drvdata(pdev); 29778c2ecf20Sopenharmony_ci struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 29788c2ecf20Sopenharmony_ci int ret = 0; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci tasklet_kill(&atmel_port->tasklet_rx); 29818c2ecf20Sopenharmony_ci tasklet_kill(&atmel_port->tasklet_tx); 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, 0); 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci ret = uart_remove_one_port(&atmel_uart, port); 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci kfree(atmel_port->rx_ring.buf); 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci /* "port" is allocated statically, so we shouldn't free it */ 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci clear_bit(port->line, atmel_ports_in_use); 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci clk_put(atmel_port->clk); 29948c2ecf20Sopenharmony_ci atmel_port->clk = NULL; 29958c2ecf20Sopenharmony_ci pdev->dev.of_node = NULL; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci return ret; 29988c2ecf20Sopenharmony_ci} 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_cistatic struct platform_driver atmel_serial_driver = { 30018c2ecf20Sopenharmony_ci .probe = atmel_serial_probe, 30028c2ecf20Sopenharmony_ci .remove = atmel_serial_remove, 30038c2ecf20Sopenharmony_ci .suspend = atmel_serial_suspend, 30048c2ecf20Sopenharmony_ci .resume = atmel_serial_resume, 30058c2ecf20Sopenharmony_ci .driver = { 30068c2ecf20Sopenharmony_ci .name = "atmel_usart_serial", 30078c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(atmel_serial_dt_ids), 30088c2ecf20Sopenharmony_ci }, 30098c2ecf20Sopenharmony_ci}; 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_cistatic int __init atmel_serial_init(void) 30128c2ecf20Sopenharmony_ci{ 30138c2ecf20Sopenharmony_ci int ret; 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci ret = uart_register_driver(&atmel_uart); 30168c2ecf20Sopenharmony_ci if (ret) 30178c2ecf20Sopenharmony_ci return ret; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci ret = platform_driver_register(&atmel_serial_driver); 30208c2ecf20Sopenharmony_ci if (ret) 30218c2ecf20Sopenharmony_ci uart_unregister_driver(&atmel_uart); 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci return ret; 30248c2ecf20Sopenharmony_ci} 30258c2ecf20Sopenharmony_cidevice_initcall(atmel_serial_init); 3026