summaryrefslogtreecommitdiff
path: root/bsp/mini2440/drivers/uart.c
blob: 6226a3cb1775890fe506fd85206ded6d312ee200 (plain)
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
 * 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;
    int mask;

    RT_ASSERT(serial != RT_NULL); 
    uart = (struct hw_uart_device *)serial->parent.user_data;

    if(uart->irqno == INTUART0)
    {
        mask = BIT_SUB_RXD0;
    }
    else if(uart->irqno == INTUART1)
    {
        mask = BIT_SUB_RXD1;
    }
    else
    {
        mask = BIT_SUB_RXD2;
    }

    switch (cmd)
    {
    case RT_DEVICE_CTRL_CLR_INT:
        /* disable rx irq */
        INTSUBMSK |= mask;
		
        break;

    case RT_DEVICE_CTRL_SET_INT:
        /* enable rx irq */
        INTSUBMSK &= ~mask;
        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)
{
    /* UART0  UART1 UART2 port configure */
    GPHCON |= 0xAAAA;
    /* PULLUP is disable */
    GPHUP |= 0xFFF;

    /* 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 RT_EOK;
}

INIT_BOARD_EXPORT(rt_hw_uart_init);