/****************************************************************************/
/* Copyright 2010, © Bendor Research Pty. Ltd. All rights reserved.			*/
/* Permission is granted to use this software for any purpose whatsoever	*/
/* as long as this copyright notice is preserved. The code is provided		*/
/* "as is", with no explicit, implicit or implied warranty or guarantee		*/
/* of any kind and Bendor Research Pty. Ltd. can not be held liable for		*/
/* any loss or damages arising out of the use of this software.				*/
/****************************************************************************/
/*																			*/
/*	Include file describing the Philips LPC23xx UARTS						*/
/*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~						*/
/*																			*/
/*	2010 Mar	ZK		Original											*/
/*	2010 May	ZK		Modified to match NXP's names						*/
/*																			*/
/****************************************************************************/

#ifndef _LPC23xx_SIO
#define _LPC23xx_SIO

/*
*	LPC23xx UART (a.k.a. SIO) registers
*/

struct lpc23xx_sio {

	union {

		unsigned rbr;				// 000 Receive buffer register
		unsigned thr;				// 000 Transmit holding register
		unsigned dll;				// 000 Divisor latch LSB
	};

	union {

		unsigned dlm;				// 004 Divisor latch MSB
		unsigned ier;				// 004 Interrupt enable register
	};

	union {

		unsigned iir;				// 008 Interrupt ID register
		unsigned fcr;				// 008 FIFO control register
	};

	unsigned lcr;					// 00c Line control register
	unsigned mcr;					// 010 Modem control register
	unsigned lsr;					// 014 Line status register
	unsigned msr;					// 018 Modem status register
	unsigned scr;					// 01c Scratch pad register
	unsigned acr;					// 020 Autobaud control register
	unsigned icr;					// 024 IrDA control register
	unsigned fdr;					// 028 Fractional divider register
	unsigned ___;
	unsigned ter;					// 030 Transmit enable register
};

/*
*	Definitions for the interrupt enable register
*/

#define	SIO_IER_ABTO		0x200	// Autobaud end interrupt
#define	SIO_IER_ABEO		0x100	// Autobaud timeout interrupt
#define	SIO_IER_CTS			0x080	// CTS transition interrupt
#define	SIO_IER_MS			0x008	// Modem status interrupt
#define	SIO_IER_RXL			0x004	// Receive line status interrupt
#define	SIO_IER_THRE		0x002	// Transmit FIFO interrupt
#define	SIO_IER_RBR			0x001	// Receive data ready interrupt

/*
*	Definitions for interrupt identification register
*/

#define	SIO_IIR_ABTO		0x200	// Autobaud timeout
#define	SIO_IIR_ABEO		0x100	// Autobaud end
#define	SIO_IIR_FIFO		0x040	// Copy of the FIFO enable bit
#define	SIO_IIR_INTID		0x00f	// Interrupt source mask
#define	SIO_IIR_INTID_RLS	0x006	// Receive line status (RX error) interrupt
#define	SIO_IIR_INTID_RDA	0x004	// Receive data ready interrupt
#define	SIO_IIR_INTID_CTI	0x00c	// Character timeout indicator interrupt
#define	SIO_IIR_INTID_THRE	0x002	// Transmit FIFO interrupt
#define	SIO_IIR_INTID_MODEM	0x000	// Modem interrupt
#define	SIO_IIR_STATUS		0x001	// No pending interrupt (yes, inverted!)

/*
*	Definitions for the FIFO control register
*/

#define	SIO_FCR_RX_TRIGG	0xc0	// Rx FIFO IRQ trigger mask
#define	SIO_FCR_RX_TRIGG_1	0x00	// Rx FIFO IRQ trigger after  1 character
#define	SIO_FCR_RX_TRIGG_4	0x40	// Rx FIFO IRQ trigger after  4 characters
#define	SIO_FCR_RX_TRIGG_8	0x80	// Rx FIFO IRQ trigger after  4 characters
#define	SIO_FCR_RX_TRIGG_14	0xc0	// Rx FIFO IRQ trigger after  4 characters
#define	SIO_FCR_TX_RESET	0x04	// Transmit FIFO reset
#define	SIO_FCR_RX_RESET	0x02	// Receive FIFO reset
#define	SIO_FCR_EN			0x01	// FIFO enable

/*
*	Definitions for the line control register
*/

#define	SIO_LCR_DLAB		0x80	// Divisor latch enable (data/irqe role)
#define	SIO_LCR_BREAK		0x40	// Send break
#define	SIO_LCR_PSEL		0x30	// Parity select mask
#define	SIO_LCR_PSEL_ODD	0x00	// Odd parity
#define	SIO_LCR_PSEL_EVEN	0x10	// Even parity
#define	SIO_LCR_PSEL_1		0x20	// Forced '1' parity
#define	SIO_LCR_PSEL_0		0x30	// Forced '0' parity
#define	SIO_LCR_PENA		0x08	// Parity enable
#define	SIO_LCR_STOP		0x04	// 2 stop bits
#define	SIO_LCR_WLEN		0x00	// Word length select mask
#define	SIO_LCR_WLEN_5		0x00	// Character is 5 bits long
#define	SIO_LCR_WLEN_6		0x01	// Character is 6 bits long
#define	SIO_LCR_WLEN_7		0x02	// Character is 7 bits long
#define	SIO_LCR_WLEN_8		0x03	// Character is 8 bits long

