linux/drivers/tty/serial/xilinx_uartps.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Cadence UART driver (found in Xilinx Zynq)
 *
 * Copyright (c) 2011 - 2014 Xilinx, Inc.
 *
 * This driver has originally been pushed by Xilinx using a Zynq-branding. This
 * still shows in the naming of this file, the kconfig symbols and some symbols
 * in the code.
 */

#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/reset.h>

#define CDNS_UART_TTY_NAME
#define CDNS_UART_NAME
#define CDNS_UART_MAJOR
#define CDNS_UART_MINOR
#define CDNS_UART_NR_PORTS
#define CDNS_UART_FIFO_SIZE
#define CDNS_UART_REGISTER_SPACE
#define TX_TIMEOUT

/* Rx Trigger level */
static int rx_trigger_level =;
module_param(rx_trigger_level, uint, 0444);
MODULE_PARM_DESC();

/* Rx Timeout */
static int rx_timeout =;
module_param(rx_timeout, uint, 0444);
MODULE_PARM_DESC();

/* Register offsets for the UART. */
#define CDNS_UART_CR
#define CDNS_UART_MR
#define CDNS_UART_IER
#define CDNS_UART_IDR
#define CDNS_UART_IMR
#define CDNS_UART_ISR
#define CDNS_UART_BAUDGEN
#define CDNS_UART_RXTOUT
#define CDNS_UART_RXWM
#define CDNS_UART_MODEMCR
#define CDNS_UART_MODEMSR
#define CDNS_UART_SR
#define CDNS_UART_FIFO
#define CDNS_UART_BAUDDIV
#define CDNS_UART_FLOWDEL
#define CDNS_UART_IRRX_PWIDTH
#define CDNS_UART_IRTX_PWIDTH
#define CDNS_UART_TXWM
#define CDNS_UART_RXBS

/* Control Register Bit Definitions */
#define CDNS_UART_CR_STOPBRK
#define CDNS_UART_CR_STARTBRK
#define CDNS_UART_CR_TX_DIS
#define CDNS_UART_CR_TX_EN
#define CDNS_UART_CR_RX_DIS
#define CDNS_UART_CR_RX_EN
#define CDNS_UART_CR_TXRST
#define CDNS_UART_CR_RXRST
#define CDNS_UART_CR_RST_TO
#define CDNS_UART_RXBS_PARITY
#define CDNS_UART_RXBS_FRAMING
#define CDNS_UART_RXBS_BRK

/*
 * Mode Register:
 * The mode register (MR) defines the mode of transfer as well as the data
 * format. If this register is modified during transmission or reception,
 * data validity cannot be guaranteed.
 */
#define CDNS_UART_MR_CLKSEL
#define CDNS_UART_MR_CHMODE_L_LOOP
#define CDNS_UART_MR_CHMODE_NORM
#define CDNS_UART_MR_CHMODE_MASK

#define CDNS_UART_MR_STOPMODE_2_BIT
#define CDNS_UART_MR_STOPMODE_1_BIT

#define CDNS_UART_MR_PARITY_NONE
#define CDNS_UART_MR_PARITY_MARK
#define CDNS_UART_MR_PARITY_SPACE
#define CDNS_UART_MR_PARITY_ODD
#define CDNS_UART_MR_PARITY_EVEN

#define CDNS_UART_MR_CHARLEN_6_BIT
#define CDNS_UART_MR_CHARLEN_7_BIT
#define CDNS_UART_MR_CHARLEN_8_BIT

/*
 * Interrupt Registers:
 * Interrupt control logic uses the interrupt enable register (IER) and the
 * interrupt disable register (IDR) to set the value of the bits in the
 * interrupt mask register (IMR). The IMR determines whether to pass an
 * interrupt to the interrupt status register (ISR).
 * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an
 * interrupt. IMR and ISR are read only, and IER and IDR are write only.
 * Reading either IER or IDR returns 0x00.
 * All four registers have the same bit definitions.
 */
#define CDNS_UART_IXR_TOUT
#define CDNS_UART_IXR_PARITY
#define CDNS_UART_IXR_FRAMING
#define CDNS_UART_IXR_OVERRUN
#define CDNS_UART_IXR_TXFULL
#define CDNS_UART_IXR_TXEMPTY
#define CDNS_UART_ISR_RXEMPTY
#define CDNS_UART_IXR_RXTRIG
#define CDNS_UART_IXR_RXFULL
#define CDNS_UART_IXR_RXEMPTY
#define CDNS_UART_IXR_RXMASK

	/*
	 * Do not enable parity error interrupt for the following
	 * reason: When parity error interrupt is enabled, each Rx
	 * parity error always results in 2 events. The first one
	 * being parity error interrupt and the second one with a
	 * proper Rx interrupt with the incoming data.  Disabling
	 * parity error interrupt ensures better handling of parity
	 * error events. With this change, for a parity error case, we
	 * get a Rx interrupt with parity error set in ISR register
	 * and we still handle parity errors in the desired way.
	 */

