145c054d0SPaul Walmsley // SPDX-License-Identifier: GPL-2.0+ 245c054d0SPaul Walmsley /* 345c054d0SPaul Walmsley * SiFive UART driver 445c054d0SPaul Walmsley * Copyright (C) 2018 Paul Walmsley <paul@pwsan.com> 545c054d0SPaul Walmsley * Copyright (C) 2018-2019 SiFive 645c054d0SPaul Walmsley * 745c054d0SPaul Walmsley * Based partially on: 845c054d0SPaul Walmsley * - drivers/tty/serial/pxa.c 945c054d0SPaul Walmsley * - drivers/tty/serial/amba-pl011.c 1045c054d0SPaul Walmsley * - drivers/tty/serial/uartlite.c 1145c054d0SPaul Walmsley * - drivers/tty/serial/omap-serial.c 1245c054d0SPaul Walmsley * - drivers/pwm/pwm-sifive.c 1345c054d0SPaul Walmsley * 1445c054d0SPaul Walmsley * See the following sources for further documentation: 1545c054d0SPaul Walmsley * - Chapter 19 "Universal Asynchronous Receiver/Transmitter (UART)" of 1645c054d0SPaul Walmsley * SiFive FE310-G000 v2p3 1745c054d0SPaul Walmsley * - The tree/master/src/main/scala/devices/uart directory of 1845c054d0SPaul Walmsley * https://github.com/sifive/sifive-blocks/ 1945c054d0SPaul Walmsley * 2045c054d0SPaul Walmsley * The SiFive UART design is not 8250-compatible. The following common 2145c054d0SPaul Walmsley * features are not supported: 2245c054d0SPaul Walmsley * - Word lengths other than 8 bits 2345c054d0SPaul Walmsley * - Break handling 2445c054d0SPaul Walmsley * - Parity 2545c054d0SPaul Walmsley * - Flow control 2645c054d0SPaul Walmsley * - Modem signals (DSR, RI, etc.) 2745c054d0SPaul Walmsley * On the other hand, the design is free from the baggage of the 8250 2845c054d0SPaul Walmsley * programming model. 2945c054d0SPaul Walmsley */ 3045c054d0SPaul Walmsley 3145c054d0SPaul Walmsley #include <linux/clk.h> 3245c054d0SPaul Walmsley #include <linux/console.h> 3345c054d0SPaul Walmsley #include <linux/delay.h> 3445c054d0SPaul Walmsley #include <linux/init.h> 3545c054d0SPaul Walmsley #include <linux/io.h> 3645c054d0SPaul Walmsley #include <linux/irq.h> 3745c054d0SPaul Walmsley #include <linux/module.h> 3845c054d0SPaul Walmsley #include <linux/of.h> 3945c054d0SPaul Walmsley #include <linux/of_irq.h> 4045c054d0SPaul Walmsley #include <linux/platform_device.h> 4145c054d0SPaul Walmsley #include <linux/serial_core.h> 4245c054d0SPaul Walmsley #include <linux/serial_reg.h> 4345c054d0SPaul Walmsley #include <linux/slab.h> 4445c054d0SPaul Walmsley #include <linux/tty.h> 4545c054d0SPaul Walmsley #include <linux/tty_flip.h> 4645c054d0SPaul Walmsley 4745c054d0SPaul Walmsley /* 4845c054d0SPaul Walmsley * Register offsets 4945c054d0SPaul Walmsley */ 5045c054d0SPaul Walmsley 5145c054d0SPaul Walmsley /* TXDATA */ 5245c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXDATA_OFFS 0x0 5345c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXDATA_FULL_SHIFT 31 5445c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXDATA_FULL_MASK (1 << SIFIVE_SERIAL_TXDATA_FULL_SHIFT) 5545c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXDATA_DATA_SHIFT 0 5645c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXDATA_DATA_MASK (0xff << SIFIVE_SERIAL_TXDATA_DATA_SHIFT) 5745c054d0SPaul Walmsley 5845c054d0SPaul Walmsley /* RXDATA */ 5945c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXDATA_OFFS 0x4 6045c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXDATA_EMPTY_SHIFT 31 6145c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXDATA_EMPTY_MASK (1 << SIFIVE_SERIAL_RXDATA_EMPTY_SHIFT) 6245c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXDATA_DATA_SHIFT 0 6345c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXDATA_DATA_MASK (0xff << SIFIVE_SERIAL_RXDATA_DATA_SHIFT) 6445c054d0SPaul Walmsley 6545c054d0SPaul Walmsley /* TXCTRL */ 6645c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXCTRL_OFFS 0x8 6745c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT 16 6845c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXCTRL_TXCNT_MASK (0x7 << SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT) 6945c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXCTRL_NSTOP_SHIFT 1 7045c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXCTRL_NSTOP_MASK (1 << SIFIVE_SERIAL_TXCTRL_NSTOP_SHIFT) 7145c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXCTRL_TXEN_SHIFT 0 7245c054d0SPaul Walmsley #define SIFIVE_SERIAL_TXCTRL_TXEN_MASK (1 << SIFIVE_SERIAL_TXCTRL_TXEN_SHIFT) 7345c054d0SPaul Walmsley 7445c054d0SPaul Walmsley /* RXCTRL */ 7545c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXCTRL_OFFS 0xC 7645c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXCTRL_RXCNT_SHIFT 16 7745c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXCTRL_RXCNT_MASK (0x7 << SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT) 7845c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXCTRL_RXEN_SHIFT 0 7945c054d0SPaul Walmsley #define SIFIVE_SERIAL_RXCTRL_RXEN_MASK (1 << SIFIVE_SERIAL_RXCTRL_RXEN_SHIFT) 8045c054d0SPaul Walmsley 8145c054d0SPaul Walmsley /* IE */ 8245c054d0SPaul Walmsley #define SIFIVE_SERIAL_IE_OFFS 0x10 8345c054d0SPaul Walmsley #define SIFIVE_SERIAL_IE_RXWM_SHIFT 1 8445c054d0SPaul Walmsley #define SIFIVE_SERIAL_IE_RXWM_MASK (1 << SIFIVE_SERIAL_IE_RXWM_SHIFT) 8545c054d0SPaul Walmsley #define SIFIVE_SERIAL_IE_TXWM_SHIFT 0 8645c054d0SPaul Walmsley #define SIFIVE_SERIAL_IE_TXWM_MASK (1 << SIFIVE_SERIAL_IE_TXWM_SHIFT) 8745c054d0SPaul Walmsley 8845c054d0SPaul Walmsley /* IP */ 8945c054d0SPaul Walmsley #define SIFIVE_SERIAL_IP_OFFS 0x14 9045c054d0SPaul Walmsley #define SIFIVE_SERIAL_IP_RXWM_SHIFT 1 9145c054d0SPaul Walmsley #define SIFIVE_SERIAL_IP_RXWM_MASK (1 << SIFIVE_SERIAL_IP_RXWM_SHIFT) 9245c054d0SPaul Walmsley #define SIFIVE_SERIAL_IP_TXWM_SHIFT 0 9345c054d0SPaul Walmsley #define SIFIVE_SERIAL_IP_TXWM_MASK (1 << SIFIVE_SERIAL_IP_TXWM_SHIFT) 9445c054d0SPaul Walmsley 9545c054d0SPaul Walmsley /* DIV */ 9645c054d0SPaul Walmsley #define SIFIVE_SERIAL_DIV_OFFS 0x18 9745c054d0SPaul Walmsley #define SIFIVE_SERIAL_DIV_DIV_SHIFT 0 9845c054d0SPaul Walmsley #define SIFIVE_SERIAL_DIV_DIV_MASK (0xffff << SIFIVE_SERIAL_IP_DIV_SHIFT) 9945c054d0SPaul Walmsley 10045c054d0SPaul Walmsley /* 10145c054d0SPaul Walmsley * Config macros 10245c054d0SPaul Walmsley */ 10345c054d0SPaul Walmsley 10445c054d0SPaul Walmsley /* 10545c054d0SPaul Walmsley * SIFIVE_SERIAL_MAX_PORTS: maximum number of UARTs on a device that can 10645c054d0SPaul Walmsley * host a serial console 10745c054d0SPaul Walmsley */ 10845c054d0SPaul Walmsley #define SIFIVE_SERIAL_MAX_PORTS 8 10945c054d0SPaul Walmsley 11045c054d0SPaul Walmsley /* 11145c054d0SPaul Walmsley * SIFIVE_DEFAULT_BAUD_RATE: default baud rate that the driver should 11245c054d0SPaul Walmsley * configure itself to use 11345c054d0SPaul Walmsley */ 11445c054d0SPaul Walmsley #define SIFIVE_DEFAULT_BAUD_RATE 115200 11545c054d0SPaul Walmsley 11645c054d0SPaul Walmsley /* SIFIVE_SERIAL_NAME: our driver's name that we pass to the operating system */ 11745c054d0SPaul Walmsley #define SIFIVE_SERIAL_NAME "sifive-serial" 11845c054d0SPaul Walmsley 11945c054d0SPaul Walmsley /* SIFIVE_TTY_PREFIX: tty name prefix for SiFive serial ports */ 12045c054d0SPaul Walmsley #define SIFIVE_TTY_PREFIX "ttySIF" 12145c054d0SPaul Walmsley 12245c054d0SPaul Walmsley /* SIFIVE_TX_FIFO_DEPTH: depth of the TX FIFO (in bytes) */ 12345c054d0SPaul Walmsley #define SIFIVE_TX_FIFO_DEPTH 8 12445c054d0SPaul Walmsley 12545c054d0SPaul Walmsley /* SIFIVE_RX_FIFO_DEPTH: depth of the TX FIFO (in bytes) */ 12645c054d0SPaul Walmsley #define SIFIVE_RX_FIFO_DEPTH 8 12745c054d0SPaul Walmsley 12845c054d0SPaul Walmsley #if (SIFIVE_TX_FIFO_DEPTH != SIFIVE_RX_FIFO_DEPTH) 12945c054d0SPaul Walmsley #error Driver does not support configurations with different TX, RX FIFO sizes 13045c054d0SPaul Walmsley #endif 13145c054d0SPaul Walmsley 13245c054d0SPaul Walmsley /* 13345c054d0SPaul Walmsley * 13445c054d0SPaul Walmsley */ 13545c054d0SPaul Walmsley 13645c054d0SPaul Walmsley /** 137180bb243SLee Jones * struct sifive_serial_port - driver-specific data extension to struct uart_port 13845c054d0SPaul Walmsley * @port: struct uart_port embedded in this struct 13945c054d0SPaul Walmsley * @dev: struct device * 14045c054d0SPaul Walmsley * @ier: shadowed copy of the interrupt enable register 14145c054d0SPaul Walmsley * @baud_rate: UART serial line rate (e.g., 115200 baud) 142180bb243SLee Jones * @clk: reference to this device's clock 14345c054d0SPaul Walmsley * @clk_notifier: clock rate change notifier for upstream clock changes 14445c054d0SPaul Walmsley * 14545c054d0SPaul Walmsley * Configuration data specific to this SiFive UART. 14645c054d0SPaul Walmsley */ 14745c054d0SPaul Walmsley struct sifive_serial_port { 14845c054d0SPaul Walmsley struct uart_port port; 14945c054d0SPaul Walmsley struct device *dev; 15045c054d0SPaul Walmsley unsigned char ier; 15145c054d0SPaul Walmsley unsigned long baud_rate; 15245c054d0SPaul Walmsley struct clk *clk; 15345c054d0SPaul Walmsley struct notifier_block clk_notifier; 15445c054d0SPaul Walmsley }; 15545c054d0SPaul Walmsley 15645c054d0SPaul Walmsley /* 15745c054d0SPaul Walmsley * Structure container-of macros 15845c054d0SPaul Walmsley */ 15945c054d0SPaul Walmsley 16045c054d0SPaul Walmsley #define port_to_sifive_serial_port(p) (container_of((p), \ 16145c054d0SPaul Walmsley struct sifive_serial_port, \ 16245c054d0SPaul Walmsley port)) 16345c054d0SPaul Walmsley 16445c054d0SPaul Walmsley #define notifier_to_sifive_serial_port(nb) (container_of((nb), \ 16545c054d0SPaul Walmsley struct sifive_serial_port, \ 16645c054d0SPaul Walmsley clk_notifier)) 16745c054d0SPaul Walmsley 16845c054d0SPaul Walmsley /* 16945c054d0SPaul Walmsley * Forward declarations 17045c054d0SPaul Walmsley */ 17145c054d0SPaul Walmsley static void sifive_serial_stop_tx(struct uart_port *port); 17245c054d0SPaul Walmsley 17345c054d0SPaul Walmsley /* 17445c054d0SPaul Walmsley * Internal functions 17545c054d0SPaul Walmsley */ 17645c054d0SPaul Walmsley 17745c054d0SPaul Walmsley /** 17845c054d0SPaul Walmsley * __ssp_early_writel() - write to a SiFive serial port register (early) 17945c054d0SPaul Walmsley * @port: pointer to a struct uart_port record 18045c054d0SPaul Walmsley * @offs: register address offset from the IP block base address 18145c054d0SPaul Walmsley * @v: value to write to the register 18245c054d0SPaul Walmsley * 18345c054d0SPaul Walmsley * Given a pointer @port to a struct uart_port record, write the value 18445c054d0SPaul Walmsley * @v to the IP block register address offset @offs. This function is 18545c054d0SPaul Walmsley * intended for early console use. 18645c054d0SPaul Walmsley * 18745c054d0SPaul Walmsley * Context: Intended to be used only by the earlyconsole code. 18845c054d0SPaul Walmsley */ 18945c054d0SPaul Walmsley static void __ssp_early_writel(u32 v, u16 offs, struct uart_port *port) 19045c054d0SPaul Walmsley { 19145c054d0SPaul Walmsley writel_relaxed(v, port->membase + offs); 19245c054d0SPaul Walmsley } 19345c054d0SPaul Walmsley 19445c054d0SPaul Walmsley /** 19545c054d0SPaul Walmsley * __ssp_early_readl() - read from a SiFive serial port register (early) 19645c054d0SPaul Walmsley * @port: pointer to a struct uart_port record 19745c054d0SPaul Walmsley * @offs: register address offset from the IP block base address 19845c054d0SPaul Walmsley * 19945c054d0SPaul Walmsley * Given a pointer @port to a struct uart_port record, read the 20045c054d0SPaul Walmsley * contents of the IP block register located at offset @offs from the 20145c054d0SPaul Walmsley * IP block base and return it. This function is intended for early 20245c054d0SPaul Walmsley * console use. 20345c054d0SPaul Walmsley * 20445c054d0SPaul Walmsley * Context: Intended to be called only by the earlyconsole code or by 20545c054d0SPaul Walmsley * __ssp_readl() or __ssp_writel() (in this driver) 20645c054d0SPaul Walmsley * 20745c054d0SPaul Walmsley * Returns: the register value read from the UART. 20845c054d0SPaul Walmsley */ 20945c054d0SPaul Walmsley static u32 __ssp_early_readl(struct uart_port *port, u16 offs) 21045c054d0SPaul Walmsley { 21145c054d0SPaul Walmsley return readl_relaxed(port->membase + offs); 21245c054d0SPaul Walmsley } 21345c054d0SPaul Walmsley 21445c054d0SPaul Walmsley /** 21545c054d0SPaul Walmsley * __ssp_writel() - write to a SiFive serial port register 21645c054d0SPaul Walmsley * @v: value to write to the register 21745c054d0SPaul Walmsley * @offs: register address offset from the IP block base address 21845c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port record 21945c054d0SPaul Walmsley * 22045c054d0SPaul Walmsley * Write the value @v to the IP block register located at offset @offs from the 22145c054d0SPaul Walmsley * IP block base, given a pointer @ssp to a struct sifive_serial_port record. 22245c054d0SPaul Walmsley * 22345c054d0SPaul Walmsley * Context: Any context. 22445c054d0SPaul Walmsley */ 22545c054d0SPaul Walmsley static void __ssp_writel(u32 v, u16 offs, struct sifive_serial_port *ssp) 22645c054d0SPaul Walmsley { 22745c054d0SPaul Walmsley __ssp_early_writel(v, offs, &ssp->port); 22845c054d0SPaul Walmsley } 22945c054d0SPaul Walmsley 23045c054d0SPaul Walmsley /** 23145c054d0SPaul Walmsley * __ssp_readl() - read from a SiFive serial port register 23245c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port record 23345c054d0SPaul Walmsley * @offs: register address offset from the IP block base address 23445c054d0SPaul Walmsley * 23545c054d0SPaul Walmsley * Read the contents of the IP block register located at offset @offs from the 23645c054d0SPaul Walmsley * IP block base, given a pointer @ssp to a struct sifive_serial_port record. 23745c054d0SPaul Walmsley * 23845c054d0SPaul Walmsley * Context: Any context. 23945c054d0SPaul Walmsley * 24045c054d0SPaul Walmsley * Returns: the value of the UART register 24145c054d0SPaul Walmsley */ 24245c054d0SPaul Walmsley static u32 __ssp_readl(struct sifive_serial_port *ssp, u16 offs) 24345c054d0SPaul Walmsley { 24445c054d0SPaul Walmsley return __ssp_early_readl(&ssp->port, offs); 24545c054d0SPaul Walmsley } 24645c054d0SPaul Walmsley 24745c054d0SPaul Walmsley /** 24845c054d0SPaul Walmsley * sifive_serial_is_txfifo_full() - is the TXFIFO full? 24945c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 25045c054d0SPaul Walmsley * 25145c054d0SPaul Walmsley * Read the transmit FIFO "full" bit, returning a non-zero value if the 25245c054d0SPaul Walmsley * TX FIFO is full, or zero if space remains. Intended to be used to prevent 25345c054d0SPaul Walmsley * writes to the TX FIFO when it's full. 25445c054d0SPaul Walmsley * 25545c054d0SPaul Walmsley * Returns: SIFIVE_SERIAL_TXDATA_FULL_MASK (non-zero) if the transmit FIFO 25645c054d0SPaul Walmsley * is full, or 0 if space remains. 25745c054d0SPaul Walmsley */ 25845c054d0SPaul Walmsley static int sifive_serial_is_txfifo_full(struct sifive_serial_port *ssp) 25945c054d0SPaul Walmsley { 26045c054d0SPaul Walmsley return __ssp_readl(ssp, SIFIVE_SERIAL_TXDATA_OFFS) & 26145c054d0SPaul Walmsley SIFIVE_SERIAL_TXDATA_FULL_MASK; 26245c054d0SPaul Walmsley } 26345c054d0SPaul Walmsley 26445c054d0SPaul Walmsley /** 26545c054d0SPaul Walmsley * __ssp_transmit_char() - enqueue a byte to transmit onto the TX FIFO 26645c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 26745c054d0SPaul Walmsley * @ch: character to transmit 26845c054d0SPaul Walmsley * 26945c054d0SPaul Walmsley * Enqueue a byte @ch onto the transmit FIFO, given a pointer @ssp to the 27045c054d0SPaul Walmsley * struct sifive_serial_port * to transmit on. Caller should first check to 27145c054d0SPaul Walmsley * ensure that the TXFIFO has space; see sifive_serial_is_txfifo_full(). 27245c054d0SPaul Walmsley * 27345c054d0SPaul Walmsley * Context: Any context. 27445c054d0SPaul Walmsley */ 27545c054d0SPaul Walmsley static void __ssp_transmit_char(struct sifive_serial_port *ssp, int ch) 27645c054d0SPaul Walmsley { 27745c054d0SPaul Walmsley __ssp_writel(ch, SIFIVE_SERIAL_TXDATA_OFFS, ssp); 27845c054d0SPaul Walmsley } 27945c054d0SPaul Walmsley 28045c054d0SPaul Walmsley /** 28145c054d0SPaul Walmsley * __ssp_transmit_chars() - enqueue multiple bytes onto the TX FIFO 28245c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 28345c054d0SPaul Walmsley * 28445c054d0SPaul Walmsley * Transfer up to a TX FIFO size's worth of characters from the Linux serial 28545c054d0SPaul Walmsley * transmit buffer to the SiFive UART TX FIFO. 28645c054d0SPaul Walmsley * 28745c054d0SPaul Walmsley * Context: Any context. Expects @ssp->port.lock to be held by caller. 28845c054d0SPaul Walmsley */ 28945c054d0SPaul Walmsley static void __ssp_transmit_chars(struct sifive_serial_port *ssp) 29045c054d0SPaul Walmsley { 291d11cc8c3SJiri Slaby (SUSE) u8 ch; 29245c054d0SPaul Walmsley 293d11cc8c3SJiri Slaby (SUSE) uart_port_tx_limited(&ssp->port, ch, SIFIVE_TX_FIFO_DEPTH, 294d11cc8c3SJiri Slaby (SUSE) true, 295d11cc8c3SJiri Slaby (SUSE) __ssp_transmit_char(ssp, ch), 296d11cc8c3SJiri Slaby (SUSE) ({})); 29745c054d0SPaul Walmsley } 29845c054d0SPaul Walmsley 29945c054d0SPaul Walmsley /** 30045c054d0SPaul Walmsley * __ssp_enable_txwm() - enable transmit watermark interrupts 30145c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 30245c054d0SPaul Walmsley * 30345c054d0SPaul Walmsley * Enable interrupt generation when the transmit FIFO watermark is reached 30445c054d0SPaul Walmsley * on the SiFive UART referred to by @ssp. 30545c054d0SPaul Walmsley */ 30645c054d0SPaul Walmsley static void __ssp_enable_txwm(struct sifive_serial_port *ssp) 30745c054d0SPaul Walmsley { 30845c054d0SPaul Walmsley if (ssp->ier & SIFIVE_SERIAL_IE_TXWM_MASK) 30945c054d0SPaul Walmsley return; 31045c054d0SPaul Walmsley 31145c054d0SPaul Walmsley ssp->ier |= SIFIVE_SERIAL_IE_TXWM_MASK; 31245c054d0SPaul Walmsley __ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp); 31345c054d0SPaul Walmsley } 31445c054d0SPaul Walmsley 31545c054d0SPaul Walmsley /** 31645c054d0SPaul Walmsley * __ssp_enable_rxwm() - enable receive watermark interrupts 31745c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 31845c054d0SPaul Walmsley * 31945c054d0SPaul Walmsley * Enable interrupt generation when the receive FIFO watermark is reached 32045c054d0SPaul Walmsley * on the SiFive UART referred to by @ssp. 32145c054d0SPaul Walmsley */ 32245c054d0SPaul Walmsley static void __ssp_enable_rxwm(struct sifive_serial_port *ssp) 32345c054d0SPaul Walmsley { 32445c054d0SPaul Walmsley if (ssp->ier & SIFIVE_SERIAL_IE_RXWM_MASK) 32545c054d0SPaul Walmsley return; 32645c054d0SPaul Walmsley 32745c054d0SPaul Walmsley ssp->ier |= SIFIVE_SERIAL_IE_RXWM_MASK; 32845c054d0SPaul Walmsley __ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp); 32945c054d0SPaul Walmsley } 33045c054d0SPaul Walmsley 33145c054d0SPaul Walmsley /** 33245c054d0SPaul Walmsley * __ssp_disable_txwm() - disable transmit watermark interrupts 33345c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 33445c054d0SPaul Walmsley * 33545c054d0SPaul Walmsley * Disable interrupt generation when the transmit FIFO watermark is reached 33645c054d0SPaul Walmsley * on the UART referred to by @ssp. 33745c054d0SPaul Walmsley */ 33845c054d0SPaul Walmsley static void __ssp_disable_txwm(struct sifive_serial_port *ssp) 33945c054d0SPaul Walmsley { 34045c054d0SPaul Walmsley if (!(ssp->ier & SIFIVE_SERIAL_IE_TXWM_MASK)) 34145c054d0SPaul Walmsley return; 34245c054d0SPaul Walmsley 34345c054d0SPaul Walmsley ssp->ier &= ~SIFIVE_SERIAL_IE_TXWM_MASK; 34445c054d0SPaul Walmsley __ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp); 34545c054d0SPaul Walmsley } 34645c054d0SPaul Walmsley 34745c054d0SPaul Walmsley /** 34845c054d0SPaul Walmsley * __ssp_disable_rxwm() - disable receive watermark interrupts 34945c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 35045c054d0SPaul Walmsley * 35145c054d0SPaul Walmsley * Disable interrupt generation when the receive FIFO watermark is reached 35245c054d0SPaul Walmsley * on the UART referred to by @ssp. 35345c054d0SPaul Walmsley */ 35445c054d0SPaul Walmsley static void __ssp_disable_rxwm(struct sifive_serial_port *ssp) 35545c054d0SPaul Walmsley { 35645c054d0SPaul Walmsley if (!(ssp->ier & SIFIVE_SERIAL_IE_RXWM_MASK)) 35745c054d0SPaul Walmsley return; 35845c054d0SPaul Walmsley 35945c054d0SPaul Walmsley ssp->ier &= ~SIFIVE_SERIAL_IE_RXWM_MASK; 36045c054d0SPaul Walmsley __ssp_writel(ssp->ier, SIFIVE_SERIAL_IE_OFFS, ssp); 36145c054d0SPaul Walmsley } 36245c054d0SPaul Walmsley 36345c054d0SPaul Walmsley /** 36445c054d0SPaul Walmsley * __ssp_receive_char() - receive a byte from the UART 36545c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 36645c054d0SPaul Walmsley * @is_empty: char pointer to return whether the RX FIFO is empty 36745c054d0SPaul Walmsley * 36845c054d0SPaul Walmsley * Try to read a byte from the SiFive UART RX FIFO, referenced by 36945c054d0SPaul Walmsley * @ssp, and to return it. Also returns the RX FIFO empty bit in 37045c054d0SPaul Walmsley * the char pointed to by @ch. The caller must pass the byte back to the 37145c054d0SPaul Walmsley * Linux serial layer if needed. 37245c054d0SPaul Walmsley * 37345c054d0SPaul Walmsley * Returns: the byte read from the UART RX FIFO. 37445c054d0SPaul Walmsley */ 37545c054d0SPaul Walmsley static char __ssp_receive_char(struct sifive_serial_port *ssp, char *is_empty) 37645c054d0SPaul Walmsley { 37745c054d0SPaul Walmsley u32 v; 37845c054d0SPaul Walmsley u8 ch; 37945c054d0SPaul Walmsley 38045c054d0SPaul Walmsley v = __ssp_readl(ssp, SIFIVE_SERIAL_RXDATA_OFFS); 38145c054d0SPaul Walmsley 38245c054d0SPaul Walmsley if (!is_empty) 38345c054d0SPaul Walmsley WARN_ON(1); 38445c054d0SPaul Walmsley else 38545c054d0SPaul Walmsley *is_empty = (v & SIFIVE_SERIAL_RXDATA_EMPTY_MASK) >> 38645c054d0SPaul Walmsley SIFIVE_SERIAL_RXDATA_EMPTY_SHIFT; 38745c054d0SPaul Walmsley 38845c054d0SPaul Walmsley ch = (v & SIFIVE_SERIAL_RXDATA_DATA_MASK) >> 38945c054d0SPaul Walmsley SIFIVE_SERIAL_RXDATA_DATA_SHIFT; 39045c054d0SPaul Walmsley 39145c054d0SPaul Walmsley return ch; 39245c054d0SPaul Walmsley } 39345c054d0SPaul Walmsley 39445c054d0SPaul Walmsley /** 39545c054d0SPaul Walmsley * __ssp_receive_chars() - receive multiple bytes from the UART 39645c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 39745c054d0SPaul Walmsley * 39845c054d0SPaul Walmsley * Receive up to an RX FIFO's worth of bytes from the SiFive UART referred 39945c054d0SPaul Walmsley * to by @ssp and pass them up to the Linux serial layer. 40045c054d0SPaul Walmsley * 40145c054d0SPaul Walmsley * Context: Expects ssp->port.lock to be held by caller. 40245c054d0SPaul Walmsley */ 40345c054d0SPaul Walmsley static void __ssp_receive_chars(struct sifive_serial_port *ssp) 40445c054d0SPaul Walmsley { 40545c054d0SPaul Walmsley char is_empty; 40645c054d0SPaul Walmsley int c; 407fd2b55f8SJiri Slaby u8 ch; 40845c054d0SPaul Walmsley 40945c054d0SPaul Walmsley for (c = SIFIVE_RX_FIFO_DEPTH; c > 0; --c) { 41045c054d0SPaul Walmsley ch = __ssp_receive_char(ssp, &is_empty); 41145c054d0SPaul Walmsley if (is_empty) 41245c054d0SPaul Walmsley break; 41345c054d0SPaul Walmsley 41445c054d0SPaul Walmsley ssp->port.icount.rx++; 41545c054d0SPaul Walmsley uart_insert_char(&ssp->port, 0, 0, ch, TTY_NORMAL); 41645c054d0SPaul Walmsley } 41745c054d0SPaul Walmsley 41845c054d0SPaul Walmsley tty_flip_buffer_push(&ssp->port.state->port); 41945c054d0SPaul Walmsley } 42045c054d0SPaul Walmsley 42145c054d0SPaul Walmsley /** 42245c054d0SPaul Walmsley * __ssp_update_div() - calculate the divisor setting by the line rate 42345c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 42445c054d0SPaul Walmsley * 42545c054d0SPaul Walmsley * Calculate the appropriate value of the clock divisor for the UART 42645c054d0SPaul Walmsley * and target line rate referred to by @ssp and write it into the 42745c054d0SPaul Walmsley * hardware. 42845c054d0SPaul Walmsley */ 42945c054d0SPaul Walmsley static void __ssp_update_div(struct sifive_serial_port *ssp) 43045c054d0SPaul Walmsley { 43145c054d0SPaul Walmsley u16 div; 43245c054d0SPaul Walmsley 4334487cd3eSMaciej W. Rozycki div = DIV_ROUND_UP(ssp->port.uartclk, ssp->baud_rate) - 1; 43445c054d0SPaul Walmsley 43545c054d0SPaul Walmsley __ssp_writel(div, SIFIVE_SERIAL_DIV_OFFS, ssp); 43645c054d0SPaul Walmsley } 43745c054d0SPaul Walmsley 43845c054d0SPaul Walmsley /** 43945c054d0SPaul Walmsley * __ssp_update_baud_rate() - set the UART "baud rate" 44045c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 44145c054d0SPaul Walmsley * @rate: new target bit rate 44245c054d0SPaul Walmsley * 44345c054d0SPaul Walmsley * Calculate the UART divisor value for the target bit rate @rate for the 44445c054d0SPaul Walmsley * SiFive UART described by @ssp and program it into the UART. There may 44545c054d0SPaul Walmsley * be some error between the target bit rate and the actual bit rate implemented 44645c054d0SPaul Walmsley * by the UART due to clock ratio granularity. 44745c054d0SPaul Walmsley */ 44845c054d0SPaul Walmsley static void __ssp_update_baud_rate(struct sifive_serial_port *ssp, 44945c054d0SPaul Walmsley unsigned int rate) 45045c054d0SPaul Walmsley { 45145c054d0SPaul Walmsley if (ssp->baud_rate == rate) 45245c054d0SPaul Walmsley return; 45345c054d0SPaul Walmsley 45445c054d0SPaul Walmsley ssp->baud_rate = rate; 45545c054d0SPaul Walmsley __ssp_update_div(ssp); 45645c054d0SPaul Walmsley } 45745c054d0SPaul Walmsley 45845c054d0SPaul Walmsley /** 45945c054d0SPaul Walmsley * __ssp_set_stop_bits() - set the number of stop bits 46045c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 46145c054d0SPaul Walmsley * @nstop: 1 or 2 (stop bits) 46245c054d0SPaul Walmsley * 46345c054d0SPaul Walmsley * Program the SiFive UART referred to by @ssp to use @nstop stop bits. 46445c054d0SPaul Walmsley */ 46545c054d0SPaul Walmsley static void __ssp_set_stop_bits(struct sifive_serial_port *ssp, char nstop) 46645c054d0SPaul Walmsley { 46745c054d0SPaul Walmsley u32 v; 46845c054d0SPaul Walmsley 46945c054d0SPaul Walmsley if (nstop < 1 || nstop > 2) { 47045c054d0SPaul Walmsley WARN_ON(1); 47145c054d0SPaul Walmsley return; 47245c054d0SPaul Walmsley } 47345c054d0SPaul Walmsley 47445c054d0SPaul Walmsley v = __ssp_readl(ssp, SIFIVE_SERIAL_TXCTRL_OFFS); 47545c054d0SPaul Walmsley v &= ~SIFIVE_SERIAL_TXCTRL_NSTOP_MASK; 47645c054d0SPaul Walmsley v |= (nstop - 1) << SIFIVE_SERIAL_TXCTRL_NSTOP_SHIFT; 47745c054d0SPaul Walmsley __ssp_writel(v, SIFIVE_SERIAL_TXCTRL_OFFS, ssp); 47845c054d0SPaul Walmsley } 47945c054d0SPaul Walmsley 48045c054d0SPaul Walmsley /** 48145c054d0SPaul Walmsley * __ssp_wait_for_xmitr() - wait for an empty slot on the TX FIFO 48245c054d0SPaul Walmsley * @ssp: pointer to a struct sifive_serial_port 48345c054d0SPaul Walmsley * 48445c054d0SPaul Walmsley * Delay while the UART TX FIFO referred to by @ssp is marked as full. 48545c054d0SPaul Walmsley * 48645c054d0SPaul Walmsley * Context: Any context. 48745c054d0SPaul Walmsley */ 48845c054d0SPaul Walmsley static void __maybe_unused __ssp_wait_for_xmitr(struct sifive_serial_port *ssp) 48945c054d0SPaul Walmsley { 49045c054d0SPaul Walmsley while (sifive_serial_is_txfifo_full(ssp)) 49145c054d0SPaul Walmsley udelay(1); /* XXX Could probably be more intelligent here */ 49245c054d0SPaul Walmsley } 49345c054d0SPaul Walmsley 49445c054d0SPaul Walmsley /* 49545c054d0SPaul Walmsley * Linux serial API functions 49645c054d0SPaul Walmsley */ 49745c054d0SPaul Walmsley 49845c054d0SPaul Walmsley static void sifive_serial_stop_tx(struct uart_port *port) 49945c054d0SPaul Walmsley { 50045c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 50145c054d0SPaul Walmsley 50245c054d0SPaul Walmsley __ssp_disable_txwm(ssp); 50345c054d0SPaul Walmsley } 50445c054d0SPaul Walmsley 50545c054d0SPaul Walmsley static void sifive_serial_stop_rx(struct uart_port *port) 50645c054d0SPaul Walmsley { 50745c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 50845c054d0SPaul Walmsley 50945c054d0SPaul Walmsley __ssp_disable_rxwm(ssp); 51045c054d0SPaul Walmsley } 51145c054d0SPaul Walmsley 51245c054d0SPaul Walmsley static void sifive_serial_start_tx(struct uart_port *port) 51345c054d0SPaul Walmsley { 51445c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 51545c054d0SPaul Walmsley 51645c054d0SPaul Walmsley __ssp_enable_txwm(ssp); 51745c054d0SPaul Walmsley } 51845c054d0SPaul Walmsley 51945c054d0SPaul Walmsley static irqreturn_t sifive_serial_irq(int irq, void *dev_id) 52045c054d0SPaul Walmsley { 52145c054d0SPaul Walmsley struct sifive_serial_port *ssp = dev_id; 52245c054d0SPaul Walmsley u32 ip; 52345c054d0SPaul Walmsley 524*93614effSThomas Gleixner uart_port_lock(&ssp->port); 52545c054d0SPaul Walmsley 52645c054d0SPaul Walmsley ip = __ssp_readl(ssp, SIFIVE_SERIAL_IP_OFFS); 52745c054d0SPaul Walmsley if (!ip) { 528*93614effSThomas Gleixner uart_port_unlock(&ssp->port); 52945c054d0SPaul Walmsley return IRQ_NONE; 53045c054d0SPaul Walmsley } 53145c054d0SPaul Walmsley 53245c054d0SPaul Walmsley if (ip & SIFIVE_SERIAL_IP_RXWM_MASK) 53345c054d0SPaul Walmsley __ssp_receive_chars(ssp); 53445c054d0SPaul Walmsley if (ip & SIFIVE_SERIAL_IP_TXWM_MASK) 53545c054d0SPaul Walmsley __ssp_transmit_chars(ssp); 53645c054d0SPaul Walmsley 537*93614effSThomas Gleixner uart_port_unlock(&ssp->port); 53845c054d0SPaul Walmsley 53945c054d0SPaul Walmsley return IRQ_HANDLED; 54045c054d0SPaul Walmsley } 54145c054d0SPaul Walmsley 54245c054d0SPaul Walmsley static unsigned int sifive_serial_tx_empty(struct uart_port *port) 54345c054d0SPaul Walmsley { 54445c054d0SPaul Walmsley return TIOCSER_TEMT; 54545c054d0SPaul Walmsley } 54645c054d0SPaul Walmsley 54745c054d0SPaul Walmsley static unsigned int sifive_serial_get_mctrl(struct uart_port *port) 54845c054d0SPaul Walmsley { 54945c054d0SPaul Walmsley return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR; 55045c054d0SPaul Walmsley } 55145c054d0SPaul Walmsley 55245c054d0SPaul Walmsley static void sifive_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) 55345c054d0SPaul Walmsley { 55445c054d0SPaul Walmsley /* IP block does not support these signals */ 55545c054d0SPaul Walmsley } 55645c054d0SPaul Walmsley 55745c054d0SPaul Walmsley static void sifive_serial_break_ctl(struct uart_port *port, int break_state) 55845c054d0SPaul Walmsley { 55945c054d0SPaul Walmsley /* IP block does not support sending a break */ 56045c054d0SPaul Walmsley } 56145c054d0SPaul Walmsley 56245c054d0SPaul Walmsley static int sifive_serial_startup(struct uart_port *port) 56345c054d0SPaul Walmsley { 56445c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 56545c054d0SPaul Walmsley 56645c054d0SPaul Walmsley __ssp_enable_rxwm(ssp); 56745c054d0SPaul Walmsley 56845c054d0SPaul Walmsley return 0; 56945c054d0SPaul Walmsley } 57045c054d0SPaul Walmsley 57145c054d0SPaul Walmsley static void sifive_serial_shutdown(struct uart_port *port) 57245c054d0SPaul Walmsley { 57345c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 57445c054d0SPaul Walmsley 57545c054d0SPaul Walmsley __ssp_disable_rxwm(ssp); 57645c054d0SPaul Walmsley __ssp_disable_txwm(ssp); 57745c054d0SPaul Walmsley } 57845c054d0SPaul Walmsley 57945c054d0SPaul Walmsley /** 58045c054d0SPaul Walmsley * sifive_serial_clk_notifier() - clock post-rate-change notifier 58145c054d0SPaul Walmsley * @nb: pointer to the struct notifier_block, from the notifier code 58245c054d0SPaul Walmsley * @event: event mask from the notifier code 58345c054d0SPaul Walmsley * @data: pointer to the struct clk_notifier_data from the notifier code 58445c054d0SPaul Walmsley * 58545c054d0SPaul Walmsley * On the V0 SoC, the UART IP block is derived from the CPU clock source 58645c054d0SPaul Walmsley * after a synchronous divide-by-two divider, so any CPU clock rate change 5874cbd7814SPalmer Dabbelt * requires the UART baud rate to be updated. This presumably corrupts any 5884cbd7814SPalmer Dabbelt * serial word currently being transmitted or received. In order to avoid 5894cbd7814SPalmer Dabbelt * corrupting the output data stream, we drain the transmit queue before 5904cbd7814SPalmer Dabbelt * allowing the clock's rate to be changed. 59145c054d0SPaul Walmsley */ 59245c054d0SPaul Walmsley static int sifive_serial_clk_notifier(struct notifier_block *nb, 59345c054d0SPaul Walmsley unsigned long event, void *data) 59445c054d0SPaul Walmsley { 59545c054d0SPaul Walmsley struct clk_notifier_data *cnd = data; 59645c054d0SPaul Walmsley struct sifive_serial_port *ssp = notifier_to_sifive_serial_port(nb); 59745c054d0SPaul Walmsley 5984cbd7814SPalmer Dabbelt if (event == PRE_RATE_CHANGE) { 5994cbd7814SPalmer Dabbelt /* 6004cbd7814SPalmer Dabbelt * The TX watermark is always set to 1 by this driver, which 6014cbd7814SPalmer Dabbelt * means that the TX busy bit will lower when there are 0 bytes 6024cbd7814SPalmer Dabbelt * left in the TX queue -- in other words, when the TX FIFO is 6034cbd7814SPalmer Dabbelt * empty. 6044cbd7814SPalmer Dabbelt */ 6054cbd7814SPalmer Dabbelt __ssp_wait_for_xmitr(ssp); 6064cbd7814SPalmer Dabbelt /* 6074cbd7814SPalmer Dabbelt * On the cycle the TX FIFO goes empty there is still a full 6084cbd7814SPalmer Dabbelt * UART frame left to be transmitted in the shift register. 6094cbd7814SPalmer Dabbelt * The UART provides no way for software to directly determine 6104cbd7814SPalmer Dabbelt * when that last frame has been transmitted, so we just sleep 6114cbd7814SPalmer Dabbelt * here instead. As we're not tracking the number of stop bits 6124cbd7814SPalmer Dabbelt * they're just worst cased here. The rest of the serial 6134cbd7814SPalmer Dabbelt * framing parameters aren't configurable by software. 6144cbd7814SPalmer Dabbelt */ 6154cbd7814SPalmer Dabbelt udelay(DIV_ROUND_UP(12 * 1000 * 1000, ssp->baud_rate)); 6164cbd7814SPalmer Dabbelt } 6174cbd7814SPalmer Dabbelt 6184487cd3eSMaciej W. Rozycki if (event == POST_RATE_CHANGE && ssp->port.uartclk != cnd->new_rate) { 6194487cd3eSMaciej W. Rozycki ssp->port.uartclk = cnd->new_rate; 62045c054d0SPaul Walmsley __ssp_update_div(ssp); 62145c054d0SPaul Walmsley } 62245c054d0SPaul Walmsley 62345c054d0SPaul Walmsley return NOTIFY_OK; 62445c054d0SPaul Walmsley } 62545c054d0SPaul Walmsley 62645c054d0SPaul Walmsley static void sifive_serial_set_termios(struct uart_port *port, 62745c054d0SPaul Walmsley struct ktermios *termios, 628bec5b814SIlpo Järvinen const struct ktermios *old) 62945c054d0SPaul Walmsley { 63045c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 63145c054d0SPaul Walmsley unsigned long flags; 63245c054d0SPaul Walmsley u32 v, old_v; 63345c054d0SPaul Walmsley int rate; 63445c054d0SPaul Walmsley char nstop; 63545c054d0SPaul Walmsley 636c069d275SIlpo Järvinen if ((termios->c_cflag & CSIZE) != CS8) { 63745c054d0SPaul Walmsley dev_err_once(ssp->port.dev, "only 8-bit words supported\n"); 638c069d275SIlpo Järvinen termios->c_cflag &= ~CSIZE; 639c069d275SIlpo Järvinen termios->c_cflag |= CS8; 640c069d275SIlpo Järvinen } 64145c054d0SPaul Walmsley if (termios->c_iflag & (INPCK | PARMRK)) 64245c054d0SPaul Walmsley dev_err_once(ssp->port.dev, "parity checking not supported\n"); 64345c054d0SPaul Walmsley if (termios->c_iflag & BRKINT) 64445c054d0SPaul Walmsley dev_err_once(ssp->port.dev, "BREAK detection not supported\n"); 645c069d275SIlpo Järvinen termios->c_iflag &= ~(INPCK|PARMRK|BRKINT); 64645c054d0SPaul Walmsley 64745c054d0SPaul Walmsley /* Set number of stop bits */ 64845c054d0SPaul Walmsley nstop = (termios->c_cflag & CSTOPB) ? 2 : 1; 64945c054d0SPaul Walmsley __ssp_set_stop_bits(ssp, nstop); 65045c054d0SPaul Walmsley 65145c054d0SPaul Walmsley /* Set line rate */ 6524487cd3eSMaciej W. Rozycki rate = uart_get_baud_rate(port, termios, old, 0, 6534487cd3eSMaciej W. Rozycki ssp->port.uartclk / 16); 65445c054d0SPaul Walmsley __ssp_update_baud_rate(ssp, rate); 65545c054d0SPaul Walmsley 656*93614effSThomas Gleixner uart_port_lock_irqsave(&ssp->port, &flags); 65745c054d0SPaul Walmsley 65845c054d0SPaul Walmsley /* Update the per-port timeout */ 65945c054d0SPaul Walmsley uart_update_timeout(port, termios->c_cflag, rate); 66045c054d0SPaul Walmsley 66145c054d0SPaul Walmsley ssp->port.read_status_mask = 0; 66245c054d0SPaul Walmsley 66345c054d0SPaul Walmsley /* Ignore all characters if CREAD is not set */ 66445c054d0SPaul Walmsley v = __ssp_readl(ssp, SIFIVE_SERIAL_RXCTRL_OFFS); 66545c054d0SPaul Walmsley old_v = v; 66645c054d0SPaul Walmsley if ((termios->c_cflag & CREAD) == 0) 66745c054d0SPaul Walmsley v &= SIFIVE_SERIAL_RXCTRL_RXEN_MASK; 66845c054d0SPaul Walmsley else 66945c054d0SPaul Walmsley v |= SIFIVE_SERIAL_RXCTRL_RXEN_MASK; 67045c054d0SPaul Walmsley if (v != old_v) 67145c054d0SPaul Walmsley __ssp_writel(v, SIFIVE_SERIAL_RXCTRL_OFFS, ssp); 67245c054d0SPaul Walmsley 673*93614effSThomas Gleixner uart_port_unlock_irqrestore(&ssp->port, flags); 67445c054d0SPaul Walmsley } 67545c054d0SPaul Walmsley 67645c054d0SPaul Walmsley static void sifive_serial_release_port(struct uart_port *port) 67745c054d0SPaul Walmsley { 67845c054d0SPaul Walmsley } 67945c054d0SPaul Walmsley 68045c054d0SPaul Walmsley static int sifive_serial_request_port(struct uart_port *port) 68145c054d0SPaul Walmsley { 68245c054d0SPaul Walmsley return 0; 68345c054d0SPaul Walmsley } 68445c054d0SPaul Walmsley 68545c054d0SPaul Walmsley static void sifive_serial_config_port(struct uart_port *port, int flags) 68645c054d0SPaul Walmsley { 68745c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 68845c054d0SPaul Walmsley 68945c054d0SPaul Walmsley ssp->port.type = PORT_SIFIVE_V0; 69045c054d0SPaul Walmsley } 69145c054d0SPaul Walmsley 69245c054d0SPaul Walmsley static int sifive_serial_verify_port(struct uart_port *port, 69345c054d0SPaul Walmsley struct serial_struct *ser) 69445c054d0SPaul Walmsley { 69545c054d0SPaul Walmsley return -EINVAL; 69645c054d0SPaul Walmsley } 69745c054d0SPaul Walmsley 69845c054d0SPaul Walmsley static const char *sifive_serial_type(struct uart_port *port) 69945c054d0SPaul Walmsley { 70045c054d0SPaul Walmsley return port->type == PORT_SIFIVE_V0 ? "SiFive UART v0" : NULL; 70145c054d0SPaul Walmsley } 70245c054d0SPaul Walmsley 703630db5cbSVincent Chen #ifdef CONFIG_CONSOLE_POLL 704630db5cbSVincent Chen static int sifive_serial_poll_get_char(struct uart_port *port) 705630db5cbSVincent Chen { 706630db5cbSVincent Chen struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 707630db5cbSVincent Chen char is_empty, ch; 708630db5cbSVincent Chen 709630db5cbSVincent Chen ch = __ssp_receive_char(ssp, &is_empty); 710630db5cbSVincent Chen if (is_empty) 711630db5cbSVincent Chen return NO_POLL_CHAR; 712630db5cbSVincent Chen 713630db5cbSVincent Chen return ch; 714630db5cbSVincent Chen } 715630db5cbSVincent Chen 716630db5cbSVincent Chen static void sifive_serial_poll_put_char(struct uart_port *port, 717630db5cbSVincent Chen unsigned char c) 718630db5cbSVincent Chen { 719630db5cbSVincent Chen struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 720630db5cbSVincent Chen 721630db5cbSVincent Chen __ssp_wait_for_xmitr(ssp); 722630db5cbSVincent Chen __ssp_transmit_char(ssp, c); 723630db5cbSVincent Chen } 724630db5cbSVincent Chen #endif /* CONFIG_CONSOLE_POLL */ 725630db5cbSVincent Chen 72645c054d0SPaul Walmsley /* 72745c054d0SPaul Walmsley * Early console support 72845c054d0SPaul Walmsley */ 72945c054d0SPaul Walmsley 73045c054d0SPaul Walmsley #ifdef CONFIG_SERIAL_EARLYCON 7313f8bab17SJiri Slaby static void early_sifive_serial_putc(struct uart_port *port, unsigned char c) 73245c054d0SPaul Walmsley { 73345c054d0SPaul Walmsley while (__ssp_early_readl(port, SIFIVE_SERIAL_TXDATA_OFFS) & 73445c054d0SPaul Walmsley SIFIVE_SERIAL_TXDATA_FULL_MASK) 73545c054d0SPaul Walmsley cpu_relax(); 73645c054d0SPaul Walmsley 73745c054d0SPaul Walmsley __ssp_early_writel(c, SIFIVE_SERIAL_TXDATA_OFFS, port); 73845c054d0SPaul Walmsley } 73945c054d0SPaul Walmsley 74045c054d0SPaul Walmsley static void early_sifive_serial_write(struct console *con, const char *s, 74145c054d0SPaul Walmsley unsigned int n) 74245c054d0SPaul Walmsley { 74345c054d0SPaul Walmsley struct earlycon_device *dev = con->data; 74445c054d0SPaul Walmsley struct uart_port *port = &dev->port; 74545c054d0SPaul Walmsley 74645c054d0SPaul Walmsley uart_console_write(port, s, n, early_sifive_serial_putc); 74745c054d0SPaul Walmsley } 74845c054d0SPaul Walmsley 74945c054d0SPaul Walmsley static int __init early_sifive_serial_setup(struct earlycon_device *dev, 75045c054d0SPaul Walmsley const char *options) 75145c054d0SPaul Walmsley { 75245c054d0SPaul Walmsley struct uart_port *port = &dev->port; 75345c054d0SPaul Walmsley 75445c054d0SPaul Walmsley if (!port->membase) 75545c054d0SPaul Walmsley return -ENODEV; 75645c054d0SPaul Walmsley 75745c054d0SPaul Walmsley dev->con->write = early_sifive_serial_write; 75845c054d0SPaul Walmsley 75945c054d0SPaul Walmsley return 0; 76045c054d0SPaul Walmsley } 76145c054d0SPaul Walmsley 76245c054d0SPaul Walmsley OF_EARLYCON_DECLARE(sifive, "sifive,uart0", early_sifive_serial_setup); 76345c054d0SPaul Walmsley OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0", 76445c054d0SPaul Walmsley early_sifive_serial_setup); 76545c054d0SPaul Walmsley #endif /* CONFIG_SERIAL_EARLYCON */ 76645c054d0SPaul Walmsley 76745c054d0SPaul Walmsley /* 76845c054d0SPaul Walmsley * Linux console interface 76945c054d0SPaul Walmsley */ 77045c054d0SPaul Walmsley 77145c054d0SPaul Walmsley #ifdef CONFIG_SERIAL_SIFIVE_CONSOLE 77245c054d0SPaul Walmsley 77345c054d0SPaul Walmsley static struct sifive_serial_port *sifive_serial_console_ports[SIFIVE_SERIAL_MAX_PORTS]; 77445c054d0SPaul Walmsley 7753f8bab17SJiri Slaby static void sifive_serial_console_putchar(struct uart_port *port, unsigned char ch) 77645c054d0SPaul Walmsley { 77745c054d0SPaul Walmsley struct sifive_serial_port *ssp = port_to_sifive_serial_port(port); 77845c054d0SPaul Walmsley 77945c054d0SPaul Walmsley __ssp_wait_for_xmitr(ssp); 78045c054d0SPaul Walmsley __ssp_transmit_char(ssp, ch); 78145c054d0SPaul Walmsley } 78245c054d0SPaul Walmsley 78345c054d0SPaul Walmsley static void sifive_serial_console_write(struct console *co, const char *s, 78445c054d0SPaul Walmsley unsigned int count) 78545c054d0SPaul Walmsley { 78645c054d0SPaul Walmsley struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index]; 78745c054d0SPaul Walmsley unsigned long flags; 78845c054d0SPaul Walmsley unsigned int ier; 78945c054d0SPaul Walmsley int locked = 1; 79045c054d0SPaul Walmsley 79145c054d0SPaul Walmsley if (!ssp) 79245c054d0SPaul Walmsley return; 79345c054d0SPaul Walmsley 79445c054d0SPaul Walmsley local_irq_save(flags); 79545c054d0SPaul Walmsley if (ssp->port.sysrq) 79645c054d0SPaul Walmsley locked = 0; 79745c054d0SPaul Walmsley else if (oops_in_progress) 798*93614effSThomas Gleixner locked = uart_port_trylock(&ssp->port); 79945c054d0SPaul Walmsley else 800*93614effSThomas Gleixner uart_port_lock(&ssp->port); 80145c054d0SPaul Walmsley 80245c054d0SPaul Walmsley ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS); 80345c054d0SPaul Walmsley __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp); 80445c054d0SPaul Walmsley 80545c054d0SPaul Walmsley uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar); 80645c054d0SPaul Walmsley 80745c054d0SPaul Walmsley __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp); 80845c054d0SPaul Walmsley 80945c054d0SPaul Walmsley if (locked) 810*93614effSThomas Gleixner uart_port_unlock(&ssp->port); 81145c054d0SPaul Walmsley local_irq_restore(flags); 81245c054d0SPaul Walmsley } 81345c054d0SPaul Walmsley 8149b8fef63SSamuel Holland static int sifive_serial_console_setup(struct console *co, char *options) 81545c054d0SPaul Walmsley { 81645c054d0SPaul Walmsley struct sifive_serial_port *ssp; 81745c054d0SPaul Walmsley int baud = SIFIVE_DEFAULT_BAUD_RATE; 81845c054d0SPaul Walmsley int bits = 8; 81945c054d0SPaul Walmsley int parity = 'n'; 82045c054d0SPaul Walmsley int flow = 'n'; 82145c054d0SPaul Walmsley 82245c054d0SPaul Walmsley if (co->index < 0 || co->index >= SIFIVE_SERIAL_MAX_PORTS) 82345c054d0SPaul Walmsley return -ENODEV; 82445c054d0SPaul Walmsley 82545c054d0SPaul Walmsley ssp = sifive_serial_console_ports[co->index]; 82645c054d0SPaul Walmsley if (!ssp) 82745c054d0SPaul Walmsley return -ENODEV; 82845c054d0SPaul Walmsley 82945c054d0SPaul Walmsley if (options) 83045c054d0SPaul Walmsley uart_parse_options(options, &baud, &parity, &bits, &flow); 83145c054d0SPaul Walmsley 83245c054d0SPaul Walmsley return uart_set_options(&ssp->port, co, baud, parity, bits, flow); 83345c054d0SPaul Walmsley } 83445c054d0SPaul Walmsley 83545c054d0SPaul Walmsley static struct uart_driver sifive_serial_uart_driver; 83645c054d0SPaul Walmsley 83745c054d0SPaul Walmsley static struct console sifive_serial_console = { 83845c054d0SPaul Walmsley .name = SIFIVE_TTY_PREFIX, 83945c054d0SPaul Walmsley .write = sifive_serial_console_write, 84045c054d0SPaul Walmsley .device = uart_console_device, 84145c054d0SPaul Walmsley .setup = sifive_serial_console_setup, 84245c054d0SPaul Walmsley .flags = CON_PRINTBUFFER, 84345c054d0SPaul Walmsley .index = -1, 84445c054d0SPaul Walmsley .data = &sifive_serial_uart_driver, 84545c054d0SPaul Walmsley }; 84645c054d0SPaul Walmsley 84745c054d0SPaul Walmsley static int __init sifive_console_init(void) 84845c054d0SPaul Walmsley { 84945c054d0SPaul Walmsley register_console(&sifive_serial_console); 85045c054d0SPaul Walmsley return 0; 85145c054d0SPaul Walmsley } 85245c054d0SPaul Walmsley 85345c054d0SPaul Walmsley console_initcall(sifive_console_init); 85445c054d0SPaul Walmsley 85545c054d0SPaul Walmsley static void __ssp_add_console_port(struct sifive_serial_port *ssp) 85645c054d0SPaul Walmsley { 85745c054d0SPaul Walmsley sifive_serial_console_ports[ssp->port.line] = ssp; 85845c054d0SPaul Walmsley } 85945c054d0SPaul Walmsley 86045c054d0SPaul Walmsley static void __ssp_remove_console_port(struct sifive_serial_port *ssp) 86145c054d0SPaul Walmsley { 86227e8c8b4SColin Ian King sifive_serial_console_ports[ssp->port.line] = NULL; 86345c054d0SPaul Walmsley } 86445c054d0SPaul Walmsley 86545c054d0SPaul Walmsley #define SIFIVE_SERIAL_CONSOLE (&sifive_serial_console) 86645c054d0SPaul Walmsley 86745c054d0SPaul Walmsley #else 86845c054d0SPaul Walmsley 86945c054d0SPaul Walmsley #define SIFIVE_SERIAL_CONSOLE NULL 87045c054d0SPaul Walmsley 87145c054d0SPaul Walmsley static void __ssp_add_console_port(struct sifive_serial_port *ssp) 87245c054d0SPaul Walmsley {} 87345c054d0SPaul Walmsley static void __ssp_remove_console_port(struct sifive_serial_port *ssp) 87445c054d0SPaul Walmsley {} 87545c054d0SPaul Walmsley 87645c054d0SPaul Walmsley #endif 87745c054d0SPaul Walmsley 87845c054d0SPaul Walmsley static const struct uart_ops sifive_serial_uops = { 87945c054d0SPaul Walmsley .tx_empty = sifive_serial_tx_empty, 88045c054d0SPaul Walmsley .set_mctrl = sifive_serial_set_mctrl, 88145c054d0SPaul Walmsley .get_mctrl = sifive_serial_get_mctrl, 88245c054d0SPaul Walmsley .stop_tx = sifive_serial_stop_tx, 88345c054d0SPaul Walmsley .start_tx = sifive_serial_start_tx, 88445c054d0SPaul Walmsley .stop_rx = sifive_serial_stop_rx, 88545c054d0SPaul Walmsley .break_ctl = sifive_serial_break_ctl, 88645c054d0SPaul Walmsley .startup = sifive_serial_startup, 88745c054d0SPaul Walmsley .shutdown = sifive_serial_shutdown, 88845c054d0SPaul Walmsley .set_termios = sifive_serial_set_termios, 88945c054d0SPaul Walmsley .type = sifive_serial_type, 89045c054d0SPaul Walmsley .release_port = sifive_serial_release_port, 89145c054d0SPaul Walmsley .request_port = sifive_serial_request_port, 89245c054d0SPaul Walmsley .config_port = sifive_serial_config_port, 89345c054d0SPaul Walmsley .verify_port = sifive_serial_verify_port, 894630db5cbSVincent Chen #ifdef CONFIG_CONSOLE_POLL 895630db5cbSVincent Chen .poll_get_char = sifive_serial_poll_get_char, 896630db5cbSVincent Chen .poll_put_char = sifive_serial_poll_put_char, 897630db5cbSVincent Chen #endif 89845c054d0SPaul Walmsley }; 89945c054d0SPaul Walmsley 90045c054d0SPaul Walmsley static struct uart_driver sifive_serial_uart_driver = { 90145c054d0SPaul Walmsley .owner = THIS_MODULE, 90245c054d0SPaul Walmsley .driver_name = SIFIVE_SERIAL_NAME, 90345c054d0SPaul Walmsley .dev_name = SIFIVE_TTY_PREFIX, 90445c054d0SPaul Walmsley .nr = SIFIVE_SERIAL_MAX_PORTS, 90545c054d0SPaul Walmsley .cons = SIFIVE_SERIAL_CONSOLE, 90645c054d0SPaul Walmsley }; 90745c054d0SPaul Walmsley 90845c054d0SPaul Walmsley static int sifive_serial_probe(struct platform_device *pdev) 90945c054d0SPaul Walmsley { 91045c054d0SPaul Walmsley struct sifive_serial_port *ssp; 91145c054d0SPaul Walmsley struct resource *mem; 91245c054d0SPaul Walmsley struct clk *clk; 91345c054d0SPaul Walmsley void __iomem *base; 91445c054d0SPaul Walmsley int irq, id, r; 91545c054d0SPaul Walmsley 91645c054d0SPaul Walmsley irq = platform_get_irq(pdev, 0); 9171df21786SStephen Boyd if (irq < 0) 91845c054d0SPaul Walmsley return -EPROBE_DEFER; 91945c054d0SPaul Walmsley 920b75c1da9SYangtao Li base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); 921b75c1da9SYangtao Li if (IS_ERR(base)) 92245c054d0SPaul Walmsley return PTR_ERR(base); 92345c054d0SPaul Walmsley 92464379204SOlof Johansson clk = devm_clk_get_enabled(&pdev->dev, NULL); 92545c054d0SPaul Walmsley if (IS_ERR(clk)) { 92645c054d0SPaul Walmsley dev_err(&pdev->dev, "unable to find controller clock\n"); 92745c054d0SPaul Walmsley return PTR_ERR(clk); 92845c054d0SPaul Walmsley } 92945c054d0SPaul Walmsley 93045c054d0SPaul Walmsley id = of_alias_get_id(pdev->dev.of_node, "serial"); 93145c054d0SPaul Walmsley if (id < 0) { 93245c054d0SPaul Walmsley dev_err(&pdev->dev, "missing aliases entry\n"); 93345c054d0SPaul Walmsley return id; 93445c054d0SPaul Walmsley } 93545c054d0SPaul Walmsley 93645c054d0SPaul Walmsley #ifdef CONFIG_SERIAL_SIFIVE_CONSOLE 93745c054d0SPaul Walmsley if (id > SIFIVE_SERIAL_MAX_PORTS) { 93845c054d0SPaul Walmsley dev_err(&pdev->dev, "too many UARTs (%d)\n", id); 93945c054d0SPaul Walmsley return -EINVAL; 94045c054d0SPaul Walmsley } 94145c054d0SPaul Walmsley #endif 94245c054d0SPaul Walmsley 94345c054d0SPaul Walmsley ssp = devm_kzalloc(&pdev->dev, sizeof(*ssp), GFP_KERNEL); 94445c054d0SPaul Walmsley if (!ssp) 94545c054d0SPaul Walmsley return -ENOMEM; 94645c054d0SPaul Walmsley 94745c054d0SPaul Walmsley ssp->port.dev = &pdev->dev; 94845c054d0SPaul Walmsley ssp->port.type = PORT_SIFIVE_V0; 94945c054d0SPaul Walmsley ssp->port.iotype = UPIO_MEM; 95045c054d0SPaul Walmsley ssp->port.irq = irq; 95145c054d0SPaul Walmsley ssp->port.fifosize = SIFIVE_TX_FIFO_DEPTH; 95245c054d0SPaul Walmsley ssp->port.ops = &sifive_serial_uops; 95345c054d0SPaul Walmsley ssp->port.line = id; 95445c054d0SPaul Walmsley ssp->port.mapbase = mem->start; 95545c054d0SPaul Walmsley ssp->port.membase = base; 95645c054d0SPaul Walmsley ssp->dev = &pdev->dev; 95745c054d0SPaul Walmsley ssp->clk = clk; 95845c054d0SPaul Walmsley ssp->clk_notifier.notifier_call = sifive_serial_clk_notifier; 95945c054d0SPaul Walmsley 96045c054d0SPaul Walmsley r = clk_notifier_register(ssp->clk, &ssp->clk_notifier); 96145c054d0SPaul Walmsley if (r) { 96245c054d0SPaul Walmsley dev_err(&pdev->dev, "could not register clock notifier: %d\n", 96345c054d0SPaul Walmsley r); 96445c054d0SPaul Walmsley goto probe_out1; 96545c054d0SPaul Walmsley } 96645c054d0SPaul Walmsley 96745c054d0SPaul Walmsley /* Set up clock divider */ 9684487cd3eSMaciej W. Rozycki ssp->port.uartclk = clk_get_rate(ssp->clk); 96945c054d0SPaul Walmsley ssp->baud_rate = SIFIVE_DEFAULT_BAUD_RATE; 97045c054d0SPaul Walmsley __ssp_update_div(ssp); 97145c054d0SPaul Walmsley 97245c054d0SPaul Walmsley platform_set_drvdata(pdev, ssp); 97345c054d0SPaul Walmsley 97445c054d0SPaul Walmsley /* Enable transmits and set the watermark level to 1 */ 97545c054d0SPaul Walmsley __ssp_writel((1 << SIFIVE_SERIAL_TXCTRL_TXCNT_SHIFT) | 97645c054d0SPaul Walmsley SIFIVE_SERIAL_TXCTRL_TXEN_MASK, 97745c054d0SPaul Walmsley SIFIVE_SERIAL_TXCTRL_OFFS, ssp); 97845c054d0SPaul Walmsley 97945c054d0SPaul Walmsley /* Enable receives and set the watermark level to 0 */ 98045c054d0SPaul Walmsley __ssp_writel((0 << SIFIVE_SERIAL_RXCTRL_RXCNT_SHIFT) | 98145c054d0SPaul Walmsley SIFIVE_SERIAL_RXCTRL_RXEN_MASK, 98245c054d0SPaul Walmsley SIFIVE_SERIAL_RXCTRL_OFFS, ssp); 98345c054d0SPaul Walmsley 98445c054d0SPaul Walmsley r = request_irq(ssp->port.irq, sifive_serial_irq, ssp->port.irqflags, 98545c054d0SPaul Walmsley dev_name(&pdev->dev), ssp); 98645c054d0SPaul Walmsley if (r) { 98745c054d0SPaul Walmsley dev_err(&pdev->dev, "could not attach interrupt: %d\n", r); 98845c054d0SPaul Walmsley goto probe_out2; 98945c054d0SPaul Walmsley } 99045c054d0SPaul Walmsley 99145c054d0SPaul Walmsley __ssp_add_console_port(ssp); 99245c054d0SPaul Walmsley 99345c054d0SPaul Walmsley r = uart_add_one_port(&sifive_serial_uart_driver, &ssp->port); 99445c054d0SPaul Walmsley if (r != 0) { 99545c054d0SPaul Walmsley dev_err(&pdev->dev, "could not add uart: %d\n", r); 99645c054d0SPaul Walmsley goto probe_out3; 99745c054d0SPaul Walmsley } 99845c054d0SPaul Walmsley 99945c054d0SPaul Walmsley return 0; 100045c054d0SPaul Walmsley 100145c054d0SPaul Walmsley probe_out3: 100245c054d0SPaul Walmsley __ssp_remove_console_port(ssp); 100345c054d0SPaul Walmsley free_irq(ssp->port.irq, ssp); 100445c054d0SPaul Walmsley probe_out2: 100545c054d0SPaul Walmsley clk_notifier_unregister(ssp->clk, &ssp->clk_notifier); 100645c054d0SPaul Walmsley probe_out1: 100745c054d0SPaul Walmsley return r; 100845c054d0SPaul Walmsley } 100945c054d0SPaul Walmsley 101045c054d0SPaul Walmsley static int sifive_serial_remove(struct platform_device *dev) 101145c054d0SPaul Walmsley { 101245c054d0SPaul Walmsley struct sifive_serial_port *ssp = platform_get_drvdata(dev); 101345c054d0SPaul Walmsley 101445c054d0SPaul Walmsley __ssp_remove_console_port(ssp); 101545c054d0SPaul Walmsley uart_remove_one_port(&sifive_serial_uart_driver, &ssp->port); 101645c054d0SPaul Walmsley free_irq(ssp->port.irq, ssp); 101745c054d0SPaul Walmsley clk_notifier_unregister(ssp->clk, &ssp->clk_notifier); 101845c054d0SPaul Walmsley 101945c054d0SPaul Walmsley return 0; 102045c054d0SPaul Walmsley } 102145c054d0SPaul Walmsley 10228a6498f2SNick Hu static int sifive_serial_suspend(struct device *dev) 10238a6498f2SNick Hu { 10248a6498f2SNick Hu struct sifive_serial_port *ssp = dev_get_drvdata(dev); 10258a6498f2SNick Hu 10268a6498f2SNick Hu return uart_suspend_port(&sifive_serial_uart_driver, &ssp->port); 10278a6498f2SNick Hu } 10288a6498f2SNick Hu 10298a6498f2SNick Hu static int sifive_serial_resume(struct device *dev) 10308a6498f2SNick Hu { 10318a6498f2SNick Hu struct sifive_serial_port *ssp = dev_get_drvdata(dev); 10328a6498f2SNick Hu 10338a6498f2SNick Hu return uart_resume_port(&sifive_serial_uart_driver, &ssp->port); 10348a6498f2SNick Hu } 10358a6498f2SNick Hu 10368a6498f2SNick Hu DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend, 10378a6498f2SNick Hu sifive_serial_resume); 10388a6498f2SNick Hu 103945c054d0SPaul Walmsley static const struct of_device_id sifive_serial_of_match[] = { 104045c054d0SPaul Walmsley { .compatible = "sifive,fu540-c000-uart0" }, 104145c054d0SPaul Walmsley { .compatible = "sifive,uart0" }, 104245c054d0SPaul Walmsley {}, 104345c054d0SPaul Walmsley }; 104445c054d0SPaul Walmsley MODULE_DEVICE_TABLE(of, sifive_serial_of_match); 104545c054d0SPaul Walmsley 104645c054d0SPaul Walmsley static struct platform_driver sifive_serial_platform_driver = { 104745c054d0SPaul Walmsley .probe = sifive_serial_probe, 104845c054d0SPaul Walmsley .remove = sifive_serial_remove, 104945c054d0SPaul Walmsley .driver = { 105045c054d0SPaul Walmsley .name = SIFIVE_SERIAL_NAME, 10518a6498f2SNick Hu .pm = pm_sleep_ptr(&sifive_uart_pm_ops), 10520aaf7818SRuan Jinjie .of_match_table = sifive_serial_of_match, 105345c054d0SPaul Walmsley }, 105445c054d0SPaul Walmsley }; 105545c054d0SPaul Walmsley 105645c054d0SPaul Walmsley static int __init sifive_serial_init(void) 105745c054d0SPaul Walmsley { 105845c054d0SPaul Walmsley int r; 105945c054d0SPaul Walmsley 106045c054d0SPaul Walmsley r = uart_register_driver(&sifive_serial_uart_driver); 106145c054d0SPaul Walmsley if (r) 106245c054d0SPaul Walmsley goto init_out1; 106345c054d0SPaul Walmsley 106445c054d0SPaul Walmsley r = platform_driver_register(&sifive_serial_platform_driver); 106545c054d0SPaul Walmsley if (r) 106645c054d0SPaul Walmsley goto init_out2; 106745c054d0SPaul Walmsley 106845c054d0SPaul Walmsley return 0; 106945c054d0SPaul Walmsley 107045c054d0SPaul Walmsley init_out2: 107145c054d0SPaul Walmsley uart_unregister_driver(&sifive_serial_uart_driver); 107245c054d0SPaul Walmsley init_out1: 107345c054d0SPaul Walmsley return r; 107445c054d0SPaul Walmsley } 107545c054d0SPaul Walmsley 107645c054d0SPaul Walmsley static void __exit sifive_serial_exit(void) 107745c054d0SPaul Walmsley { 107845c054d0SPaul Walmsley platform_driver_unregister(&sifive_serial_platform_driver); 107945c054d0SPaul Walmsley uart_unregister_driver(&sifive_serial_uart_driver); 108045c054d0SPaul Walmsley } 108145c054d0SPaul Walmsley 108245c054d0SPaul Walmsley module_init(sifive_serial_init); 108345c054d0SPaul Walmsley module_exit(sifive_serial_exit); 108445c054d0SPaul Walmsley 108545c054d0SPaul Walmsley MODULE_DESCRIPTION("SiFive UART serial driver"); 108645c054d0SPaul Walmsley MODULE_LICENSE("GPL"); 108745c054d0SPaul Walmsley MODULE_AUTHOR("Paul Walmsley <paul@pwsan.com>"); 1088