/*
*	Definitions for modem control register
*	This register exists only on UART 1
*/

#define	SIO_MCR_CTS_EN		0x80	// Enable CTS to control Tx	automatically
#define	SIO_MCR_RTS_EN		0x40	// Enable Tx to generate RTS automatically
#define	SIO_MCR_LOOP		0x10	// Loopback mode
#define	SIO_MCR_RTS			0x02	// Assert RTS (if not automatic)
#define	SIO_MCR_DTR			0x01	// Assert DTR

/*
*	Definitions for line status register
*/

#define	SIO_LSR_RXFE		0x80	// There is a char with error in Rx FIFO
#define	SIO_LSR_TEMT		0x40	// Transmit complete (all bits are out)
#define	SIO_LSR_THRE		0x20	// Transmit ready (to accept data)
#define	SIO_LSR_BI			0x10	// Break was detected
#define	SIO_LSR_FE			0x08	// Receive frame error
#define	SIO_LSR_PE			0x04	// Receive parity error
#define	SIO_LSR_OE			0x02	// Receive overrun error
#define	SIO_LSR_RDR			0x01	// Receive ready (char in buffer)

/*
*	Definitions for modem status register
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	This register exists only on UART 1
*/

#define	SIO_MSR_DCD			0x80	// Data carrier detect status
#define	SIO_MSR_RI			0x40	// Ring indicator status
#define	SIO_MSR_DSR			0x20	// Data set ready status
#define	SIO_MSR_CTS			0x10	// Clear to send status
#define	SIO_MSR_DDCD		0x08	// State change on DCD detected
#define	SIO_MSR_TERI		0x04	// Trailing edge on RI detected
#define	SIO_MSR_DDSR		0x02	// State change on DSR detected
#define	SIO_MSR_DCTS		0x01	// State change on CTS detected

/*
*	Definitions for the auto-baud control register
*/

#define	SIO_ACR_ABTOIC		0x200	// Autobaud timeout interrupt clear
#define	SIO_ACR_ABEOIC		0x100	// End of autobaud interrupt clear
#define	SIO_ACR_AUTO_RES	0x004	// Automatic restart on timeout
#define	SIO_ACR_MODE		0x002	// Mode select
#define	SIO_ACR_START		0x001	// Start

/*
*	Definitions for the transmit enable register
*/

#define	SIO_TER_TXEN		0x80	// Transmitter is enabled

/*
*	Definition for the baud rate divisor registers
*	There are two registers involved, one is the eight bit fractional
*	divider register and the other is the 16-bit divisor latch.
*	The latter is located at the data and interrupt enable registers
*	(Little-Endian fashion) when the DLAB bit in the line control
*	register is set (typical Intel logic). Now the actual baud rate
*	is calculated as follows:
*
*			     PCLK					  MUL
*	BR = --------------------------- * ---------
*		 ( ( DLM << 8 ) + DLL ) << 4   MUL + ADD
*
*	where
*		PCLK	is the clock frequency (UART's clock)
*		DLM		is the "MSB" of the divisor latch
*		DLL		is the "LSB" of the divisor latch
*		MUL		is the lower nibble of the fractional divider register
*		ADD		is the upper nibble of the fractional divider register
*/

#define	SIO_DLL(n)		((n)&255)
#define	SIO_DLM(n)		(((n)>>8)&255)
#define	SIO_FDR(m,a)	(((a)&15)|(((m)<<4)&240))

/*
*	Definitions for the IrDA control register
*	This register exists only on UART 3
*/

#define	SIO_ICR_EN			0x01	// Enable IrDA mode
#define	SIO_ICR_INV			0x02	// Invert serial input (but not output!)
#define	SIO_ICR_FIX_PULSE	0x04	// Use fixed pulse width mode
#define	SIO_ICR_PDIV		0x38	// Pulse width select mask
#define	SIO_ICR_PDIV_2		0x00	// Fixed pulse width is Tpclk * 2
#define	SIO_ICR_PDIV_4		0x08	// Fixed pulse width is Tpclk * 4
#define	SIO_ICR_PDIV_8		0x10	// Fixed pulse width is Tpclk * 8
#define	SIO_ICR_PDIV_16		0x18	// Fixed pulse width is Tpclk * 16
#define	SIO_ICR_PDIV_32		0x20	// Fixed pulse width is Tpclk * 32
#define	SIO_ICR_PDIV_64		0x28	// Fixed pulse width is Tpclk * 64
#define	SIO_ICR_PDIV_128	0x30	// Fixed pulse width is Tpclk * 128
#define	SIO_ICR_PDIV_256	0x38	// Fixed pulse width is Tpclk * 256

/*
*	Instances of the UARTS
*/

static volatile struct lpc23xx_sio * const lpc_sio0 = (void *) 0xe000c000;
static volatile struct lpc23xx_sio * const lpc_sio1 = (void *) 0xe0010000;
static volatile struct lpc23xx_sio * const lpc_sio2 = (void *) 0xe0078000;
static volatile struct lpc23xx_sio * const lpc_sio3 = (void *) 0xe007c000;

#endif