#define CDNS_UART_RX_IRQS

/* Goes in read_status_mask for break detection as the HW doesn't do it*/
#define CDNS_UART_IXR_BRK

#define CDNS_UART_RXBS_SUPPORT
/*
 * Modem Control register:
 * The read/write Modem Control register controls the interface with the modem
 * or data set, or a peripheral device emulating a modem.
 */
#define CDNS_UART_MODEMCR_FCM
#define CDNS_UART_MODEMCR_RTS
#define CDNS_UART_MODEMCR_DTR

/*
 * Modem Status register:
 * The read/write Modem Status register reports the interface with the modem
 * or data set, or a peripheral device emulating a modem.
 */
#define CDNS_UART_MODEMSR_DCD
#define CDNS_UART_MODEMSR_RI
#define CDNS_UART_MODEMSR_DSR
#define CDNS_UART_MODEMSR_CTS

/*
 * Channel Status Register:
 * The channel status register (CSR) is provided to enable the control logic
 * to monitor the status of bits in the channel interrupt status register,
 * even if these are masked out by the interrupt mask register.
 */
#define CDNS_UART_SR_RXEMPTY
#define CDNS_UART_SR_TXEMPTY
#define CDNS_UART_SR_TXFULL
#define CDNS_UART_SR_RXTRIG
#define CDNS_UART_SR_TACTIVE

/* baud dividers min/max values */
#define CDNS_UART_BDIV_MIN
#define CDNS_UART_BDIV_MAX
#define CDNS_UART_CD_MAX
#define UART_AUTOSUSPEND_TIMEOUT

/**
 * struct cdns_uart - device data
 * @port:		Pointer to the UART port
 * @uartclk:		Reference clock
 * @pclk:		APB clock
 * @cdns_uart_driver:	Pointer to UART driver
 * @baud:		Current baud rate
 * @clk_rate_change_nb:	Notifier block for clock changes
 * @quirks:		Flags for RXBS support.
 * @cts_override:	Modem control state override
 * @gpiod_rts:		Pointer to the gpio descriptor
 * @rs485_tx_started:	RS485 tx state
 * @tx_timer:		Timer for tx
 * @rstc:		Pointer to the reset control
 */
struct cdns_uart {};
struct cdns_platform_data {};

struct serial_rs485 cdns_rs485_supported =;

#define to_cdns_uart(_nb)

/**
 * cdns_uart_handle_rx - Handle the received bytes along with Rx errors.
 * @dev_id: Id of the UART port
 * @isrstatus: The interrupt status register value as read
 * Return: None
 */
static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
{}

/**
 * cdns_rts_gpio_enable - Configure RTS/GPIO to high/low
 * @cdns_uart: Handle to the cdns_uart
 * @enable: Value to be set to RTS/GPIO
 */
static void cdns_rts_gpio_enable(struct cdns_uart *cdns_uart, bool enable)
{}

/**
 * cdns_rs485_tx_setup - Tx setup specific to rs485
 * @cdns_uart: Handle to the cdns_uart
 */
static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart)
{}

/**
 * cdns_rs485_rx_setup - Rx setup specific to rs485
 * @cdns_uart: Handle to the cdns_uart
 */
static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart)
{}

/**
 * cdns_uart_tx_empty -  Check whether TX is empty
 * @port: Handle to the uart port structure
 *
 * Return: TIOCSER_TEMT on success, 0 otherwise
 */
static unsigned int cdns_uart_tx_empty(struct uart_port *port)
{}

/**
 * cdns_rs485_rx_callback - Timer rx callback handler for rs485.
 * @t: Handle to the hrtimer structure
 */
static enum hrtimer_restart cdns_rs485_rx_callback(struct hrtimer *t)
{}

/**
 * cdns_calc_after_tx_delay - calculate delay required for after tx.
 * @cdns_uart: Handle to the cdns_uart
 */
static u64 cdns_calc_after_tx_delay(struct cdns_uart *cdns_uart)
{}

/**
 * cdns_uart_handle_tx - Handle the bytes to be transmitted.
 * @dev_id: Id of the UART port
 * Return: None
 */
static void cdns_uart_handle_tx(void *dev_id)
{}

/**
 * cdns_uart_isr - Interrupt handler
 * @irq: Irq number
 * @dev_id: Id of the port
 *
 * Return: IRQHANDLED
 */
static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
{}

