summaryrefslogtreecommitdiff
path: root/bsp/mini2440/drivers/uart.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsp/mini2440/drivers/uart.c')
-rw-r--r--bsp/mini2440/drivers/uart.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/bsp/mini2440/drivers/uart.c b/bsp/mini2440/drivers/uart.c
new file mode 100644
index 0000000000..f7bf1d9461
--- /dev/null
+++ b/bsp/mini2440/drivers/uart.c
@@ -0,0 +1,183 @@
+/*
+ * File : uart.c
+ * Drivers for s3c2440 uarts.
+ * Change Logs:
+ * Date Author Notes
+ * 2020-04-09 Jonne Code refactoring for new bsp
+ */
+
+#include <rthw.h>
+#include <rtdevice.h>
+#include <board.h>
+
+#define ULCON_OFS 0x00
+#define UCON_OFS 0x04
+#define UFCON_OFS 0x08
+#define UMCON_OFS 0x0c
+#define UTRSTAT_OFS 0x10
+#define UERSTAT_OFS 0x14
+#define UFSTAT_OFS 0x18
+#define UMSTAT_OFS 0x1c
+#define UTXH_OFS 0x20
+#define URXH_OFS 0x24
+#define UBRDIV_OFS 0x28
+
+#define readl(addr) (*(volatile unsigned long *)(addr))
+#define writel(addr, value) (*(volatile unsigned long *)(addr) = value)
+
+#define PCLK_HZ 50000000
+
+struct hw_uart_device
+{
+ rt_uint32_t hw_base;
+ rt_uint32_t irqno;
+};
+
+static rt_err_t s3c2440_serial_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
+{
+ struct hw_uart_device* uart = serial->parent.user_data;
+
+ writel(uart->hw_base + UBRDIV_OFS, PCLK_HZ / (cfg->baud_rate * 16));
+
+ writel(uart->hw_base + ULCON_OFS, 0x03);// 8bit data, 1bit stop, No parity
+ writel(uart->hw_base + UCON_OFS, 0x05);
+ writel(uart->hw_base + UFCON_OFS, 0x00);
+ writel(uart->hw_base + UMCON_OFS, 0x00);
+
+ return RT_EOK;
+}
+
+static rt_err_t s3c2440_serial_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct hw_uart_device *uart;
+
+ RT_ASSERT(serial != RT_NULL);
+ uart = (struct hw_uart_device *)serial->parent.user_data;
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_CLR_INT:
+ /* disable rx irq */
+ INTSUBMSK |= BIT_SUB_RXD0;
+
+ break;
+
+ case RT_DEVICE_CTRL_SET_INT:
+ /* enable rx irq */
+ INTSUBMSK &= ~(BIT_SUB_RXD0);
+ break;
+ }
+
+ return RT_EOK;
+}
+static int s3c2440_putc(struct rt_serial_device *serial, char c)
+{
+ struct hw_uart_device* uart = serial->parent.user_data;
+
+ while(!(readl(uart->hw_base + UTRSTAT_OFS) & (1<<2)))
+ {
+ }
+
+ writel(uart->hw_base + UTXH_OFS, c);
+
+ return 0;
+
+
+}
+static int s3c2440_getc(struct rt_serial_device *serial)
+{
+ struct hw_uart_device* uart = serial->parent.user_data;
+ int ch = -1;
+
+ if(readl(uart->hw_base + UTRSTAT_OFS) & (1<<0))
+ {
+ ch = readl(uart->hw_base + URXH_OFS) & 0x000000FF;
+ }
+
+ return ch;
+}
+
+static void rt_hw_uart_isr(int irqno, void *param)
+{
+ struct rt_serial_device *serial = (struct rt_serial_device *)param;
+
+ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
+
+ /*clear SUBSRCPND*/
+ if(irqno == INTUART0)
+ {
+ SUBSRCPND = BIT_SUB_RXD0;
+ }
+ else if(irqno == INTUART1)
+ {
+ SUBSRCPND = BIT_SUB_RXD1;
+ }
+ else
+ {
+ SUBSRCPND = BIT_SUB_RXD2;
+ }
+}
+
+static struct rt_uart_ops s3c2440_uart_ops = {
+ .configure = s3c2440_serial_configure,
+ .control = s3c2440_serial_control,
+ .putc = s3c2440_putc,
+ .getc = s3c2440_getc
+};
+
+
+static struct rt_serial_device _serial0 = {
+ .ops = &s3c2440_uart_ops,
+ .config = RT_SERIAL_CONFIG_DEFAULT,
+ .serial_rx = NULL,
+ .serial_tx = NULL
+};
+static struct hw_uart_device _hwserial0 = {
+ .hw_base = 0x50000000,
+ .irqno = INTUART0
+};
+
+static struct rt_serial_device _serial1 = {
+ .ops = &s3c2440_uart_ops,
+ .config = RT_SERIAL_CONFIG_DEFAULT,
+ .serial_rx = NULL,
+ .serial_tx = NULL
+};
+static struct hw_uart_device _hwserial1 = {
+ .hw_base = 0x50004000,
+ .irqno = INTUART1
+};
+
+static struct rt_serial_device _serial2 = {
+ .ops = &s3c2440_uart_ops,
+ .config = RT_SERIAL_CONFIG_DEFAULT,
+ .serial_rx = NULL,
+ .serial_tx = NULL
+};
+static struct hw_uart_device _hwserial2 = {
+ .hw_base = 0x50008000,
+ .irqno = INTUART2
+};
+
+
+int rt_hw_uart_init(void)
+{
+ /* register UART0 device */
+ rt_hw_serial_register(&_serial0, "uart0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_hwserial0);
+ rt_hw_interrupt_install(_hwserial0.irqno, rt_hw_uart_isr, &_serial0, "uart0");
+ rt_hw_interrupt_umask(INTUART0);
+
+ /* register UART1 device */
+ rt_hw_serial_register(&_serial1, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_hwserial1);
+ rt_hw_interrupt_install(_hwserial1.irqno, rt_hw_uart_isr, &_serial1, "uart1");
+ rt_hw_interrupt_umask(INTUART1);
+
+ /* register UART2 device */
+ rt_hw_serial_register(&_serial2, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, &_hwserial2);
+ rt_hw_interrupt_install(_hwserial2.irqno, rt_hw_uart_isr, &_serial2, "uart2");
+ rt_hw_interrupt_umask(INTUART2);
+
+ return 0;
+}
+
+INIT_BOARD_EXPORT(rt_hw_uart_init);