2012-10-27 11:17:12 +04:00
/*
* ARC On - Chip ( fpga ) UART Driver
*
* Copyright ( C ) 2010 - 2012 Synopsys , Inc . ( www . synopsys . com )
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* vineetg : July 10 th 2012
* - Decoupled the driver from arch / arc
* + Using platform_get_resource ( ) for irq / membase ( thx to bfin_uart . c )
* + Using early_platform_xxx ( ) for early console ( thx to mach - shmobile / xxx )
*
* Vineetg : Aug 21 st 2010
* - Is uart_tx_stopped ( ) not done in tty write path as it has already been
* taken care of , in serial core
*
* Vineetg : Aug 18 th 2010
* - New Serial Core based ARC UART driver
* - Derived largely from blackfin driver albiet with some major tweaks
*
* TODO :
* - check if sysreq works
*/
# if defined(CONFIG_SERIAL_ARC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
# define SUPPORT_SYSRQ
# endif
# include <linux/module.h>
# include <linux/serial.h>
# include <linux/console.h>
# include <linux/sysrq.h>
# include <linux/platform_device.h>
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/serial_core.h>
# include <linux/io.h>
2013-01-11 10:20:23 +04:00
# include <linux/of.h>
# include <linux/of_platform.h>
2012-10-27 11:17:12 +04:00
/*************************************
* ARC UART Hardware Specs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define ARC_UART_TX_FIFO_SIZE 1
/*
* UART Register set ( this is not a Standards Compliant IP )
* Also each reg is Word aligned , but only 8 bits wide
*/
# define R_ID0 0
# define R_ID1 4
# define R_ID2 8
# define R_ID3 12
# define R_DATA 16
# define R_STS 20
# define R_BAUDL 24
# define R_BAUDH 28
/* Bits for UART Status Reg (R/W) */
# define RXIENB 0x04 /* Receive Interrupt Enable */
# define TXIENB 0x40 /* Transmit Interrupt Enable */
# define RXEMPTY 0x20 /* Receive FIFO Empty: No char receivede */
# define TXEMPTY 0x80 /* Transmit FIFO Empty, thus char can be written into */
# define RXFULL 0x08 /* Receive FIFO full */
# define RXFULL1 0x10 /* Receive FIFO has space for 1 char (tot space=4) */
# define RXFERR 0x01 /* Frame Error: Stop Bit not detected */
# define RXOERR 0x02 /* OverFlow Err: Char recv but RXFULL still set */
/* Uart bit fiddling helpers: lowest level */
# define RBASE(uart, reg) (uart->port.membase + reg)
# define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r))
# define UART_REG_GET(u, r) readb(RBASE(u, r))
# define UART_REG_OR(u, r, v) UART_REG_SET(u, r, UART_REG_GET(u, r) | (v))
# define UART_REG_CLR(u, r, v) UART_REG_SET(u, r, UART_REG_GET(u, r) & ~(v))
/* Uart bit fiddling helpers: API level */
# define UART_SET_DATA(uart, val) UART_REG_SET(uart, R_DATA, val)
# define UART_GET_DATA(uart) UART_REG_GET(uart, R_DATA)
# define UART_SET_BAUDH(uart, val) UART_REG_SET(uart, R_BAUDH, val)
# define UART_SET_BAUDL(uart, val) UART_REG_SET(uart, R_BAUDL, val)
# define UART_CLR_STATUS(uart, val) UART_REG_CLR(uart, R_STS, val)
# define UART_GET_STATUS(uart) UART_REG_GET(uart, R_STS)
# define UART_ALL_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, RXIENB|TXIENB)
# define UART_RX_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, RXIENB)
# define UART_TX_IRQ_DISABLE(uart) UART_REG_CLR(uart, R_STS, TXIENB)
# define UART_ALL_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, RXIENB|TXIENB)
# define UART_RX_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, RXIENB)
# define UART_TX_IRQ_ENABLE(uart) UART_REG_OR(uart, R_STS, TXIENB)
# define ARC_SERIAL_DEV_NAME "ttyARC"
struct arc_uart_port {
struct uart_port port ;
unsigned long baud ;
int is_emulated ; /* H/w vs. Instruction Set Simulator */
} ;
# define to_arc_port(uport) container_of(uport, struct arc_uart_port, port)
static struct arc_uart_port arc_uart_ports [ CONFIG_SERIAL_ARC_NR_PORTS ] ;
# ifdef CONFIG_SERIAL_ARC_CONSOLE
static struct console arc_console ;
# endif
# define DRIVER_NAME "arc-uart"
static struct uart_driver arc_uart_driver = {
. owner = THIS_MODULE ,
. driver_name = DRIVER_NAME ,
. dev_name = ARC_SERIAL_DEV_NAME ,
. major = 0 ,
. minor = 0 ,
. nr = CONFIG_SERIAL_ARC_NR_PORTS ,
# ifdef CONFIG_SERIAL_ARC_CONSOLE
. cons = & arc_console ,
# endif
} ;
static void arc_serial_stop_rx ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
UART_RX_IRQ_DISABLE ( uart ) ;
}
static void arc_serial_stop_tx ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
while ( ! ( UART_GET_STATUS ( uart ) & TXEMPTY ) )
cpu_relax ( ) ;
UART_TX_IRQ_DISABLE ( uart ) ;
}
/*
* Return TIOCSER_TEMT when transmitter is not busy .
*/
static unsigned int arc_serial_tx_empty ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
unsigned int stat ;
stat = UART_GET_STATUS ( uart ) ;
if ( stat & TXEMPTY )
return TIOCSER_TEMT ;
return 0 ;
}
/*
* Driver internal routine , used by both tty ( serial core ) as well as tx - isr
* - Called under spinlock in either cases
2013-03-07 16:12:34 +04:00
* - also tty - > stopped has already been checked
2012-10-27 11:17:12 +04:00
* = by uart_start ( ) before calling us
* = tx_ist checks that too before calling
*/
static void arc_serial_tx_chars ( struct arc_uart_port * uart )
{
struct circ_buf * xmit = & uart - > port . state - > xmit ;
int sent = 0 ;
unsigned char ch ;
if ( unlikely ( uart - > port . x_char ) ) {
UART_SET_DATA ( uart , uart - > port . x_char ) ;
uart - > port . icount . tx + + ;
uart - > port . x_char = 0 ;
sent = 1 ;
} else if ( xmit - > tail ! = xmit - > head ) { /* TODO: uart_circ_empty */
ch = xmit - > buf [ xmit - > tail ] ;
xmit - > tail = ( xmit - > tail + 1 ) & ( UART_XMIT_SIZE - 1 ) ;
uart - > port . icount . tx + + ;
while ( ! ( UART_GET_STATUS ( uart ) & TXEMPTY ) )
cpu_relax ( ) ;
UART_SET_DATA ( uart , ch ) ;
sent = 1 ;
}
/*
* If num chars in xmit buffer are too few , ask tty layer for more .
* By Hard ISR to schedule processing in software interrupt part
*/
if ( uart_circ_chars_pending ( xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( & uart - > port ) ;
if ( sent )
UART_TX_IRQ_ENABLE ( uart ) ;
}
/*
* port is locked and interrupts are disabled
* uart_start ( ) calls us under the port spinlock irqsave
*/
static void arc_serial_start_tx ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
arc_serial_tx_chars ( uart ) ;
}
2013-08-02 08:49:19 +04:00
static void arc_serial_rx_chars ( struct arc_uart_port * uart , unsigned int status )
2012-10-27 11:17:12 +04:00
{
2013-08-02 08:49:19 +04:00
unsigned int ch , flg = 0 ;
2012-10-27 11:17:12 +04:00
/*
* UART has 4 deep RX - FIFO . Driver ' s recongnition of this fact
* is very subtle . Here ' s how . . .
* Upon getting a RX - Intr , such that RX - EMPTY = 0 , meaning data available ,
* driver reads the DATA Reg and keeps doing that in a loop , until
* RX - EMPTY = 1. Multiple chars being avail , with a single Interrupt ,
* before RX - EMPTY = 0 , implies some sort of buffering going on in the
* controller , which is indeed the Rx - FIFO .
*/
2013-08-02 08:49:19 +04:00
do {
/*
* This could be an Rx Intr for err ( no data ) ,
* so check err and clear that Intr first
*/
2012-10-27 11:17:12 +04:00
if ( unlikely ( status & ( RXOERR | RXFERR ) ) ) {
if ( status & RXOERR ) {
uart - > port . icount . overrun + + ;
flg = TTY_OVERRUN ;
UART_CLR_STATUS ( uart , RXOERR ) ;
}
if ( status & RXFERR ) {
uart - > port . icount . frame + + ;
flg = TTY_FRAME ;
UART_CLR_STATUS ( uart , RXFERR ) ;
}
} else
flg = TTY_NORMAL ;
2013-08-02 08:49:19 +04:00
if ( status & RXEMPTY )
continue ;
ch = UART_GET_DATA ( uart ) ;
uart - > port . icount . rx + + ;
2013-08-02 08:49:20 +04:00
if ( ! ( uart_handle_sysrq_char ( & uart - > port , ch ) ) )
uart_insert_char ( & uart - > port , status , RXOERR , ch , flg ) ;
2012-10-27 11:17:12 +04:00
2013-08-19 18:44:09 +04:00
spin_unlock ( & uart - > port . lock ) ;
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & uart - > port . state - > port ) ;
2013-08-19 18:44:09 +04:00
spin_lock ( & uart - > port . lock ) ;
2013-08-02 08:49:19 +04:00
} while ( ! ( ( status = UART_GET_STATUS ( uart ) ) & RXEMPTY ) ) ;
2012-10-27 11:17:12 +04:00
}
/*
* A note on the Interrupt handling state machine of this driver
*
* kernel printk writes funnel thru the console driver framework and in order
* to keep things simple as well as efficient , it writes to UART in polled
* mode , in one shot , and exits .
*
* OTOH , Userland output ( via tty layer ) , uses interrupt based writes as there
* can be undeterministic delay between char writes .
*
* Thus Rx - interrupts are always enabled , while tx - interrupts are by default
* disabled .
*
* When tty has some data to send out , serial core calls driver ' s start_tx
* which
* - checks - if - tty - buffer - has - char - to - send
* - writes - data - to - uart
* - enable - tx - intr
*
* Once data bits are pushed out , controller raises the Tx - room - avail - Interrupt .
* The first thing Tx ISR does is disable further Tx interrupts ( as this could
* be the last char to send , before settling down into the quiet polled mode ) .
* It then calls the exact routine used by tty layer write to send out any
* more char in tty buffer . In case of sending , it re - enables Tx - intr . In case
* of no data , it remains disabled .
* This is how the transmit state machine is dynamically switched on / off
*/
static irqreturn_t arc_serial_isr ( int irq , void * dev_id )
{
struct arc_uart_port * uart = dev_id ;
unsigned int status ;
status = UART_GET_STATUS ( uart ) ;
/*
* Single IRQ for both Rx ( data available ) Tx ( room available ) Interrupt
* notifications from the UART Controller .
* To demultiplex between the two , we check the relevant bits
*/
2013-08-02 08:49:19 +04:00
if ( status & RXIENB ) {
2012-10-27 11:17:12 +04:00
/* already in ISR, no need of xx_irqsave */
spin_lock ( & uart - > port . lock ) ;
2013-08-02 08:49:19 +04:00
arc_serial_rx_chars ( uart , status ) ;
2012-10-27 11:17:12 +04:00
spin_unlock ( & uart - > port . lock ) ;
}
if ( ( status & TXIENB ) & & ( status & TXEMPTY ) ) {
/* Unconditionally disable further Tx-Interrupts.
* will be enabled by tx_chars ( ) if needed .
*/
UART_TX_IRQ_DISABLE ( uart ) ;
spin_lock ( & uart - > port . lock ) ;
if ( ! uart_tx_stopped ( & uart - > port ) )
arc_serial_tx_chars ( uart ) ;
spin_unlock ( & uart - > port . lock ) ;
}
return IRQ_HANDLED ;
}
static unsigned int arc_serial_get_mctrl ( struct uart_port * port )
{
/*
* Pretend we have a Modem status reg and following bits are
* always set , to satify the serial core state machine
* ( DSR ) Data Set Ready
* ( CTS ) Clear To Send
* ( CAR ) Carrier Detect
*/
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR ;
}
static void arc_serial_set_mctrl ( struct uart_port * port , unsigned int mctrl )
{
/* MCR not present */
}
/* Enable Modem Status Interrupts */
static void arc_serial_enable_ms ( struct uart_port * port )
{
/* MSR not present */
}
static void arc_serial_break_ctl ( struct uart_port * port , int break_state )
{
/* ARC UART doesn't support sending Break signal */
}
static int arc_serial_startup ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
/* Before we hook up the ISR, Disable all UART Interrupts */
UART_ALL_IRQ_DISABLE ( uart ) ;
if ( request_irq ( uart - > port . irq , arc_serial_isr , 0 , " arc uart rx-tx " ,
uart ) ) {
dev_warn ( uart - > port . dev , " Unable to attach ARC UART intr \n " ) ;
return - EBUSY ;
}
UART_RX_IRQ_ENABLE ( uart ) ; /* Only Rx IRQ enabled to begin with */
return 0 ;
}
/* This is not really needed */
static void arc_serial_shutdown ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
free_irq ( uart - > port . irq , uart ) ;
}
static void
arc_serial_set_termios ( struct uart_port * port , struct ktermios * new ,
struct ktermios * old )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
unsigned int baud , uartl , uarth , hw_val ;
unsigned long flags ;
/*
* Use the generic handler so that any specially encoded baud rates
* such as SPD_xx flags or " %B0 " can be handled
* Max Baud I suppose will not be more than current 115 K * 4
* Formula for ARC UART is : hw - val = ( ( CLK / ( BAUD * 4 ) ) - 1 )
* spread over two 8 - bit registers
*/
baud = uart_get_baud_rate ( port , new , old , 0 , 460800 ) ;
hw_val = port - > uartclk / ( uart - > baud * 4 ) - 1 ;
uartl = hw_val & 0xFF ;
uarth = ( hw_val > > 8 ) & 0xFF ;
/*
* UART ISS ( Instruction Set simulator ) emulation has a subtle bug :
* A existing value of Baudh = 0 is used as a indication to startup
* it ' s internal state machine .
* Thus if baudh is set to 0 , 2 times , it chokes .
* This happens with BAUD = 115200 and the formaula above
* Until that is fixed , when running on ISS , we will set baudh to ! 0
*/
if ( uart - > is_emulated )
uarth = 1 ;
spin_lock_irqsave ( & port - > lock , flags ) ;
UART_ALL_IRQ_DISABLE ( uart ) ;
UART_SET_BAUDL ( uart , uartl ) ;
UART_SET_BAUDH ( uart , uarth ) ;
UART_RX_IRQ_ENABLE ( uart ) ;
/*
* UART doesn ' t support Parity / Hardware Flow Control ;
* Only supports 8 N1 character size
*/
new - > c_cflag & = ~ ( CMSPAR | CRTSCTS | CSIZE ) ;
new - > c_cflag | = CS8 ;
if ( old )
tty_termios_copy_hw ( new , old ) ;
/* Don't rewrite B0 */
if ( tty_termios_baud_rate ( new ) )
tty_termios_encode_baud_rate ( new , baud , baud ) ;
uart_update_timeout ( port , new - > c_cflag , baud ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
static const char * arc_serial_type ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
return uart - > port . type = = PORT_ARC ? DRIVER_NAME : NULL ;
}
static void arc_serial_release_port ( struct uart_port * port )
{
}
static int arc_serial_request_port ( struct uart_port * port )
{
return 0 ;
}
/*
* Verify the new serial_struct ( for TIOCSSERIAL ) .
*/
static int
arc_serial_verify_port ( struct uart_port * port , struct serial_struct * ser )
{
if ( port - > type ! = PORT_UNKNOWN & & ser - > type ! = PORT_ARC )
return - EINVAL ;
return 0 ;
}
/*
* Configure / autoconfigure the port .
*/
static void arc_serial_config_port ( struct uart_port * port , int flags )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
if ( flags & UART_CONFIG_TYPE )
uart - > port . type = PORT_ARC ;
}
# if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE)
static void arc_serial_poll_putchar ( struct uart_port * port , unsigned char chr )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
while ( ! ( UART_GET_STATUS ( uart ) & TXEMPTY ) )
cpu_relax ( ) ;
UART_SET_DATA ( uart , chr ) ;
}
# endif
# ifdef CONFIG_CONSOLE_POLL
static int arc_serial_poll_getchar ( struct uart_port * port )
{
struct arc_uart_port * uart = to_arc_port ( port ) ;
unsigned char chr ;
while ( ! ( UART_GET_STATUS ( uart ) & RXEMPTY ) )
cpu_relax ( ) ;
chr = UART_GET_DATA ( uart ) ;
return chr ;
}
# endif
static struct uart_ops arc_serial_pops = {
. tx_empty = arc_serial_tx_empty ,
. set_mctrl = arc_serial_set_mctrl ,
. get_mctrl = arc_serial_get_mctrl ,
. stop_tx = arc_serial_stop_tx ,
. start_tx = arc_serial_start_tx ,
. stop_rx = arc_serial_stop_rx ,
. enable_ms = arc_serial_enable_ms ,
. break_ctl = arc_serial_break_ctl ,
. startup = arc_serial_startup ,
. shutdown = arc_serial_shutdown ,
. set_termios = arc_serial_set_termios ,
. type = arc_serial_type ,
. release_port = arc_serial_release_port ,
. request_port = arc_serial_request_port ,
. config_port = arc_serial_config_port ,
. verify_port = arc_serial_verify_port ,
# ifdef CONFIG_CONSOLE_POLL
. poll_put_char = arc_serial_poll_putchar ,
. poll_get_char = arc_serial_poll_getchar ,
# endif
} ;
2012-11-19 22:21:50 +04:00
static int
2013-01-11 10:20:20 +04:00
arc_uart_init_one ( struct platform_device * pdev , int dev_id )
2012-10-27 11:17:12 +04:00
{
struct resource * res , * res2 ;
unsigned long * plat_data ;
2013-01-11 10:20:20 +04:00
struct arc_uart_port * uart = & arc_uart_ports [ dev_id ] ;
2012-10-27 11:17:12 +04:00
2013-07-30 12:06:57 +04:00
plat_data = ( unsigned long * ) dev_get_platdata ( & pdev - > dev ) ;
2013-01-11 10:20:22 +04:00
if ( ! plat_data )
return - ENODEV ;
uart - > is_emulated = ! ! plat_data [ 0 ] ; /* workaround ISS bug */
2013-01-11 10:20:23 +04:00
if ( is_early_platform_device ( pdev ) ) {
uart - > port . uartclk = plat_data [ 1 ] ;
uart - > baud = plat_data [ 2 ] ;
} else {
struct device_node * np = pdev - > dev . of_node ;
u32 val ;
if ( of_property_read_u32 ( np , " clock-frequency " , & val ) ) {
dev_err ( & pdev - > dev , " clock-frequency property NOTset \n " ) ;
return - EINVAL ;
}
uart - > port . uartclk = val ;
2013-02-11 12:41:41 +04:00
if ( of_property_read_u32 ( np , " current-speed " , & val ) ) {
dev_err ( & pdev - > dev , " current-speed property NOT set \n " ) ;
2013-01-11 10:20:23 +04:00
return - EINVAL ;
}
uart - > baud = val ;
}
2012-10-27 11:17:12 +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 ;
uart - > port . mapbase = res - > start ;
uart - > port . membase = ioremap_nocache ( res - > start , resource_size ( res ) ) ;
if ( ! uart - > port . membase )
/* No point of dev_err since UART itself is hosed here */
return - ENXIO ;
uart - > port . irq = res2 - > start ;
uart - > port . dev = & pdev - > dev ;
uart - > port . iotype = UPIO_MEM ;
uart - > port . flags = UPF_BOOT_AUTOCONF ;
2013-01-11 10:20:20 +04:00
uart - > port . line = dev_id ;
2012-10-27 11:17:12 +04:00
uart - > port . ops = & arc_serial_pops ;
uart - > port . fifosize = ARC_UART_TX_FIFO_SIZE ;
/*
* uart_insert_char ( ) uses it in decideding whether to ignore a
* char or not . Explicitly setting it here , removes the subtelty
*/
uart - > port . ignore_status_mask = 0 ;
return 0 ;
}
# ifdef CONFIG_SERIAL_ARC_CONSOLE
2012-11-19 22:21:50 +04:00
static int arc_serial_console_setup ( struct console * co , char * options )
2012-10-27 11:17:12 +04:00
{
struct uart_port * port ;
int baud = 115200 ;
int bits = 8 ;
int parity = ' n ' ;
int flow = ' n ' ;
if ( co - > index < 0 | | co - > index > = CONFIG_SERIAL_ARC_NR_PORTS )
return - ENODEV ;
/*
* The uart port backing the console ( e . g . ttyARC1 ) might not have been
* init yet . If so , defer the console setup to after the port .
*/
port = & arc_uart_ports [ co - > index ] . port ;
if ( ! port - > membase )
return - ENODEV ;
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
/*
* Serial core will call port - > ops - > set_termios ( )
* which will set the baud reg
*/
return uart_set_options ( port , co , baud , parity , bits , flow ) ;
}
static void arc_serial_console_putchar ( struct uart_port * port , int ch )
{
arc_serial_poll_putchar ( port , ( unsigned char ) ch ) ;
}
/*
* Interrupts are disabled on entering
*/
static void arc_serial_console_write ( struct console * co , const char * s ,
unsigned int count )
{
struct uart_port * port = & arc_uart_ports [ co - > index ] . port ;
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
uart_console_write ( port , s , count , arc_serial_console_putchar ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
static struct console arc_console = {
. name = ARC_SERIAL_DEV_NAME ,
. write = arc_serial_console_write ,
. device = uart_console_device ,
. setup = arc_serial_console_setup ,
. flags = CON_PRINTBUFFER ,
. index = - 1 ,
. data = & arc_uart_driver
} ;
static __init void early_serial_write ( struct console * con , const char * s ,
unsigned int n )
{
struct uart_port * port = & arc_uart_ports [ con - > index ] . port ;
unsigned int i ;
for ( i = 0 ; i < n ; i + + , s + + ) {
if ( * s = = ' \n ' )
arc_serial_poll_putchar ( port , ' \r ' ) ;
arc_serial_poll_putchar ( port , * s ) ;
}
}
2013-01-16 12:17:23 +04:00
static struct console arc_early_serial_console __initdata = {
2012-10-27 11:17:12 +04:00
. name = " early_ARCuart " ,
. write = early_serial_write ,
. flags = CON_PRINTBUFFER | CON_BOOT ,
. index = - 1
} ;
2013-01-11 10:20:21 +04:00
static int __init arc_serial_probe_earlyprintk ( struct platform_device * pdev )
2012-10-27 11:17:12 +04:00
{
2013-01-11 10:20:20 +04:00
int dev_id = pdev - > id < 0 ? 0 : pdev - > id ;
int rc ;
2012-10-27 11:17:12 +04:00
2013-01-11 10:20:20 +04:00
arc_early_serial_console . index = dev_id ;
rc = arc_uart_init_one ( pdev , dev_id ) ;
if ( rc )
panic ( " early console init failed \n " ) ;
2012-10-27 11:17:12 +04:00
arc_serial_console_setup ( & arc_early_serial_console , NULL ) ;
register_console ( & arc_early_serial_console ) ;
return 0 ;
}
# endif /* CONFIG_SERIAL_ARC_CONSOLE */
2012-11-19 22:21:50 +04:00
static int arc_serial_probe ( struct platform_device * pdev )
2012-10-27 11:17:12 +04:00
{
2013-01-11 10:20:20 +04:00
int rc , dev_id ;
2013-01-11 10:20:23 +04:00
struct device_node * np = pdev - > dev . of_node ;
/* no device tree device */
if ( ! np )
return - ENODEV ;
dev_id = of_alias_get_id ( np , " serial " ) ;
2013-02-11 12:41:41 +04:00
if ( dev_id < 0 )
dev_id = 0 ;
2012-10-27 11:17:12 +04:00
2013-01-11 10:20:20 +04:00
rc = arc_uart_init_one ( pdev , dev_id ) ;
2012-10-27 11:17:12 +04:00
if ( rc )
return rc ;
2013-01-11 10:20:20 +04:00
rc = uart_add_one_port ( & arc_uart_driver , & arc_uart_ports [ dev_id ] . port ) ;
return rc ;
2012-10-27 11:17:12 +04:00
}
2012-11-19 22:26:18 +04:00
static int arc_serial_remove ( struct platform_device * pdev )
2012-10-27 11:17:12 +04:00
{
/* This will never be called */
return 0 ;
}
2013-01-11 10:20:23 +04:00
static const struct of_device_id arc_uart_dt_ids [ ] = {
{ . compatible = " snps,arc-uart " } ,
{ /* Sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , arc_uart_dt_ids ) ;
2012-10-27 11:17:12 +04:00
static struct platform_driver arc_platform_driver = {
. probe = arc_serial_probe ,
2012-11-19 22:21:34 +04:00
. remove = arc_serial_remove ,
2012-10-27 11:17:12 +04:00
. driver = {
. name = DRIVER_NAME ,
. owner = THIS_MODULE ,
2013-01-11 10:20:23 +04:00
. of_match_table = arc_uart_dt_ids ,
2012-10-27 11:17:12 +04:00
} ,
} ;
# ifdef CONFIG_SERIAL_ARC_CONSOLE
2013-01-11 10:20:21 +04:00
2013-01-16 12:17:23 +04:00
static struct platform_driver early_arc_platform_driver __initdata = {
2013-01-11 10:20:21 +04:00
. probe = arc_serial_probe_earlyprintk ,
. remove = arc_serial_remove ,
. driver = {
. name = DRIVER_NAME ,
. owner = THIS_MODULE ,
} ,
} ;
2012-10-27 11:17:12 +04:00
/*
* Register an early platform driver of " earlyprintk " class .
* ARCH platform code installs the driver and probes the early devices
* The installation could rely on user specifying earlyprintk = xyx in cmd line
* or it could be done independently , for all " earlyprintk " class drivers .
* [ see arch / arc / plat - arcfpga / platform . c ]
*/
2013-01-11 10:20:21 +04:00
early_platform_init ( " earlyprintk " , & early_arc_platform_driver ) ;
2012-10-27 11:17:12 +04:00
# endif /* CONFIG_SERIAL_ARC_CONSOLE */
static int __init arc_serial_init ( void )
{
int ret ;
ret = uart_register_driver ( & arc_uart_driver ) ;
if ( ret )
return ret ;
ret = platform_driver_register ( & arc_platform_driver ) ;
if ( ret )
uart_unregister_driver ( & arc_uart_driver ) ;
return ret ;
}
static void __exit arc_serial_exit ( void )
{
platform_driver_unregister ( & arc_platform_driver ) ;
uart_unregister_driver ( & arc_uart_driver ) ;
}
module_init ( arc_serial_init ) ;
module_exit ( arc_serial_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2013-07-21 06:14:15 +04:00
MODULE_ALIAS ( " platform: " DRIVER_NAME ) ;
2012-10-27 11:17:12 +04:00
MODULE_AUTHOR ( " Vineet Gupta " ) ;
MODULE_DESCRIPTION ( " ARC(Synopsys) On-Chip(fpga) serial driver " ) ;