/**
 * cdns_uart_calc_baud_divs - Calculate baud rate divisors
 * @clk: UART module input clock
 * @baud: Desired baud rate
 * @rbdiv: BDIV value (return value)
 * @rcd: CD value (return value)
 * @div8: Value for clk_sel bit in mod (return value)
 * Return: baud rate, requested baud when possible, or actual baud when there
 *	was too much error, zero if no valid divisors are found.
 *
 * Formula to obtain baud rate is
 *	baud_tx/rx rate = clk/CD * (BDIV + 1)
 *	input_clk = (Uart User Defined Clock or Apb Clock)
 *		depends on UCLKEN in MR Reg
 *	clk = input_clk or input_clk/8;
 *		depends on CLKS in MR reg
 *	CD and BDIV depends on values in
 *			baud rate generate register
 *			baud rate clock divisor register
 */
static unsigned int cdns_uart_calc_baud_divs(unsigned int clk,
		unsigned int baud, u32 *rbdiv, u32 *rcd, int *div8)
{}

/**
 * cdns_uart_set_baud_rate - Calculate and set the baud rate
 * @port: Handle to the uart port structure
 * @baud: Baud rate to set
 * Return: baud rate, requested baud when possible, or actual baud when there
 *	   was too much error, zero if no valid divisors are found.
 */
static unsigned int cdns_uart_set_baud_rate(struct uart_port *port,
		unsigned int baud)
{}

#ifdef CONFIG_COMMON_CLK
/**
 * cdns_uart_clk_notifier_cb - Clock notifier callback
 * @nb:		Notifier block
 * @event:	Notify event
 * @data:	Notifier data
 * Return:	NOTIFY_OK or NOTIFY_DONE on success, NOTIFY_BAD on error.
 */
static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
		unsigned long event, void *data)
{}
#endif

/**
 * cdns_rs485_tx_callback - Timer tx callback handler for rs485.
 * @t: Handle to the hrtimer structure
 */
static enum hrtimer_restart cdns_rs485_tx_callback(struct hrtimer *t)
{}

/**
 * cdns_uart_start_tx -  Start transmitting bytes
 * @port: Handle to the uart port structure
 */
static void cdns_uart_start_tx(struct uart_port *port)
{}

/**
 * cdns_uart_stop_tx - Stop TX
 * @port: Handle to the uart port structure
 */
static void cdns_uart_stop_tx(struct uart_port *port)
{}

/**
 * cdns_uart_stop_rx - Stop RX
 * @port: Handle to the uart port structure
 */
static void cdns_uart_stop_rx(struct uart_port *port)
{}

/**
 * cdns_uart_break_ctl - Based on the input ctl we have to start or stop
 *			transmitting char breaks
 * @port: Handle to the uart port structure
 * @ctl: Value based on which start or stop decision is taken
 */
static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
{}

/**
 * cdns_uart_set_termios - termios operations, handling data length, parity,
 *				stop bits, flow control, baud rate
 * @port: Handle to the uart port structure
 * @termios: Handle to the input termios structure
 * @old: Values of the previously saved termios structure
 */
static void cdns_uart_set_termios(struct uart_port *port,
				  struct ktermios *termios,
				  const struct ktermios *old)
{}

/**
 * cdns_uart_startup - Called when an application opens a cdns_uart port
 * @port: Handle to the uart port structure
 *
 * Return: 0 on success, negative errno otherwise
 */
static int cdns_uart_startup(struct uart_port *port)
{}

/**
 * cdns_uart_shutdown - Called when an application closes a cdns_uart port
 * @port: Handle to the uart port structure
 */
static void cdns_uart_shutdown(struct uart_port *port)
{}

/**
 * cdns_uart_type - Set UART type to cdns_uart port
 * @port: Handle to the uart port structure
 *
 * Return: string on success, NULL otherwise
 */
static const char *cdns_uart_type(struct uart_port *port)
{}

/**
 * cdns_uart_verify_port - Verify the port params
 * @port: Handle to the uart port structure
 * @ser: Handle to the structure whose members are compared
 *
 * Return: 0 on success, negative errno otherwise.
 */
static int cdns_uart_verify_port(struct uart_port *port,
					struct serial_struct *ser)
{}

/**
 * cdns_uart_request_port - Claim the memory region attached to cdns_uart port,
 *				called when the driver adds a cdns_uart port via
 *				uart_add_one_port()
 * @port: Handle to the uart port structure
 *
 * Return: 0 on success, negative errno otherwise.
 */
static int cdns_uart_request_port(struct uart_port *port)
{}

/**
 * cdns_uart_release_port - Release UART port
 * @port: Handle to the uart port structure
 *
 * Release the memory region attached to a cdns_uart port. Called when the
 * driver removes a cdns_uart port via uart_remove_one_port().
 */
