2011-04-30 08:07:43 +04:00
/*
* Xilinx PS UART driver
*
* 2011 ( c ) Xilinx Inc .
*
* This program is free software ; you can redistribute it
* and / or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation ;
* either version 2 of the License , or ( at your option ) any
* later version .
*
*/
# include <linux/platform_device.h>
2011-09-01 18:20:57 +04:00
# include <linux/serial.h>
2011-04-30 08:07:43 +04:00
# include <linux/serial_core.h>
2011-09-01 18:20:57 +04:00
# include <linux/tty.h>
# include <linux/tty_flip.h>
2011-04-30 08:07:43 +04:00
# include <linux/console.h>
2013-01-21 22:57:41 +04:00
# include <linux/clk.h>
2011-04-30 08:07:43 +04:00
# include <linux/irq.h>
# include <linux/io.h>
# include <linux/of.h>
2011-05-28 00:14:23 +04:00
# include <linux/module.h>
2011-04-30 08:07:43 +04:00
# define XUARTPS_TTY_NAME "ttyPS"
# define XUARTPS_NAME "xuartps"
# define XUARTPS_MAJOR 0 /* use dynamic node allocation */
# define XUARTPS_MINOR 0 /* works best with devtmpfs */
# define XUARTPS_NR_PORTS 2
# define XUARTPS_FIFO_SIZE 16 /* FIFO size */
# define XUARTPS_REGISTER_SPACE 0xFFF
# define xuartps_readl(offset) ioread32(port->membase + offset)
# define xuartps_writel(val, offset) iowrite32(val, port->membase + offset)
/********************************Register Map********************************/
/** UART
*
* Register offsets for the UART .
*
*/
# define XUARTPS_CR_OFFSET 0x00 /* Control Register [8:0] */
# define XUARTPS_MR_OFFSET 0x04 /* Mode Register [10:0] */
# define XUARTPS_IER_OFFSET 0x08 /* Interrupt Enable [10:0] */
# define XUARTPS_IDR_OFFSET 0x0C /* Interrupt Disable [10:0] */
# define XUARTPS_IMR_OFFSET 0x10 /* Interrupt Mask [10:0] */
# define XUARTPS_ISR_OFFSET 0x14 /* Interrupt Status [10:0]*/
# define XUARTPS_BAUDGEN_OFFSET 0x18 /* Baud Rate Generator [15:0] */
# define XUARTPS_RXTOUT_OFFSET 0x1C /* RX Timeout [7:0] */
# define XUARTPS_RXWM_OFFSET 0x20 /* RX FIFO Trigger Level [5:0] */
# define XUARTPS_MODEMCR_OFFSET 0x24 /* Modem Control [5:0] */
# define XUARTPS_MODEMSR_OFFSET 0x28 /* Modem Status [8:0] */
# define XUARTPS_SR_OFFSET 0x2C /* Channel Status [11:0] */
# define XUARTPS_FIFO_OFFSET 0x30 /* FIFO [15:0] or [7:0] */
# define XUARTPS_BAUDDIV_OFFSET 0x34 /* Baud Rate Divider [7:0] */
# define XUARTPS_FLOWDEL_OFFSET 0x38 /* Flow Delay [15:0] */
# define XUARTPS_IRRX_PWIDTH_OFFSET 0x3C / * IR Minimum Received Pulse
Width [ 15 : 0 ] */
# define XUARTPS_IRTX_PWIDTH_OFFSET 0x40 / * IR Transmitted pulse
Width [ 7 : 0 ] */
# define XUARTPS_TXWM_OFFSET 0x44 /* TX FIFO Trigger Level [5:0] */
/** Control Register
*
* The Control register ( CR ) controls the major functions of the device .
*
* Control Register Bit Definitions
*/
# define XUARTPS_CR_STOPBRK 0x00000100 /* Stop TX break */
# define XUARTPS_CR_STARTBRK 0x00000080 /* Set TX break */
# define XUARTPS_CR_TX_DIS 0x00000020 /* TX disabled. */
# define XUARTPS_CR_TX_EN 0x00000010 /* TX enabled */
# define XUARTPS_CR_RX_DIS 0x00000008 /* RX disabled. */
# define XUARTPS_CR_RX_EN 0x00000004 /* RX enabled */
# define XUARTPS_CR_TXRST 0x00000002 /* TX logic reset */
# define XUARTPS_CR_RXRST 0x00000001 /* RX logic reset */
# define XUARTPS_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
/** 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 .
*
* Mode Register Bit Definitions
*
*/
# define XUARTPS_MR_CLKSEL 0x00000001 /* Pre-scalar selection */
# define XUARTPS_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */
# define XUARTPS_MR_CHMODE_NORM 0x00000000 /* Normal mode */
# define XUARTPS_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */
# define XUARTPS_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */
# define XUARTPS_MR_PARITY_NONE 0x00000020 /* No parity mode */
# define XUARTPS_MR_PARITY_MARK 0x00000018 /* Mark parity mode */
# define XUARTPS_MR_PARITY_SPACE 0x00000010 /* Space parity mode */
# define XUARTPS_MR_PARITY_ODD 0x00000008 /* Odd parity mode */
# define XUARTPS_MR_PARITY_EVEN 0x00000000 /* Even parity mode */
# define XUARTPS_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */
# define XUARTPS_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */
# define XUARTPS_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */
/** 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 XUARTPS_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */
# define XUARTPS_IXR_PARITY 0x00000080 /* Parity error interrupt */
# define XUARTPS_IXR_FRAMING 0x00000040 /* Framing error interrupt */
# define XUARTPS_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */
# define XUARTPS_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */
# define XUARTPS_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */
# define XUARTPS_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */
# define XUARTPS_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
# define XUARTPS_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
# define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
# define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */
/** 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 XUARTPS_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
# define XUARTPS_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
# define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */
# define XUARTPS_SR_RXTRIG 0x00000001 /* Rx Trigger */
/**
* xuartps_isr - Interrupt handler
* @ irq : Irq number
* @ dev_id : Id of the port
*
* Returns IRQHANDLED
* */
static irqreturn_t xuartps_isr ( int irq , void * dev_id )
{
struct uart_port * port = ( struct uart_port * ) dev_id ;
unsigned long flags ;
unsigned int isrstatus , numbytes ;
unsigned int data ;
char status = TTY_NORMAL ;
spin_lock_irqsave ( & port - > lock , flags ) ;
/* Read the interrupt status register to determine which
* interrupt ( s ) is / are active .
*/
isrstatus = xuartps_readl ( XUARTPS_ISR_OFFSET ) ;
/* drop byte with parity error if IGNPAR specified */
if ( isrstatus & port - > ignore_status_mask & XUARTPS_IXR_PARITY )
isrstatus & = ~ ( XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT ) ;
isrstatus & = port - > read_status_mask ;
isrstatus & = ~ port - > ignore_status_mask ;
if ( ( isrstatus & XUARTPS_IXR_TOUT ) | |
( isrstatus & XUARTPS_IXR_RXTRIG ) ) {
/* Receive Timeout Interrupt */
while ( ( xuartps_readl ( XUARTPS_SR_OFFSET ) &
XUARTPS_SR_RXEMPTY ) ! = XUARTPS_SR_RXEMPTY ) {
data = xuartps_readl ( XUARTPS_FIFO_OFFSET ) ;
port - > icount . rx + + ;
if ( isrstatus & XUARTPS_IXR_PARITY ) {
port - > icount . parity + + ;
status = TTY_PARITY ;
} else if ( isrstatus & XUARTPS_IXR_FRAMING ) {
port - > icount . frame + + ;
status = TTY_FRAME ;
} else if ( isrstatus & XUARTPS_IXR_OVERRUN )
port - > icount . overrun + + ;
2013-01-03 18:53:06 +04:00
uart_insert_char ( port , isrstatus , XUARTPS_IXR_OVERRUN ,
data , status ) ;
2011-04-30 08:07:43 +04:00
}
spin_unlock ( & port - > lock ) ;
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & port - > state - > port ) ;
2011-04-30 08:07:43 +04:00
spin_lock ( & port - > lock ) ;
}
/* Dispatch an appropriate handler */
if ( ( isrstatus & XUARTPS_IXR_TXEMPTY ) = = XUARTPS_IXR_TXEMPTY ) {
if ( uart_circ_empty ( & port - > state - > xmit ) ) {
xuartps_writel ( XUARTPS_IXR_TXEMPTY ,
XUARTPS_IDR_OFFSET ) ;
} else {
numbytes = port - > fifosize ;
/* Break if no more data available in the UART buffer */
while ( numbytes - - ) {
if ( uart_circ_empty ( & port - > state - > xmit ) )
break ;
/* Get the data from the UART circular buffer
* and write it to the xuartps ' s TX_FIFO
* register .
*/
xuartps_writel (
port - > state - > xmit . buf [ port - > state - > xmit .
tail ] , XUARTPS_FIFO_OFFSET ) ;
port - > icount . tx + + ;
/* Adjust the tail of the UART buffer and wrap
* the buffer if it reaches limit .
*/
port - > state - > xmit . tail =
( port - > state - > xmit . tail + 1 ) & \
( UART_XMIT_SIZE - 1 ) ;
}
if ( uart_circ_chars_pending (
& port - > state - > xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( port ) ;
}
}
xuartps_writel ( isrstatus , XUARTPS_ISR_OFFSET ) ;
/* be sure to release the lock and tty before leaving */
spin_unlock_irqrestore ( & port - > lock , flags ) ;
return IRQ_HANDLED ;
}
/**
* xuartps_set_baud_rate - Calculate and set the baud rate
* @ port : Handle to the uart port structure
* @ baud : Baud rate to set
*
* Returns baud rate , requested baud when possible , or actual baud when there
* was too much error
* */
static unsigned int xuartps_set_baud_rate ( struct uart_port * port ,
unsigned int baud )
{
unsigned int sel_clk ;
unsigned int calc_baud = 0 ;
unsigned int brgr_val , brdiv_val ;
unsigned int bauderror ;
/* Formula to obtain baud rate is
* baud_tx / rx rate = sel_clk / CD * ( BDIV + 1 )
* input_clk = ( Uart User Defined Clock or Apb Clock )
* depends on UCLKEN in MR Reg
* sel_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
*/
sel_clk = port - > uartclk ;
if ( xuartps_readl ( XUARTPS_MR_OFFSET ) & XUARTPS_MR_CLKSEL )
sel_clk = sel_clk / 8 ;
/* Find the best values for baud generation */
for ( brdiv_val = 4 ; brdiv_val < 255 ; brdiv_val + + ) {
brgr_val = sel_clk / ( baud * ( brdiv_val + 1 ) ) ;
if ( brgr_val < 2 | | brgr_val > 65535 )
continue ;
calc_baud = sel_clk / ( brgr_val * ( brdiv_val + 1 ) ) ;
if ( baud > calc_baud )
bauderror = baud - calc_baud ;
else
bauderror = calc_baud - baud ;
/* use the values when percent error is acceptable */
if ( ( ( bauderror * 100 ) / baud ) < 3 ) {
calc_baud = baud ;
break ;
}
}
/* Set the values for the new baud rate */
xuartps_writel ( brgr_val , XUARTPS_BAUDGEN_OFFSET ) ;
xuartps_writel ( brdiv_val , XUARTPS_BAUDDIV_OFFSET ) ;
return calc_baud ;
}
/*----------------------Uart Operations---------------------------*/
/**
* xuartps_start_tx - Start transmitting bytes
* @ port : Handle to the uart port structure
*
* */
static void xuartps_start_tx ( struct uart_port * port )
{
unsigned int status , numbytes = port - > fifosize ;
if ( uart_circ_empty ( & port - > state - > xmit ) | | uart_tx_stopped ( port ) )
return ;
status = xuartps_readl ( XUARTPS_CR_OFFSET ) ;
/* Set the TX enable bit and clear the TX disable bit to enable the
* transmitter .
*/
xuartps_writel ( ( status & ~ XUARTPS_CR_TX_DIS ) | XUARTPS_CR_TX_EN ,
XUARTPS_CR_OFFSET ) ;
while ( numbytes - - & & ( ( xuartps_readl ( XUARTPS_SR_OFFSET )
& XUARTPS_SR_TXFULL ) ) ! = XUARTPS_SR_TXFULL ) {
/* Break if no more data available in the UART buffer */
if ( uart_circ_empty ( & port - > state - > xmit ) )
break ;
/* Get the data from the UART circular buffer and
* write it to the xuartps ' s TX_FIFO register .
*/
xuartps_writel (
port - > state - > xmit . buf [ port - > state - > xmit . tail ] ,
XUARTPS_FIFO_OFFSET ) ;
port - > icount . tx + + ;
/* Adjust the tail of the UART buffer and wrap
* the buffer if it reaches limit .
*/
port - > state - > xmit . tail = ( port - > state - > xmit . tail + 1 ) &
( UART_XMIT_SIZE - 1 ) ;
}
/* Enable the TX Empty interrupt */
xuartps_writel ( XUARTPS_IXR_TXEMPTY , XUARTPS_IER_OFFSET ) ;
if ( uart_circ_chars_pending ( & port - > state - > xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( port ) ;
}
/**
* xuartps_stop_tx - Stop TX
* @ port : Handle to the uart port structure
*
* */
static void xuartps_stop_tx ( struct uart_port * port )
{
unsigned int regval ;
regval = xuartps_readl ( XUARTPS_CR_OFFSET ) ;
regval | = XUARTPS_CR_TX_DIS ;
/* Disable the transmitter */
xuartps_writel ( regval , XUARTPS_CR_OFFSET ) ;
}
/**
* xuartps_stop_rx - Stop RX
* @ port : Handle to the uart port structure
*
* */
static void xuartps_stop_rx ( struct uart_port * port )
{
unsigned int regval ;
regval = xuartps_readl ( XUARTPS_CR_OFFSET ) ;
regval | = XUARTPS_CR_RX_DIS ;
/* Disable the receiver */
xuartps_writel ( regval , XUARTPS_CR_OFFSET ) ;
}
/**
* xuartps_tx_empty - Check whether TX is empty
* @ port : Handle to the uart port structure
*
* Returns TIOCSER_TEMT on success , 0 otherwise
* */
static unsigned int xuartps_tx_empty ( struct uart_port * port )
{
unsigned int status ;
status = xuartps_readl ( XUARTPS_ISR_OFFSET ) & XUARTPS_IXR_TXEMPTY ;
return status ? TIOCSER_TEMT : 0 ;
}
/**
* xuartps_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 xuartps_break_ctl ( struct uart_port * port , int ctl )
{
unsigned int status ;
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
status = xuartps_readl ( XUARTPS_CR_OFFSET ) ;
if ( ctl = = - 1 )
xuartps_writel ( XUARTPS_CR_STARTBRK | status ,
XUARTPS_CR_OFFSET ) ;
else {
if ( ( status & XUARTPS_CR_STOPBRK ) = = 0 )
xuartps_writel ( XUARTPS_CR_STOPBRK | status ,
XUARTPS_CR_OFFSET ) ;
}
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/**
* xuartps_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 xuartps_set_termios ( struct uart_port * port ,
struct ktermios * termios , struct ktermios * old )
{
unsigned int cval = 0 ;
unsigned int baud ;
unsigned long flags ;
unsigned int ctrl_reg , mode_reg ;
spin_lock_irqsave ( & port - > lock , flags ) ;
/* Empty the receive FIFO 1st before making changes */
while ( ( xuartps_readl ( XUARTPS_SR_OFFSET ) &
XUARTPS_SR_RXEMPTY ) ! = XUARTPS_SR_RXEMPTY ) {
xuartps_readl ( XUARTPS_FIFO_OFFSET ) ;
}
/* Disable the TX and RX to set baud rate */
xuartps_writel ( xuartps_readl ( XUARTPS_CR_OFFSET ) |
( XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS ) ,
XUARTPS_CR_OFFSET ) ;
/* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */
baud = uart_get_baud_rate ( port , termios , old , 0 , 10000000 ) ;
baud = xuartps_set_baud_rate ( port , baud ) ;
if ( tty_termios_baud_rate ( termios ) )
tty_termios_encode_baud_rate ( termios , baud , baud ) ;
/*
* Update the per - port timeout .
*/
uart_update_timeout ( port , termios - > c_cflag , baud ) ;
/* Set TX/RX Reset */
xuartps_writel ( xuartps_readl ( XUARTPS_CR_OFFSET ) |
( XUARTPS_CR_TXRST | XUARTPS_CR_RXRST ) ,
XUARTPS_CR_OFFSET ) ;
ctrl_reg = xuartps_readl ( XUARTPS_CR_OFFSET ) ;
/* Clear the RX disable and TX disable bits and then set the TX enable
* bit and RX enable bit to enable the transmitter and receiver .
*/
xuartps_writel (
( ctrl_reg & ~ ( XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS ) )
| ( XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN ) ,
XUARTPS_CR_OFFSET ) ;
xuartps_writel ( 10 , XUARTPS_RXTOUT_OFFSET ) ;
port - > read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG |
XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT ;
port - > ignore_status_mask = 0 ;
if ( termios - > c_iflag & INPCK )
port - > read_status_mask | = XUARTPS_IXR_PARITY |
XUARTPS_IXR_FRAMING ;
if ( termios - > c_iflag & IGNPAR )
port - > ignore_status_mask | = XUARTPS_IXR_PARITY |
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN ;
/* ignore all characters if CREAD is not set */
if ( ( termios - > c_cflag & CREAD ) = = 0 )
port - > ignore_status_mask | = XUARTPS_IXR_RXTRIG |
XUARTPS_IXR_TOUT | XUARTPS_IXR_PARITY |
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN ;
mode_reg = xuartps_readl ( XUARTPS_MR_OFFSET ) ;
/* Handling Data Size */
switch ( termios - > c_cflag & CSIZE ) {
case CS6 :
cval | = XUARTPS_MR_CHARLEN_6_BIT ;
break ;
case CS7 :
cval | = XUARTPS_MR_CHARLEN_7_BIT ;
break ;
default :
case CS8 :
cval | = XUARTPS_MR_CHARLEN_8_BIT ;
termios - > c_cflag & = ~ CSIZE ;
termios - > c_cflag | = CS8 ;
break ;
}
/* Handling Parity and Stop Bits length */
if ( termios - > c_cflag & CSTOPB )
cval | = XUARTPS_MR_STOPMODE_2_BIT ; /* 2 STOP bits */
else
cval | = XUARTPS_MR_STOPMODE_1_BIT ; /* 1 STOP bit */
if ( termios - > c_cflag & PARENB ) {
/* Mark or Space parity */
if ( termios - > c_cflag & CMSPAR ) {
if ( termios - > c_cflag & PARODD )
cval | = XUARTPS_MR_PARITY_MARK ;
else
cval | = XUARTPS_MR_PARITY_SPACE ;
} else if ( termios - > c_cflag & PARODD )
cval | = XUARTPS_MR_PARITY_ODD ;
else
cval | = XUARTPS_MR_PARITY_EVEN ;
} else
cval | = XUARTPS_MR_PARITY_NONE ;
xuartps_writel ( cval , XUARTPS_MR_OFFSET ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/**
* xuartps_startup - Called when an application opens a xuartps port
* @ port : Handle to the uart port structure
*
* Returns 0 on success , negative error otherwise
* */
static int xuartps_startup ( struct uart_port * port )
{
unsigned int retval = 0 , status = 0 ;
retval = request_irq ( port - > irq , xuartps_isr , 0 , XUARTPS_NAME ,
( void * ) port ) ;
if ( retval )
return retval ;
/* Disable the TX and RX */
xuartps_writel ( XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS ,
XUARTPS_CR_OFFSET ) ;
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
* no break chars .
*/
xuartps_writel ( XUARTPS_CR_TXRST | XUARTPS_CR_RXRST ,
XUARTPS_CR_OFFSET ) ;
status = xuartps_readl ( XUARTPS_CR_OFFSET ) ;
/* Clear the RX disable and TX disable bits and then set the TX enable
* bit and RX enable bit to enable the transmitter and receiver .
*/
xuartps_writel ( ( status & ~ ( XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS ) )
| ( XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN |
XUARTPS_CR_STOPBRK ) , XUARTPS_CR_OFFSET ) ;
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
* no parity .
*/
xuartps_writel ( XUARTPS_MR_CHMODE_NORM | XUARTPS_MR_STOPMODE_1_BIT
| XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT ,
XUARTPS_MR_OFFSET ) ;
/* Set the RX FIFO Trigger level to 14 assuming FIFO size as 16 */
xuartps_writel ( 14 , XUARTPS_RXWM_OFFSET ) ;
/* Receive Timeout register is enabled with value of 10 */
xuartps_writel ( 10 , XUARTPS_RXTOUT_OFFSET ) ;
2013-03-22 21:49:27 +04:00
/* Clear out any pending interrupts before enabling them */
xuartps_writel ( xuartps_readl ( XUARTPS_ISR_OFFSET ) , XUARTPS_ISR_OFFSET ) ;
2011-04-30 08:07:43 +04:00
/* Set the Interrupt Registers with desired interrupts */
xuartps_writel ( XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT , XUARTPS_IER_OFFSET ) ;
return retval ;
}
/**
* xuartps_shutdown - Called when an application closes a xuartps port
* @ port : Handle to the uart port structure
*
* */
static void xuartps_shutdown ( struct uart_port * port )
{
int status ;
/* Disable interrupts */
status = xuartps_readl ( XUARTPS_IMR_OFFSET ) ;
xuartps_writel ( status , XUARTPS_IDR_OFFSET ) ;
/* Disable the TX and RX */
xuartps_writel ( XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS ,
XUARTPS_CR_OFFSET ) ;
free_irq ( port - > irq , port ) ;
}
/**
* xuartps_type - Set UART type to xuartps port
* @ port : Handle to the uart port structure
*
* Returns string on success , NULL otherwise
* */
static const char * xuartps_type ( struct uart_port * port )
{
return port - > type = = PORT_XUARTPS ? XUARTPS_NAME : NULL ;
}
/**
* xuartps_verify_port - Verify the port params
* @ port : Handle to the uart port structure
* @ ser : Handle to the structure whose members are compared
*
* Returns 0 if success otherwise - EINVAL
* */
static int xuartps_verify_port ( struct uart_port * port ,
struct serial_struct * ser )
{
if ( ser - > type ! = PORT_UNKNOWN & & ser - > type ! = PORT_XUARTPS )
return - EINVAL ;
if ( port - > irq ! = ser - > irq )
return - EINVAL ;
if ( ser - > io_type ! = UPIO_MEM )
return - EINVAL ;
if ( port - > iobase ! = ser - > port )
return - EINVAL ;
if ( ser - > hub6 ! = 0 )
return - EINVAL ;
return 0 ;
}
/**
* xuartps_request_port - Claim the memory region attached to xuartps port ,
* called when the driver adds a xuartps port via
* uart_add_one_port ( )
* @ port : Handle to the uart port structure
*
* Returns 0 , - ENOMEM if request fails
* */
static int xuartps_request_port ( struct uart_port * port )
{
if ( ! request_mem_region ( port - > mapbase , XUARTPS_REGISTER_SPACE ,
XUARTPS_NAME ) ) {
return - ENOMEM ;
}
port - > membase = ioremap ( port - > mapbase , XUARTPS_REGISTER_SPACE ) ;
if ( ! port - > membase ) {
dev_err ( port - > dev , " Unable to map registers \n " ) ;
release_mem_region ( port - > mapbase , XUARTPS_REGISTER_SPACE ) ;
return - ENOMEM ;
}
return 0 ;
}
/**
* xuartps_release_port - Release the memory region attached to a xuartps
* port , called when the driver removes a xuartps
* port via uart_remove_one_port ( ) .
* @ port : Handle to the uart port structure
*
* */
static void xuartps_release_port ( struct uart_port * port )
{
release_mem_region ( port - > mapbase , XUARTPS_REGISTER_SPACE ) ;
iounmap ( port - > membase ) ;
port - > membase = NULL ;
}
/**
* xuartps_config_port - Configure xuartps , called when the driver adds a
* xuartps port
* @ port : Handle to the uart port structure
* @ flags : If any
*
* */
static void xuartps_config_port ( struct uart_port * port , int flags )
{
if ( flags & UART_CONFIG_TYPE & & xuartps_request_port ( port ) = = 0 )
port - > type = PORT_XUARTPS ;
}
/**
* xuartps_get_mctrl - Get the modem control state
*
* @ port : Handle to the uart port structure
*
* Returns the modem control state
*
* */
static unsigned int xuartps_get_mctrl ( struct uart_port * port )
{
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR ;
}
static void xuartps_set_mctrl ( struct uart_port * port , unsigned int mctrl )
{
/* N/A */
}
static void xuartps_enable_ms ( struct uart_port * port )
{
/* N/A */
}
/** The UART operations structure
*/
static struct uart_ops xuartps_ops = {
. set_mctrl = xuartps_set_mctrl ,
. get_mctrl = xuartps_get_mctrl ,
. enable_ms = xuartps_enable_ms ,
. start_tx = xuartps_start_tx , /* Start transmitting */
. stop_tx = xuartps_stop_tx , /* Stop transmission */
. stop_rx = xuartps_stop_rx , /* Stop reception */
. tx_empty = xuartps_tx_empty , /* Transmitter busy? */
. break_ctl = xuartps_break_ctl , /* Start/stop
* transmitting break
*/
. set_termios = xuartps_set_termios , /* Set termios */
. startup = xuartps_startup , /* App opens xuartps */
. shutdown = xuartps_shutdown , /* App closes xuartps */
. type = xuartps_type , /* Set UART type */
. verify_port = xuartps_verify_port , /* Verification of port
* params
*/
. request_port = xuartps_request_port , /* Claim resources
* associated with a
* xuartps port
*/
. release_port = xuartps_release_port , /* Release resources
* associated with a
* xuartps port
*/
. config_port = xuartps_config_port , /* Configure when driver
* adds a xuartps port
*/
} ;
static struct uart_port xuartps_port [ 2 ] ;
/**
* xuartps_get_port - Configure the port from the platform device resource
* info
*
* Returns a pointer to a uart_port or NULL for failure
* */
static struct uart_port * xuartps_get_port ( void )
{
struct uart_port * port ;
int id ;
/* Find the next unused port */
for ( id = 0 ; id < XUARTPS_NR_PORTS ; id + + )
if ( xuartps_port [ id ] . mapbase = = 0 )
break ;
if ( id > = XUARTPS_NR_PORTS )
return NULL ;
port = & xuartps_port [ id ] ;
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init ( & port - > lock ) ;
port - > membase = NULL ;
port - > iobase = 1 ; /* mark port in use */
port - > irq = 0 ;
port - > type = PORT_UNKNOWN ;
port - > iotype = UPIO_MEM32 ;
port - > flags = UPF_BOOT_AUTOCONF ;
port - > ops = & xuartps_ops ;
port - > fifosize = XUARTPS_FIFO_SIZE ;
port - > line = id ;
port - > dev = NULL ;
return port ;
}
/*-----------------------Console driver operations--------------------------*/
# ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/**
* xuartps_console_wait_tx - Wait for the TX to be full
* @ port : Handle to the uart port structure
*
* */
static void xuartps_console_wait_tx ( struct uart_port * port )
{
while ( ( xuartps_readl ( XUARTPS_SR_OFFSET ) & XUARTPS_SR_TXEMPTY )
! = XUARTPS_SR_TXEMPTY )
barrier ( ) ;
}
/**
* xuartps_console_putchar - write the character to the FIFO buffer
* @ port : Handle to the uart port structure
* @ ch : Character to be written
*
* */
static void xuartps_console_putchar ( struct uart_port * port , int ch )
{
xuartps_console_wait_tx ( port ) ;
xuartps_writel ( ch , XUARTPS_FIFO_OFFSET ) ;
}
/**
* xuartps_console_write - perform write operation
* @ port : Handle to the uart port structure
* @ s : Pointer to character array
* @ count : No of characters
* */
static void xuartps_console_write ( struct console * co , const char * s ,
unsigned int count )
{
struct uart_port * port = & xuartps_port [ co - > index ] ;
unsigned long flags ;
unsigned int imr ;
int locked = 1 ;
if ( oops_in_progress )
locked = spin_trylock_irqsave ( & port - > lock , flags ) ;
else
spin_lock_irqsave ( & port - > lock , flags ) ;
/* save and disable interrupt */
imr = xuartps_readl ( XUARTPS_IMR_OFFSET ) ;
xuartps_writel ( imr , XUARTPS_IDR_OFFSET ) ;
uart_console_write ( port , s , count , xuartps_console_putchar ) ;
xuartps_console_wait_tx ( port ) ;
/* restore interrupt state, it seems like there may be a h/w bug
* in that the interrupt enable register should not need to be
* written based on the data sheet
*/
xuartps_writel ( ~ imr , XUARTPS_IDR_OFFSET ) ;
xuartps_writel ( imr , XUARTPS_IER_OFFSET ) ;
if ( locked )
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/**
* xuartps_console_setup - Initialize the uart to default config
* @ co : Console handle
* @ options : Initial settings of uart
*
* Returns 0 , - ENODEV if no device
* */
static int __init xuartps_console_setup ( struct console * co , char * options )
{
struct uart_port * port = & xuartps_port [ co - > index ] ;
int baud = 9600 ;
int bits = 8 ;
int parity = ' n ' ;
int flow = ' n ' ;
if ( co - > index < 0 | | co - > index > = XUARTPS_NR_PORTS )
return - EINVAL ;
if ( ! port - > mapbase ) {
pr_debug ( " console on ttyPS%i not present \n " , co - > index ) ;
return - ENODEV ;
}
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
return uart_set_options ( port , co , baud , parity , bits , flow ) ;
}
static struct uart_driver xuartps_uart_driver ;
static struct console xuartps_console = {
. name = XUARTPS_TTY_NAME ,
. write = xuartps_console_write ,
. device = uart_console_device ,
. setup = xuartps_console_setup ,
. flags = CON_PRINTBUFFER ,
. index = - 1 , /* Specified on the cmdline (e.g. console=ttyPS ) */
. data = & xuartps_uart_driver ,
} ;
/**
* xuartps_console_init - Initialization call
*
* Returns 0 on success , negative error otherwise
* */
static int __init xuartps_console_init ( void )
{
register_console ( & xuartps_console ) ;
return 0 ;
}
console_initcall ( xuartps_console_init ) ;
# endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
/** Structure Definitions
*/
static struct uart_driver xuartps_uart_driver = {
. owner = THIS_MODULE , /* Owner */
. driver_name = XUARTPS_NAME , /* Driver name */
. dev_name = XUARTPS_TTY_NAME , /* Node name */
. major = XUARTPS_MAJOR , /* Major number */
. minor = XUARTPS_MINOR , /* Minor number */
. nr = XUARTPS_NR_PORTS , /* Number of UART ports */
# ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
. cons = & xuartps_console , /* Console */
# endif
} ;
/* ---------------------------------------------------------------------
* Platform bus binding
*/
/**
* xuartps_probe - Platform driver probe
* @ pdev : Pointer to the platform device structure
*
* Returns 0 on success , negative error otherwise
* */
2012-11-19 22:21:50 +04:00
static int xuartps_probe ( struct platform_device * pdev )
2011-04-30 08:07:43 +04:00
{
int rc ;
struct uart_port * port ;
struct resource * res , * res2 ;
2013-01-21 22:57:41 +04:00
struct clk * clk ;
2011-04-30 08:07:43 +04:00
2013-01-21 22:57:41 +04:00
clk = of_clk_get ( pdev - > dev . of_node , 0 ) ;
if ( IS_ERR ( clk ) ) {
2011-04-30 08:07:43 +04:00
dev_err ( & pdev - > dev , " no clock specified \n " ) ;
2013-01-21 22:57:41 +04:00
return PTR_ERR ( clk ) ;
}
rc = clk_prepare_enable ( clk ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " could not enable clock \n " ) ;
return - EBUSY ;
2011-04-30 08:07:43 +04:00
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - ENODEV ;
res2 = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
if ( ! res2 )
return - ENODEV ;
/* Initialize the port structure */
port = xuartps_get_port ( ) ;
if ( ! port ) {
dev_err ( & pdev - > dev , " Cannot get uart_port structure \n " ) ;
return - ENODEV ;
} else {
/* Register the port.
* This function also registers this device with the tty layer
* and triggers invocation of the config_port ( ) entry point .
*/
port - > mapbase = res - > start ;
port - > irq = res2 - > start ;
port - > dev = & pdev - > dev ;
2013-01-21 22:57:41 +04:00
port - > uartclk = clk_get_rate ( clk ) ;
port - > private_data = clk ;
2011-04-30 08:07:43 +04:00
dev_set_drvdata ( & pdev - > dev , port ) ;
rc = uart_add_one_port ( & xuartps_uart_driver , port ) ;
if ( rc ) {
dev_err ( & pdev - > dev ,
" uart_add_one_port() failed; err=%i \n " , rc ) ;
dev_set_drvdata ( & pdev - > dev , NULL ) ;
return rc ;
}
return 0 ;
}
}
/**
* xuartps_remove - called when the platform driver is unregistered
* @ pdev : Pointer to the platform device structure
*
* Returns 0 on success , negative error otherwise
* */
2012-11-19 22:26:18 +04:00
static int xuartps_remove ( struct platform_device * pdev )
2011-04-30 08:07:43 +04:00
{
struct uart_port * port = dev_get_drvdata ( & pdev - > dev ) ;
2013-01-21 22:57:41 +04:00
struct clk * clk = port - > private_data ;
int rc ;
2011-04-30 08:07:43 +04:00
/* Remove the xuartps port from the serial core */
2013-01-21 22:57:41 +04:00
rc = uart_remove_one_port ( & xuartps_uart_driver , port ) ;
dev_set_drvdata ( & pdev - > dev , NULL ) ;
port - > mapbase = 0 ;
clk_disable_unprepare ( clk ) ;
2011-04-30 08:07:43 +04:00
return rc ;
}
/**
* xuartps_suspend - suspend event
* @ pdev : Pointer to the platform device structure
* @ state : State of the device
*
* Returns 0
* */
static int xuartps_suspend ( struct platform_device * pdev , pm_message_t state )
{
/* Call the API provided in serial_core.c file which handles
* the suspend .
*/
uart_suspend_port ( & xuartps_uart_driver , & xuartps_port [ pdev - > id ] ) ;
return 0 ;
}
/**
* xuartps_resume - Resume after a previous suspend
* @ pdev : Pointer to the platform device structure
*
* Returns 0
* */
static int xuartps_resume ( struct platform_device * pdev )
{
uart_resume_port ( & xuartps_uart_driver , & xuartps_port [ pdev - > id ] ) ;
return 0 ;
}
/* Match table for of_platform binding */
2012-11-19 22:24:32 +04:00
static struct of_device_id xuartps_of_match [ ] = {
2011-04-30 08:07:43 +04:00
{ . compatible = " xlnx,xuartps " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , xuartps_of_match ) ;
static struct platform_driver xuartps_platform_driver = {
. probe = xuartps_probe , /* Probe method */
2013-01-22 16:11:11 +04:00
. remove = xuartps_remove , /* Detach method */
2011-04-30 08:07:43 +04:00
. suspend = xuartps_suspend , /* Suspend */
. resume = xuartps_resume , /* Resume after a suspend */
. driver = {
. owner = THIS_MODULE ,
. name = XUARTPS_NAME , /* Driver name */
. of_match_table = xuartps_of_match ,
} ,
} ;
/* ---------------------------------------------------------------------
* Module Init and Exit
*/
/**
* xuartps_init - Initial driver registration call
*
* Returns whether the registration was successful or not
* */
static int __init xuartps_init ( void )
{
int retval = 0 ;
/* Register the xuartps driver with the serial core */
retval = uart_register_driver ( & xuartps_uart_driver ) ;
if ( retval )
return retval ;
/* Register the platform driver */
retval = platform_driver_register ( & xuartps_platform_driver ) ;
if ( retval )
uart_unregister_driver ( & xuartps_uart_driver ) ;
return retval ;
}
/**
* xuartps_exit - Driver unregistration call
* */
static void __exit xuartps_exit ( void )
{
/* The order of unregistration is important. Unregister the
* UART driver before the platform driver crashes the system .
*/
/* Unregister the platform driver */
platform_driver_unregister ( & xuartps_platform_driver ) ;
/* Unregister the xuartps driver */
uart_unregister_driver ( & xuartps_uart_driver ) ;
}
module_init ( xuartps_init ) ;
module_exit ( xuartps_exit ) ;
MODULE_DESCRIPTION ( " Driver for PS UART " ) ;
MODULE_AUTHOR ( " Xilinx Inc. " ) ;
MODULE_LICENSE ( " GPL " ) ;