/*
* WKIC Ltd.
* By David Tech
* DEMO Version :1.0 Data:2020-2-25
*
*
*
* 1. compiler warnings all changes
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/freezer.h>
#include <linux/timer.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
//#include <asm/mach/map.h>
#include <linux/regmap.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/unistd.h>
#include <uapi/asm/unistd.h>
#include <linux/termios.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/printk.h>
#include <linux/miscdevice.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/clk.h>
#include <linux/serial.h>
#include "wk2xxx.h"
//#define _DEBUG_RK_FUNCTION
//#define _DEBUG_WK_FUNCTION
//#define _DEBUG_WK_RX
//#define _DEBUG_WK_TX
//#define _DEBUG_WK_IRQ
//#define _DEBUG_WK_VALUE
//#define _DEBUG_WK_FIFO
//#define _DEBUG_WK_TEST
//#define WK_RS485_FUNCTION
//#define WK_FIFO_FUNCTION
#define CONFIG_DEVFS_FS
#define WK2XXX_PAGE1 1
#define WK2XXX_PAGE0 0
#define WK2XXX_STATUS_PE 1
#define WK2XXX_STATUS_FE 2
#define WK2XXX_STATUS_BRK 4
#define WK2XXX_STATUS_OE 8
/////////////////////////////////////////
/**RK3288 uart offset***/
#define UART1RK_RX 0x00
#define UART1RK_TX 0x00
#define UART1RK_DLL 0x00
#define UART1RK_DLH 0x04
#define UART1RK_IER 0x04
#define UART1RK_IIR 0x08
#define UART1RK_FCR 0x08
#define UART1RK_LCR 0x0C
#define UART1RK_MCR 0x10
#define UART1RK_LSR 0x14
#define UART1RK_MSR 0x18
#define UART1RK_SCR 0x1C
#define UART1RK_SRBR 0x30
#define UART1RK_STHR 0x30
#define UART1RK_FAR 0x70
#define UART1RK_TFR 0x74
#define UART1RK_RFW 0x78
#define UART1RK_USR 0x7C
#define UART1RK_TFL 0x80
#define UART1RK_RFL 0x84
#define UART1RK_SRR 0x88
#define UART1RK_SRTS 0x8C
#define UART1RK_SBCR 0x90
#define UART1RK_SDMAM 0x94
#define UART1RK_SFE 0x98
#define UART1RK_SRT 0x9C
#define UART1RK_STET 0xA0
#define UART1RK_HTX 0xA4
#define UART1RK_DMASA 0xA8
#define UART1RK_CPR 0xF4
#define UART1RK_UCV 0xF8
#define UART1RK_CTR 0xFC
/***************************/
static DEFINE_MUTEX(wk2xxxs_lock); /* race on probe */
static DEFINE_MUTEX(wk2xxxs_wr_lock);
static DEFINE_MUTEX(wk2xxs_work_lock); /* work on probe */
static DEFINE_MUTEX(wk2xxxs_global_lock);
////static struct uart_driver rk_uart_reg;
/************************ROCHCHIP*************START*************************/
#define CONFIG_CLOCK_CTRL
#define PORT_RK 90
#define DBG_PORT 1 //DBG_PORT which uart is used to print log message
#ifdef CONFIG_OF
struct of_rk_serial {
unsigned int id;
unsigned int use_dma;
unsigned int uartclk;
unsigned int uartbaud;
};
#endif
struct uart_rk_port {
struct uart_port port;
struct platform_device *pdev;
struct clk *clk;
struct clk *pclk;
unsigned int tx_loadsz; /* transmit fifo load size */
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned char iir;
unsigned char fcr;
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
unsigned char lsr_saved_flags;
#if 0
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
#endif
char name[16];
char fifo[64];
char fifo_size;
unsigned long port_activity;
struct work_struct uart_work;
struct work_struct uart_work_rx;
struct workqueue_struct *uart_wq;
struct rk_uart_dma *dma;
};
struct uart_rk_port *g_uart_port;;
static inline unsigned int serial_in(struct uart_rk_port *up, int offset)
{
//offset = offset << 2;
// printk(KERN_ALERT "%s! address=0x%x!!\n",__func__,up->port.membase + offset);
return __raw_readl(up->port.membase + offset);
}
/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
static inline void dwapb_save_out_value(struct uart_rk_port *up, int offset,
unsigned char value)
{
if (offset == UART1RK_LCR)
up->lcr = value;
}
/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
static inline void dwapb_check_clear_ier(struct uart_rk_port *up, int offset)
{
if (offset == UART1RK_TX || offset == UART1RK_IER)
serial_in(up, UART1RK_IER);
}
static inline void serial_out(struct uart_rk_port *up, int offset, unsigned char value)
{
dwapb_save_out_value(up, offset, value);
__raw_writel(value, up->port.membase + (offset ));
if (offset != UART1RK_TX)
dsb();
dwapb_check_clear_ier(up, offset);
}
/* Uart divisor latch read */
static inline int serial_dl_read(struct uart_rk_port *up)
{
return serial_in(up, UART1RK_DLL) | serial_in(up, UART1RK_DLH) << 8;
}
/* Uart divisor latch write */
static int serial_dl_write(struct uart_rk_port *up, unsigned int value)
{
unsigned int tmout = 100;
while(!(serial_in(up, UART1RK_LCR) & 0x80)){
if (--tmout == 0){
if(up->port.line != DBG_PORT)
printk(KERN_ALERT"set serial.%d baudrate fail with DLAB not set\n", up->port.line);
return -1;
}
}
tmout = 15000;
while(serial_in(up, UART1RK_USR) & 0x01){
if (--tmout == 0){
if(up->port.line != DBG_PORT)
printk(KERN_ALERT "set serial.%d baudrate timeout\n", up->port.line);
return -1;
}
udelay(1);
}
serial_out(up, UART1RK_DLL, value & 0xff);
serial_out(up, UART1RK_DLH, value >> 8 & 0xff);
return 0;
}
static int rk32_uart_dump_register(struct uart_rk_port *up)
{
unsigned int reg_value = 0;
reg_value =serial_dl_read(up);
printk(KERN_ALERT "%s!!--UART1RK_DLL and DLH =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_IER);
printk(KERN_ALERT "%s!!--UART1RK_IER =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_IIR);
printk(KERN_ALERT "%s!!--UART1RK_IIR =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_LSR);
printk(KERN_ALERT "%s!!--UART1RK_LSR =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_MSR);
printk(KERN_ALERT "%s!!--UART1RK_MSR =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_MCR);
printk(KERN_ALERT "%s!!--UART1RK_MCR =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_SCR);
printk(KERN_ALERT "%s!!--UART1RK_SCR =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_LCR);
printk(KERN_ALERT "%s!!--UART1RK_LCR =0x:%X-\n", __func__,reg_value);
reg_value = serial_in(up, UART1RK_USR);
printk(KERN_ALERT "%s!!--UART1RK_USR =0x:%X-\n", __func__,reg_value);
return 0;
}
static int serial_lcr_write(struct uart_rk_port *up, unsigned char value)
{
unsigned int tmout = 15000;
while(serial_in(up, UART1RK_USR) & 0X01){
if (--tmout == 0){
if(up->port.line != DBG_PORT)
printk(KERN_ALERT"set serial.%d lcr = 0x%02x timeout\n", up->port.line, value);
return -1;
}
udelay(1);
}
serial_out(up, UART1RK_LCR, value);
return 0;
}
void uart_putc(struct uart_rk_port *up,unsigned char ch)
{
int timeout=500;
while(!(serial_in(up, UART1RK_LSR)&0x40)&&timeout)
timeout--;
serial_out(up, UART1RK_TX ,ch);
t