static void cdns_uart_release_port(struct uart_port *port)
{}

/**
 * cdns_uart_config_port - Configure UART port
 * @port: Handle to the uart port structure
 * @flags: If any
 */
static void cdns_uart_config_port(struct uart_port *port, int flags)
{}

/**
 * cdns_uart_get_mctrl - Get the modem control state
 * @port: Handle to the uart port structure
 *
 * Return: the modem control state
 */
static unsigned int cdns_uart_get_mctrl(struct uart_port *port)
{}

static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{}

#ifdef CONFIG_CONSOLE_POLL
static int cdns_uart_poll_get_char(struct uart_port *port)
{}

static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
{}
#endif

static void cdns_uart_pm(struct uart_port *port, unsigned int state,
		   unsigned int oldstate)
{}

static const struct uart_ops cdns_uart_ops =;

static struct uart_driver cdns_uart_uart_driver;

#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/**
 * cdns_uart_console_putchar - write the character to the FIFO buffer
 * @port: Handle to the uart port structure
 * @ch: Character to be written
 */
static void cdns_uart_console_putchar(struct uart_port *port, unsigned char ch)
{}

static void cdns_early_write(struct console *con, const char *s,
				    unsigned int n)
{}

static int __init cdns_early_console_setup(struct earlycon_device *device,
					   const char *opt)
{}
OF_EARLYCON_DECLARE();
OF_EARLYCON_DECLARE();
OF_EARLYCON_DECLARE();
OF_EARLYCON_DECLARE();


/* Static pointer to console port */
static struct uart_port *console_port;

/**
 * cdns_uart_console_write - perform write operation
 * @co: Console handle
 * @s: Pointer to character array
 * @count: No of characters
 */
static void cdns_uart_console_write(struct console *co, const char *s,
				unsigned int count)
{}

/**
 * cdns_uart_console_setup - Initialize the uart to default config
 * @co: Console handle
 * @options: Initial settings of uart
 *
 * Return: 0 on success, negative errno otherwise.
 */
static int cdns_uart_console_setup(struct console *co, char *options)
{}

static struct console cdns_uart_console =;
#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */

#ifdef CONFIG_PM_SLEEP
/**
 * cdns_uart_suspend - suspend event
 * @device: Pointer to the device structure
 *
 * Return: 0
 */
static int cdns_uart_suspend(struct device *device)
{}

/**
 * cdns_uart_resume - Resume after a previous suspend
 * @device: Pointer to the device structure
 *
 * Return: 0
 */
static int cdns_uart_resume(struct device *device)
{}
#endif /* ! CONFIG_PM_SLEEP */
static int __maybe_unused cdns_runtime_suspend(struct device *dev)
{
	struct uart_port *port = dev_get_drvdata(dev);
	struct cdns_uart *cdns_uart = port->private_data;

	clk_disable(cdns_uart->uartclk);
	clk_disable(cdns_uart->pclk);
	return 0;
};

static int __maybe_unused cdns_runtime_resume(struct device *dev)
{
	struct uart_port *port = dev_get_drvdata(dev);
	struct cdns_uart *cdns_uart = port->private_data;
	int ret;

	ret = clk_enable(cdns_uart->pclk);
	if (ret)
		return ret;

	ret = clk_enable(cdns_uart->uartclk);
	if (ret) {
		clk_disable(cdns_uart->pclk);
		return ret;
	}
	return 0;
};

static const struct dev_pm_ops cdns_uart_dev_pm_ops =;

static const struct cdns_platform_data zynqmp_uart_def =;

/* Match table for of_platform binding */
static const struct of_device_id cdns_uart_of_match[] =;
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);

/* Temporary variable for storing number of instances */
static int instances;

/**
 * cdns_rs485_config - Called when an application calls TIOCSRS485 ioctl.
 * @port: Pointer to the uart_port structure
 * @termios: Pointer to the ktermios structure
 * @rs485: Pointer to the serial_rs485 structure
 *
 * Return: 0
 */
static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
			     struct serial_rs485 *rs485)
{}

/**
 * cdns_uart_probe - Platform driver probe
 * @pdev: Pointer to the platform device structure
 *
 * Return: 0 on success, negative errno otherwise
 */
static int cdns_uart_probe(struct platform_device *pdev)
{}

/**
 * cdns_uart_remove - called when the platform driver is unregistered
 * @pdev: Pointer to the platform device structure
 */
static void cdns_uart_remove(struct platform_device *pdev)
{}

static struct platform_driver cdns_uart_platform_driver =;

static int __init cdns_uart_init(void)
{}

static void __exit cdns_uart_exit(void)
{}

arch_initcall(cdns_uart_init);
module_exit(cdns_uart_exit);

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();