uart.c 4.9 KB
Newer Older
J
Jonne 已提交
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
3
 *
4 5
 * SPDX-License-Identifier: Apache-2.0
 *
J
Jonne 已提交
6 7 8 9 10
 * Change Logs:
 * Date           Author       Notes
 * 2020-04-09     Jonne        Code refactoring for new bsp
 */

11
#include <stddef.h>
J
Jonne 已提交
12 13 14 15
#include <rthw.h>
#include <rtdevice.h>
#include <board.h>

16 17 18 19 20 21 22 23 24 25 26
#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
J
Jonne 已提交
27 28

#define readl(addr)             (*(volatile unsigned long *)(addr))
29
#define writel(addr, value)     (*(volatile unsigned long *)(addr) = value)
J
Jonne 已提交
30 31 32 33 34 35 36 37 38

#define PCLK_HZ                 50000000

struct hw_uart_device
{
    rt_uint32_t hw_base;
    rt_uint32_t irqno;
};

39
static rt_err_t s3c2440_serial_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
J
Jonne 已提交
40
{
41
    struct hw_uart_device *uart = serial->parent.user_data;
J
Jonne 已提交
42 43 44 45 46 47 48 49

    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);

50
    return RT_EOK;
J
Jonne 已提交
51 52 53 54
}

static rt_err_t s3c2440_serial_control(struct rt_serial_device *serial, int cmd, void *arg)
{
55
    struct hw_uart_device *uart;
56
    int mask;
J
Jonne 已提交
57

58
    RT_ASSERT(serial != RT_NULL);
J
Jonne 已提交
59 60
    uart = (struct hw_uart_device *)serial->parent.user_data;

61
    if (uart->irqno == INTUART0)
62 63 64
    {
        mask = BIT_SUB_RXD0;
    }
65
    else if (uart->irqno == INTUART1)
66 67 68 69 70 71 72 73
    {
        mask = BIT_SUB_RXD1;
    }
    else
    {
        mask = BIT_SUB_RXD2;
    }

J
Jonne 已提交
74 75 76 77
    switch (cmd)
    {
    case RT_DEVICE_CTRL_CLR_INT:
        /* disable rx irq */
78
        INTSUBMSK |= mask;
79

J
Jonne 已提交
80 81 82 83
        break;

    case RT_DEVICE_CTRL_SET_INT:
        /* enable rx irq */
84
        INTSUBMSK &= ~mask;
J
Jonne 已提交
85 86 87 88 89 90 91
        break;
    }

    return RT_EOK;
}
static int s3c2440_putc(struct rt_serial_device *serial, char c)
{
92
    struct hw_uart_device *uart = serial->parent.user_data;
J
Jonne 已提交
93

94
    while (!(readl(uart->hw_base + UTRSTAT_OFS) & (1 << 2)))
J
Jonne 已提交
95 96 97 98
    {
    }

    writel(uart->hw_base + UTXH_OFS, c);
99

J
Jonne 已提交
100 101
    return 0;

102

J
Jonne 已提交
103 104 105
}
static int s3c2440_getc(struct rt_serial_device *serial)
{
106
    struct hw_uart_device *uart = serial->parent.user_data;
J
Jonne 已提交
107 108
    int ch = -1;

109
    if (readl(uart->hw_base + UTRSTAT_OFS) & (1 << 0))
J
Jonne 已提交
110 111 112
    {
        ch = readl(uart->hw_base + URXH_OFS) & 0x000000FF;
    }
113

J
Jonne 已提交
114 115 116 117 118 119 120 121
    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);
122 123 124

    /*clear SUBSRCPND*/
    if (irqno == INTUART0)
J
Jonne 已提交
125 126
    {
        SUBSRCPND = BIT_SUB_RXD0;
127 128
    }
    else if (irqno == INTUART1)
J
Jonne 已提交
129 130 131
    {
        SUBSRCPND = BIT_SUB_RXD1;
    }
132
    else
J
Jonne 已提交
133 134 135 136 137
    {
        SUBSRCPND = BIT_SUB_RXD2;
    }
}

138 139 140 141 142 143
static struct rt_uart_ops s3c2440_uart_ops =
{
    .configure = s3c2440_serial_configure,
    .control = s3c2440_serial_control,
    .putc = s3c2440_putc,
    .getc = s3c2440_getc
J
Jonne 已提交
144 145 146
};


147 148 149 150 151 152
static struct rt_serial_device _serial0 =
{
    .ops = &s3c2440_uart_ops,
    .config = RT_SERIAL_CONFIG_DEFAULT,
    .serial_rx = NULL,
    .serial_tx = NULL
J
Jonne 已提交
153
};
154 155 156 157
static struct hw_uart_device _hwserial0 =
{
    .hw_base = 0x50000000,
    .irqno = INTUART0
J
Jonne 已提交
158 159
};

160 161 162 163 164 165
static struct rt_serial_device _serial1 =
{
    .ops = &s3c2440_uart_ops,
    .config = RT_SERIAL_CONFIG_DEFAULT,
    .serial_rx = NULL,
    .serial_tx = NULL
J
Jonne 已提交
166
};
167 168 169 170
static struct hw_uart_device _hwserial1 =
{
    .hw_base = 0x50004000,
    .irqno = INTUART1
J
Jonne 已提交
171 172
};

173 174 175 176 177 178
static struct rt_serial_device _serial2 =
{
    .ops = &s3c2440_uart_ops,
    .config = RT_SERIAL_CONFIG_DEFAULT,
    .serial_rx = NULL,
    .serial_tx = NULL
J
Jonne 已提交
179
};
180 181 182 183
static struct hw_uart_device _hwserial2 =
{
    .hw_base = 0x50008000,
    .irqno = INTUART2
J
Jonne 已提交
184 185 186 187 188
};


int rt_hw_uart_init(void)
{
189 190 191 192 193
    /* UART0  UART1 UART2 port configure */
    GPHCON |= 0xAAAA;
    /* PULLUP is disable */
    GPHUP |= 0xFFF;

J
Jonne 已提交
194 195 196 197
    /* 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);
198

J
Jonne 已提交
199 200 201 202 203 204 205 206 207 208
    /* 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);

J
Jonne 已提交
209
    return RT_EOK;
J
Jonne 已提交
210 211
}
INIT_BOARD_EXPORT(rt_hw_uart_init);
212