2017-11-06 18:11:51 +01:00
// SPDX-License-Identifier: GPL-2.0+
2016-01-13 18:15:43 -07:00
/*
* PIC32 Integrated Serial Driver .
*
* Copyright ( C ) 2015 Microchip Technology , Inc .
*
* Authors :
* Sorin - Andrei Pistirica < andrei . pistirica @ microchip . com >
*/
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/of_irq.h>
# include <linux/of_gpio.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/console.h>
# include <linux/clk.h>
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/serial_core.h>
# include <linux/delay.h>
# include <asm/mach-pic32/pic32.h>
# include "pic32_uart.h"
/* UART name and device definitions */
# define PIC32_DEV_NAME "pic32-uart"
# define PIC32_MAX_UARTS 6
# define PIC32_SDEV_NAME "ttyPIC"
/* pic32_sport pointer for console use */
static struct pic32_sport * pic32_sports [ PIC32_MAX_UARTS ] ;
static inline void pic32_wait_deplete_txbuf ( struct pic32_sport * sport )
{
/* wait for tx empty, otherwise chars will be lost or corrupted */
while ( ! ( pic32_uart_readl ( sport , PIC32_UART_STA ) & PIC32_UART_STA_TRMT ) )
udelay ( 1 ) ;
}
static inline int pic32_enable_clock ( struct pic32_sport * sport )
{
int ret = clk_prepare_enable ( sport - > clk ) ;
if ( ret )
return ret ;
sport - > ref_clk + + ;
return 0 ;
}
static inline void pic32_disable_clock ( struct pic32_sport * sport )
{
sport - > ref_clk - - ;
clk_disable_unprepare ( sport - > clk ) ;
}
/* serial core request to check if uart tx buffer is empty */
static unsigned int pic32_uart_tx_empty ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
u32 val = pic32_uart_readl ( sport , PIC32_UART_STA ) ;
return ( val & PIC32_UART_STA_TRMT ) ? 1 : 0 ;
}
/* serial core request to set UART outputs */
static void pic32_uart_set_mctrl ( struct uart_port * port , unsigned int mctrl )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
/* set loopback mode */
if ( mctrl & TIOCM_LOOP )
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_LPBK ) ;
else
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_LPBK ) ;
}
/* get the state of CTS input pin for this port */
static unsigned int get_cts_state ( struct pic32_sport * sport )
{
/* read and invert UxCTS */
if ( gpio_is_valid ( sport - > cts_gpio ) )
return ! gpio_get_value ( sport - > cts_gpio ) ;
return 1 ;
}
/* serial core request to return the state of misc UART input pins */
static unsigned int pic32_uart_get_mctrl ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
unsigned int mctrl = 0 ;
if ( ! sport - > hw_flow_ctrl )
mctrl | = TIOCM_CTS ;
else if ( get_cts_state ( sport ) )
mctrl | = TIOCM_CTS ;
/* DSR and CD are not supported in PIC32, so return 1
* RI is not supported in PIC32 , so return 0
*/
mctrl | = TIOCM_CD ;
mctrl | = TIOCM_DSR ;
return mctrl ;
}
/* stop tx and start tx are not called in pairs, therefore a flag indicates
* the status of irq to control the irq - depth .
*/
static inline void pic32_uart_irqtxen ( struct pic32_sport * sport , u8 en )
{
if ( en & & ! tx_irq_enabled ( sport ) ) {
enable_irq ( sport - > irq_tx ) ;
tx_irq_enabled ( sport ) = 1 ;
} else if ( ! en & & tx_irq_enabled ( sport ) ) {
/* use disable_irq_nosync() and not disable_irq() to avoid self
* imposed deadlock by not waiting for irq handler to end ,
* since this callback is called from interrupt context .
*/
disable_irq_nosync ( sport - > irq_tx ) ;
tx_irq_enabled ( sport ) = 0 ;
}
}
/* serial core request to disable tx ASAP (used for flow control) */
static void pic32_uart_stop_tx ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
if ( ! ( pic32_uart_readl ( sport , PIC32_UART_MODE ) & PIC32_UART_MODE_ON ) )
return ;
if ( ! ( pic32_uart_readl ( sport , PIC32_UART_STA ) & PIC32_UART_STA_UTXEN ) )
return ;
/* wait for tx empty */
pic32_wait_deplete_txbuf ( sport ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_STA ) ,
PIC32_UART_STA_UTXEN ) ;
pic32_uart_irqtxen ( sport , 0 ) ;
}
/* serial core request to (re)enable tx */
static void pic32_uart_start_tx ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
pic32_uart_irqtxen ( sport , 1 ) ;
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_STA ) ,
PIC32_UART_STA_UTXEN ) ;
}
/* serial core request to stop rx, called before port shutdown */
static void pic32_uart_stop_rx ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
/* disable rx interrupts */
disable_irq ( sport - > irq_rx ) ;
/* receiver Enable bit OFF */
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_STA ) ,
PIC32_UART_STA_URXEN ) ;
}
/* serial core request to start/stop emitting break char */
static void pic32_uart_break_ctl ( struct uart_port * port , int ctl )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
if ( ctl )
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_STA ) ,
PIC32_UART_STA_UTXBRK ) ;
else
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_STA ) ,
PIC32_UART_STA_UTXBRK ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/* get port type in string format */
static const char * pic32_uart_type ( struct uart_port * port )
{
return ( port - > type = = PORT_PIC32 ) ? PIC32_DEV_NAME : NULL ;
}
/* read all chars in rx fifo and send them to core */
static void pic32_uart_do_rx ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
struct tty_port * tty ;
unsigned int max_count ;
/* limit number of char read in interrupt, should not be
* higher than fifo size anyway since we ' re much faster than
* serial port
*/
max_count = PIC32_UART_RX_FIFO_DEPTH ;
spin_lock ( & port - > lock ) ;
tty = & port - > state - > port ;
do {
u32 sta_reg , c ;
char flag ;
/* get overrun/fifo empty information from status register */
sta_reg = pic32_uart_readl ( sport , PIC32_UART_STA ) ;
if ( unlikely ( sta_reg & PIC32_UART_STA_OERR ) ) {
/* fifo reset is required to clear interrupt */
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_STA ) ,
PIC32_UART_STA_OERR ) ;
port - > icount . overrun + + ;
tty_insert_flip_char ( tty , 0 , TTY_OVERRUN ) ;
}
/* Can at least one more character can be read? */
if ( ! ( sta_reg & PIC32_UART_STA_URXDA ) )
break ;
/* read the character and increment the rx counter */
c = pic32_uart_readl ( sport , PIC32_UART_RX ) ;
port - > icount . rx + + ;
flag = TTY_NORMAL ;
c & = 0xff ;
if ( unlikely ( ( sta_reg & PIC32_UART_STA_PERR ) | |
( sta_reg & PIC32_UART_STA_FERR ) ) ) {
/* do stats first */
if ( sta_reg & PIC32_UART_STA_PERR )
port - > icount . parity + + ;
if ( sta_reg & PIC32_UART_STA_FERR )
port - > icount . frame + + ;
/* update flag wrt read_status_mask */
sta_reg & = port - > read_status_mask ;
if ( sta_reg & PIC32_UART_STA_FERR )
flag = TTY_FRAME ;
if ( sta_reg & PIC32_UART_STA_PERR )
flag = TTY_PARITY ;
}
if ( uart_handle_sysrq_char ( port , c ) )
continue ;
if ( ( sta_reg & port - > ignore_status_mask ) = = 0 )
tty_insert_flip_char ( tty , c , flag ) ;
} while ( - - max_count ) ;
spin_unlock ( & port - > lock ) ;
tty_flip_buffer_push ( tty ) ;
}
/* fill tx fifo with chars to send, stop when fifo is about to be full
* or when all chars have been sent .
*/
static void pic32_uart_do_tx ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
struct circ_buf * xmit = & port - > state - > xmit ;
unsigned int max_count = PIC32_UART_TX_FIFO_DEPTH ;
if ( port - > x_char ) {
pic32_uart_writel ( sport , PIC32_UART_TX , port - > x_char ) ;
port - > icount . tx + + ;
port - > x_char = 0 ;
return ;
}
if ( uart_tx_stopped ( port ) ) {
pic32_uart_stop_tx ( port ) ;
return ;
}
if ( uart_circ_empty ( xmit ) )
goto txq_empty ;
/* keep stuffing chars into uart tx buffer
* 1 ) until uart fifo is full
* or
* 2 ) until the circ buffer is empty
* ( all chars have been sent )
* or
* 3 ) until the max count is reached
* ( prevents lingering here for too long in certain cases )
*/
while ( ! ( PIC32_UART_STA_UTXBF &
pic32_uart_readl ( sport , PIC32_UART_STA ) ) ) {
unsigned int c = xmit - > buf [ xmit - > tail ] ;
pic32_uart_writel ( sport , PIC32_UART_TX , c ) ;
xmit - > tail = ( xmit - > tail + 1 ) & ( UART_XMIT_SIZE - 1 ) ;
port - > icount . tx + + ;
if ( uart_circ_empty ( xmit ) )
break ;
if ( - - max_count = = 0 )
break ;
}
if ( uart_circ_chars_pending ( xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( port ) ;
if ( uart_circ_empty ( xmit ) )
goto txq_empty ;
return ;
txq_empty :
pic32_uart_irqtxen ( sport , 0 ) ;
}
/* RX interrupt handler */
static irqreturn_t pic32_uart_rx_interrupt ( int irq , void * dev_id )
{
struct uart_port * port = dev_id ;
pic32_uart_do_rx ( port ) ;
return IRQ_HANDLED ;
}
/* TX interrupt handler */
static irqreturn_t pic32_uart_tx_interrupt ( int irq , void * dev_id )
{
struct uart_port * port = dev_id ;
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
pic32_uart_do_tx ( port ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
return IRQ_HANDLED ;
}
/* FAULT interrupt handler */
static irqreturn_t pic32_uart_fault_interrupt ( int irq , void * dev_id )
{
/* do nothing: pic32_uart_do_rx() handles faults. */
return IRQ_HANDLED ;
}
/* enable rx & tx operation on uart */
static void pic32_uart_en_and_unmask ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_STA ) ,
PIC32_UART_STA_UTXEN | PIC32_UART_STA_URXEN ) ;
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_ON ) ;
}
/* disable rx & tx operation on uart */
static void pic32_uart_dsbl_and_mask ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
/* wait for tx empty, otherwise chars will be lost or corrupted */
pic32_wait_deplete_txbuf ( sport ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_STA ) ,
PIC32_UART_STA_UTXEN | PIC32_UART_STA_URXEN ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_ON ) ;
}
/* serial core request to initialize uart and start rx operation */
static int pic32_uart_startup ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
u32 dflt_baud = ( port - > uartclk / PIC32_UART_DFLT_BRATE / 16 ) - 1 ;
unsigned long flags ;
int ret ;
local_irq_save ( flags ) ;
ret = pic32_enable_clock ( sport ) ;
if ( ret ) {
local_irq_restore ( flags ) ;
goto out_done ;
}
/* clear status and mode registers */
pic32_uart_writel ( sport , PIC32_UART_MODE , 0 ) ;
pic32_uart_writel ( sport , PIC32_UART_STA , 0 ) ;
/* disable uart and mask all interrupts */
pic32_uart_dsbl_and_mask ( port ) ;
/* set default baud */
pic32_uart_writel ( sport , PIC32_UART_BRG , dflt_baud ) ;
local_irq_restore ( flags ) ;
/* Each UART of a PIC32 has three interrupts therefore,
* we setup driver to register the 3 irqs for the device .
*
* For each irq request_irq ( ) is called with interrupt disabled .
* And the irq is enabled as soon as we are ready to handle them .
*/
tx_irq_enabled ( sport ) = 0 ;
sport - > irq_fault_name = kasprintf ( GFP_KERNEL , " %s%d-fault " ,
pic32_uart_type ( port ) ,
sport - > idx ) ;
if ( ! sport - > irq_fault_name ) {
dev_err ( port - > dev , " %s: kasprintf err! " , __func__ ) ;
ret = - ENOMEM ;
goto out_done ;
}
irq_set_status_flags ( sport - > irq_fault , IRQ_NOAUTOEN ) ;
ret = request_irq ( sport - > irq_fault , pic32_uart_fault_interrupt ,
sport - > irqflags_fault , sport - > irq_fault_name , port ) ;
if ( ret ) {
dev_err ( port - > dev , " %s: request irq(%d) err! ret:%d name:%s \n " ,
__func__ , sport - > irq_fault , ret ,
pic32_uart_type ( port ) ) ;
goto out_f ;
}
sport - > irq_rx_name = kasprintf ( GFP_KERNEL , " %s%d-rx " ,
pic32_uart_type ( port ) ,
sport - > idx ) ;
if ( ! sport - > irq_rx_name ) {
dev_err ( port - > dev , " %s: kasprintf err! " , __func__ ) ;
ret = - ENOMEM ;
goto out_f ;
}
irq_set_status_flags ( sport - > irq_rx , IRQ_NOAUTOEN ) ;
ret = request_irq ( sport - > irq_rx , pic32_uart_rx_interrupt ,
sport - > irqflags_rx , sport - > irq_rx_name , port ) ;
if ( ret ) {
dev_err ( port - > dev , " %s: request irq(%d) err! ret:%d name:%s \n " ,
__func__ , sport - > irq_rx , ret ,
pic32_uart_type ( port ) ) ;
goto out_r ;
}
sport - > irq_tx_name = kasprintf ( GFP_KERNEL , " %s%d-tx " ,
pic32_uart_type ( port ) ,
sport - > idx ) ;
if ( ! sport - > irq_tx_name ) {
dev_err ( port - > dev , " %s: kasprintf err! " , __func__ ) ;
ret = - ENOMEM ;
goto out_r ;
}
irq_set_status_flags ( sport - > irq_tx , IRQ_NOAUTOEN ) ;
ret = request_irq ( sport - > irq_tx , pic32_uart_tx_interrupt ,
sport - > irqflags_tx , sport - > irq_tx_name , port ) ;
if ( ret ) {
dev_err ( port - > dev , " %s: request irq(%d) err! ret:%d name:%s \n " ,
__func__ , sport - > irq_tx , ret ,
pic32_uart_type ( port ) ) ;
goto out_t ;
}
local_irq_save ( flags ) ;
/* set rx interrupt on first receive */
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_STA ) ,
PIC32_UART_STA_URXISEL1 | PIC32_UART_STA_URXISEL0 ) ;
/* set interrupt on empty */
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_STA ) ,
PIC32_UART_STA_UTXISEL1 ) ;
/* enable all interrupts and eanable uart */
pic32_uart_en_and_unmask ( port ) ;
enable_irq ( sport - > irq_rx ) ;
return 0 ;
out_t :
kfree ( sport - > irq_tx_name ) ;
2016-12-18 07:38:11 +01:00
free_irq ( sport - > irq_tx , port ) ;
2016-01-13 18:15:43 -07:00
out_r :
kfree ( sport - > irq_rx_name ) ;
2016-12-18 07:38:11 +01:00
free_irq ( sport - > irq_rx , port ) ;
2016-01-13 18:15:43 -07:00
out_f :
kfree ( sport - > irq_fault_name ) ;
2016-12-18 07:38:11 +01:00
free_irq ( sport - > irq_fault , port ) ;
2016-01-13 18:15:43 -07:00
out_done :
return ret ;
}
/* serial core request to flush & disable uart */
static void pic32_uart_shutdown ( struct uart_port * port )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
unsigned long flags ;
/* disable uart */
spin_lock_irqsave ( & port - > lock , flags ) ;
pic32_uart_dsbl_and_mask ( port ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
pic32_disable_clock ( sport ) ;
/* free all 3 interrupts for this UART */
free_irq ( sport - > irq_fault , port ) ;
free_irq ( sport - > irq_tx , port ) ;
free_irq ( sport - > irq_rx , port ) ;
}
/* serial core request to change current uart setting */
static void pic32_uart_set_termios ( struct uart_port * port ,
struct ktermios * new ,
struct ktermios * old )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
unsigned int baud ;
unsigned int quot ;
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
/* disable uart and mask all interrupts while changing speed */
pic32_uart_dsbl_and_mask ( port ) ;
/* stop bit options */
if ( new - > c_cflag & CSTOPB )
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_STSEL ) ;
else
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_STSEL ) ;
/* parity options */
if ( new - > c_cflag & PARENB ) {
if ( new - > c_cflag & PARODD ) {
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_PDSEL1 ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_PDSEL0 ) ;
} else {
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_PDSEL0 ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_PDSEL1 ) ;
}
} else {
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_PDSEL1 |
PIC32_UART_MODE_PDSEL0 ) ;
}
/* if hw flow ctrl, then the pins must be specified in device tree */
if ( ( new - > c_cflag & CRTSCTS ) & & sport - > hw_flow_ctrl ) {
/* enable hardware flow control */
pic32_uart_writel ( sport , PIC32_SET ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_UEN1 ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_UEN0 ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_RTSMD ) ;
} else {
/* disable hardware flow control */
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_UEN1 ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_UEN0 ) ;
pic32_uart_writel ( sport , PIC32_CLR ( PIC32_UART_MODE ) ,
PIC32_UART_MODE_RTSMD ) ;
}
/* Always 8-bit */
new - > c_cflag | = CS8 ;
/* Mark/Space parity is not supported */
new - > c_cflag & = ~ CMSPAR ;
/* update baud */
baud = uart_get_baud_rate ( port , new , old , 0 , port - > uartclk / 16 ) ;
quot = uart_get_divisor ( port , baud ) - 1 ;
pic32_uart_writel ( sport , PIC32_UART_BRG , quot ) ;
uart_update_timeout ( port , new - > c_cflag , baud ) ;
if ( tty_termios_baud_rate ( new ) )
tty_termios_encode_baud_rate ( new , baud , baud ) ;
/* enable uart */
pic32_uart_en_and_unmask ( port ) ;
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/* serial core request to claim uart iomem */
static int pic32_uart_request_port ( struct uart_port * port )
{
struct platform_device * pdev = to_platform_device ( port - > dev ) ;
struct resource * res_mem ;
res_mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( unlikely ( ! res_mem ) )
return - EINVAL ;
if ( ! request_mem_region ( port - > mapbase , resource_size ( res_mem ) ,
" pic32_uart_mem " ) )
return - EBUSY ;
port - > membase = devm_ioremap_nocache ( port - > dev , port - > mapbase ,
resource_size ( res_mem ) ) ;
if ( ! port - > membase ) {
dev_err ( port - > dev , " Unable to map registers \n " ) ;
release_mem_region ( port - > mapbase , resource_size ( res_mem ) ) ;
return - ENOMEM ;
}
return 0 ;
}
/* serial core request to release uart iomem */
static void pic32_uart_release_port ( struct uart_port * port )
{
struct platform_device * pdev = to_platform_device ( port - > dev ) ;
struct resource * res_mem ;
unsigned int res_size ;
res_mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( unlikely ( ! res_mem ) )
return ;
res_size = resource_size ( res_mem ) ;
release_mem_region ( port - > mapbase , res_size ) ;
}
/* serial core request to do any port required auto-configuration */
static void pic32_uart_config_port ( struct uart_port * port , int flags )
{
if ( flags & UART_CONFIG_TYPE ) {
if ( pic32_uart_request_port ( port ) )
return ;
port - > type = PORT_PIC32 ;
}
}
/* serial core request to check that port information in serinfo are suitable */
static int pic32_uart_verify_port ( struct uart_port * port ,
struct serial_struct * serinfo )
{
if ( port - > type ! = PORT_PIC32 )
return - EINVAL ;
if ( port - > irq ! = serinfo - > irq )
return - EINVAL ;
if ( port - > iotype ! = serinfo - > io_type )
return - EINVAL ;
if ( port - > mapbase ! = ( unsigned long ) serinfo - > iomem_base )
return - EINVAL ;
return 0 ;
}
/* serial core callbacks */
static const struct uart_ops pic32_uart_ops = {
. tx_empty = pic32_uart_tx_empty ,
. get_mctrl = pic32_uart_get_mctrl ,
. set_mctrl = pic32_uart_set_mctrl ,
. start_tx = pic32_uart_start_tx ,
. stop_tx = pic32_uart_stop_tx ,
. stop_rx = pic32_uart_stop_rx ,
. break_ctl = pic32_uart_break_ctl ,
. startup = pic32_uart_startup ,
. shutdown = pic32_uart_shutdown ,
. set_termios = pic32_uart_set_termios ,
. type = pic32_uart_type ,
. release_port = pic32_uart_release_port ,
. request_port = pic32_uart_request_port ,
. config_port = pic32_uart_config_port ,
. verify_port = pic32_uart_verify_port ,
} ;
# ifdef CONFIG_SERIAL_PIC32_CONSOLE
/* output given char */
static void pic32_console_putchar ( struct uart_port * port , int ch )
{
struct pic32_sport * sport = to_pic32_sport ( port ) ;
if ( ! ( pic32_uart_readl ( sport , PIC32_UART_MODE ) & PIC32_UART_MODE_ON ) )
return ;
if ( ! ( pic32_uart_readl ( sport , PIC32_UART_STA ) & PIC32_UART_STA_UTXEN ) )
return ;
/* wait for tx empty */
pic32_wait_deplete_txbuf ( sport ) ;
pic32_uart_writel ( sport , PIC32_UART_TX , ch & 0xff ) ;
}
/* console core request to output given string */
static void pic32_console_write ( struct console * co , const char * s ,
unsigned int count )
{
struct pic32_sport * sport = pic32_sports [ co - > index ] ;
struct uart_port * port = pic32_get_port ( sport ) ;
/* call uart helper to deal with \r\n */
uart_console_write ( port , s , count , pic32_console_putchar ) ;
}
/* console core request to setup given console, find matching uart
* port and setup it .
*/
static int pic32_console_setup ( struct console * co , char * options )
{
struct pic32_sport * sport ;
struct uart_port * port = NULL ;
int baud = 115200 ;
int bits = 8 ;
int parity = ' n ' ;
int flow = ' n ' ;
int ret = 0 ;
if ( unlikely ( co - > index < 0 | | co - > index > = PIC32_MAX_UARTS ) )
return - ENODEV ;
sport = pic32_sports [ co - > index ] ;
if ( ! sport )
return - ENODEV ;
port = pic32_get_port ( sport ) ;
ret = pic32_enable_clock ( sport ) ;
if ( ret )
return ret ;
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
return uart_set_options ( port , co , baud , parity , bits , flow ) ;
}
static struct uart_driver pic32_uart_driver ;
static struct console pic32_console = {
. name = PIC32_SDEV_NAME ,
. write = pic32_console_write ,
. device = uart_console_device ,
. setup = pic32_console_setup ,
. flags = CON_PRINTBUFFER ,
. index = - 1 ,
. data = & pic32_uart_driver ,
} ;
# define PIC32_SCONSOLE (&pic32_console)
static int __init pic32_console_init ( void )
{
register_console ( & pic32_console ) ;
return 0 ;
}
console_initcall ( pic32_console_init ) ;
static inline bool is_pic32_console_port ( struct uart_port * port )
{
return port - > cons & & port - > cons - > index = = port - > line ;
}
/*
* Late console initialization .
*/
static int __init pic32_late_console_init ( void )
{
if ( ! ( pic32_console . flags & CON_ENABLED ) )
register_console ( & pic32_console ) ;
return 0 ;
}
core_initcall ( pic32_late_console_init ) ;
# else
# define PIC32_SCONSOLE NULL
# endif
static struct uart_driver pic32_uart_driver = {
. owner = THIS_MODULE ,
. driver_name = PIC32_DEV_NAME ,
. dev_name = PIC32_SDEV_NAME ,
. nr = PIC32_MAX_UARTS ,
. cons = PIC32_SCONSOLE ,
} ;
static int pic32_uart_probe ( struct platform_device * pdev )
{
struct device_node * np = pdev - > dev . of_node ;
struct pic32_sport * sport ;
int uart_idx = 0 ;
struct resource * res_mem ;
struct uart_port * port ;
int ret ;
uart_idx = of_alias_get_id ( np , " serial " ) ;
if ( uart_idx < 0 | | uart_idx > = PIC32_MAX_UARTS )
return - EINVAL ;
res_mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res_mem )
return - EINVAL ;
sport = devm_kzalloc ( & pdev - > dev , sizeof ( * sport ) , GFP_KERNEL ) ;
if ( ! sport )
return - ENOMEM ;
sport - > idx = uart_idx ;
sport - > irq_fault = irq_of_parse_and_map ( np , 0 ) ;
sport - > irqflags_fault = IRQF_NO_THREAD ;
sport - > irq_rx = irq_of_parse_and_map ( np , 1 ) ;
sport - > irqflags_rx = IRQF_NO_THREAD ;
sport - > irq_tx = irq_of_parse_and_map ( np , 2 ) ;
sport - > irqflags_tx = IRQF_NO_THREAD ;
sport - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
sport - > cts_gpio = - EINVAL ;
sport - > dev = & pdev - > dev ;
/* Hardware flow control: gpios
* ! Note : Basically , CTS is needed for reading the status .
*/
sport - > hw_flow_ctrl = false ;
sport - > cts_gpio = of_get_named_gpio ( np , " cts-gpios " , 0 ) ;
if ( gpio_is_valid ( sport - > cts_gpio ) ) {
sport - > hw_flow_ctrl = true ;
ret = devm_gpio_request ( sport - > dev ,
sport - > cts_gpio , " CTS " ) ;
if ( ret ) {
dev_err ( & pdev - > dev ,
" error requesting CTS GPIO \n " ) ;
goto err ;
}
ret = gpio_direction_input ( sport - > cts_gpio ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " error setting CTS GPIO \n " ) ;
goto err ;
}
}
pic32_sports [ uart_idx ] = sport ;
port = & sport - > port ;
memset ( port , 0 , sizeof ( * port ) ) ;
port - > iotype = UPIO_MEM ;
port - > mapbase = res_mem - > start ;
port - > ops = & pic32_uart_ops ;
port - > flags = UPF_BOOT_AUTOCONF ;
port - > dev = & pdev - > dev ;
port - > fifosize = PIC32_UART_TX_FIFO_DEPTH ;
port - > uartclk = clk_get_rate ( sport - > clk ) ;
port - > line = uart_idx ;
ret = uart_add_one_port ( & pic32_uart_driver , port ) ;
if ( ret ) {
port - > membase = NULL ;
dev_err ( port - > dev , " %s: uart add port error! \n " , __func__ ) ;
goto err ;
}
# ifdef CONFIG_SERIAL_PIC32_CONSOLE
if ( is_pic32_console_port ( port ) & &
( pic32_console . flags & CON_ENABLED ) ) {
/* The peripheral clock has been enabled by console_setup,
* so disable it till the port is used .
*/
pic32_disable_clock ( sport ) ;
}
# endif
platform_set_drvdata ( pdev , port ) ;
dev_info ( & pdev - > dev , " %s: uart(%d) driver initialized. \n " ,
__func__ , uart_idx ) ;
return 0 ;
err :
/* automatic unroll of sport and gpios */
return ret ;
}
static int pic32_uart_remove ( struct platform_device * pdev )
{
struct uart_port * port = platform_get_drvdata ( pdev ) ;
struct pic32_sport * sport = to_pic32_sport ( port ) ;
uart_remove_one_port ( & pic32_uart_driver , port ) ;
pic32_disable_clock ( sport ) ;
platform_set_drvdata ( pdev , NULL ) ;
pic32_sports [ sport - > idx ] = NULL ;
/* automatic unroll of sport and gpios */
return 0 ;
}
static const struct of_device_id pic32_serial_dt_ids [ ] = {
{ . compatible = " microchip,pic32mzda-uart " } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , pic32_serial_dt_ids ) ;
static struct platform_driver pic32_uart_platform_driver = {
. probe = pic32_uart_probe ,
. remove = pic32_uart_remove ,
. driver = {
. name = PIC32_DEV_NAME ,
. of_match_table = of_match_ptr ( pic32_serial_dt_ids ) ,
2018-10-30 12:35:44 +01:00
. suppress_bind_attrs = IS_BUILTIN ( CONFIG_SERIAL_PIC32 ) ,
2016-01-13 18:15:43 -07:00
} ,
} ;
static int __init pic32_uart_init ( void )
{
int ret ;
ret = uart_register_driver ( & pic32_uart_driver ) ;
if ( ret ) {
pr_err ( " failed to register %s:%d \n " ,
pic32_uart_driver . driver_name , ret ) ;
return ret ;
}
ret = platform_driver_register ( & pic32_uart_platform_driver ) ;
if ( ret ) {
pr_err ( " fail to register pic32 uart \n " ) ;
uart_unregister_driver ( & pic32_uart_driver ) ;
}
return ret ;
}
arch_initcall ( pic32_uart_init ) ;
static void __exit pic32_uart_exit ( void )
{
# ifdef CONFIG_SERIAL_PIC32_CONSOLE
unregister_console ( & pic32_console ) ;
# endif
platform_driver_unregister ( & pic32_uart_platform_driver ) ;
uart_unregister_driver ( & pic32_uart_driver ) ;
}
module_exit ( pic32_uart_exit ) ;
MODULE_AUTHOR ( " Sorin-Andrei Pistirica <andrei.pistirica@microchip.com> " ) ;
MODULE_DESCRIPTION ( " Microchip PIC32 integrated serial port driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;