diff options
Diffstat (limited to 'bsp/mini2440/drivers/uart.c')
| -rw-r--r-- | bsp/mini2440/drivers/uart.c | 183 |
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); |
