uart.c 3.3 KB
Newer Older
A
ArcherChang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
#include <nds32_intrinsic.h>

#define DEFAULT_BAUDRATE	115200 /* 8n1 */

#define IN8(reg) 		(uint8_t)((*(volatile unsigned long *)(reg)) & 0x000000FF)
#define READ_CLR(reg) 	(*(volatile unsigned long *)(reg))

int drv_uart_set_baudrate(int baudrate)
{
	unsigned long baud_div;	/* baud rate divisor */
	unsigned long temp_word;

	baud_div = (MB_UCLK / (16 * baudrate));

	/* Save LCR temporary */
	temp_word = IN8(STUARTC_BASE + UARTC_LCR_OFFSET);

	/* Setup dlab bit for baud rate setting */
	OUT8(STUARTC_BASE + UARTC_LCR_OFFSET, (temp_word | UARTC_LCR_DLAB));

	/* Apply baud rate */
	OUT8(STUARTC_BASE + UARTC_DLM_OFFSET, (unsigned char)(baud_div >> 8));
	OUT8(STUARTC_BASE + UARTC_DLL_OFFSET, (unsigned char)baud_div);
	OUT8(STUARTC_BASE + UARTC_PSR_OFFSET, (unsigned char)1);

	/* Restore LCR */
	OUT8(STUARTC_BASE + UARTC_LCR_OFFSET, temp_word);
	
	return 0;
}

int drv_uart_is_kbd_hit(void)
{
	return IN8(STUARTC_BASE + UARTC_LSR_OFFSET) & UARTC_LSR_RDR;
}

int drv_uart_get_char(void)
{
	while (!(IN8(STUARTC_BASE + UARTC_LSR_OFFSET) & UARTC_LSR_RDR))
		;

	return IN8(STUARTC_BASE + UARTC_RBR_OFFSET);
}

void drv_uart_put_char(int ch)
{
	while (!(IN8(STUARTC_BASE + UARTC_LSR_OFFSET) & UARTC_LSR_THRE))
		;

	OUT8(STUARTC_BASE + UARTC_THR_OFFSET, ch);
}

int drv_uart_init(void)
{
	/* Clear everything */
	OUT8(STUARTC_BASE + UARTC_IER_OFFSET, 0x0);
	OUT8(STUARTC_BASE + UARTC_LCR_OFFSET, 0x0);

	/* Setup baud rate */
	drv_uart_set_baudrate(DEFAULT_BAUDRATE);

	/* Setup parity, data bits, and stop bits */
	OUT8(STUARTC_BASE + UARTC_LCR_OFFSET, \
			(UARTC_LCR_PARITY_NONE | UARTC_LCR_BITS8 | UARTC_LCR_STOP1));

	return 0;
}

/**********************************************
 *
 * Archer Chang
 *
 * driver API with reg base
 *
***********************************************/
int __drv_uart_set_baudrate(unsigned int regbase, int baudrate)
{
	unsigned long baud_div;	/* baud rate divisor */
	unsigned long temp_word;

	baud_div = (MB_UCLK / (16 * baudrate));

	/* Save LCR temporary */
	temp_word = IN8(regbase + UARTC_LCR_OFFSET);

	/* Setup dlab bit for baud rate setting */
	OUT8(regbase + UARTC_LCR_OFFSET, (temp_word | UARTC_LCR_DLAB));

	/* Apply baud rate */
	OUT8(regbase + UARTC_DLM_OFFSET, (unsigned char)(baud_div >> 8));
	OUT8(regbase + UARTC_DLL_OFFSET, (unsigned char)baud_div);
	OUT8(regbase + UARTC_PSR_OFFSET, (unsigned char)1);

	/* Restore LCR */
	OUT8(regbase + UARTC_LCR_OFFSET, temp_word);

	return 0;
}

int __drv_uart_is_kbd_hit(unsigned int regbase)
{
	return IN8(regbase + UARTC_LSR_OFFSET) & UARTC_LSR_RDR;
}

int __drv_uart_get_char(unsigned int regbase)
{
	while (!(IN8(regbase + UARTC_LSR_OFFSET) & UARTC_LSR_RDR))
		;

	return IN8(regbase + UARTC_RBR_OFFSET);
}

void __drv_uart_put_char(unsigned int regbase, int ch)
{
	while (!(IN8(regbase + UARTC_LSR_OFFSET) & UARTC_LSR_THRE))
		;

	OUT8(regbase + UARTC_THR_OFFSET, ch);
}

int __drv_uart_put_char_nowait(unsigned int regbase, int ch)
{
	OUT8(regbase + UARTC_THR_OFFSET, ch);

	return 1;
}

int __drv_uart_init(unsigned int regbase, int baudrate)
{
	/* Clear everything */
	OUT8(regbase + UARTC_IER_OFFSET, 0x0);
	OUT8(regbase + UARTC_LCR_OFFSET, 0x0);

	/* Setup baud rate */
	__drv_uart_set_baudrate(regbase, baudrate);

	/* Setup parity, data bits, and stop bits */
	OUT8(regbase + UARTC_LCR_OFFSET, \
			(UARTC_LCR_PARITY_NONE | UARTC_LCR_BITS8 | UARTC_LCR_STOP1));

	return 0;
}