source: mainline/uspace/srv/hw/char/s3c24xx_uart/s3c24xx_uart.c@ 24abb85d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 24abb85d was 24abb85d, checked in by Jakub Jermar <jakub@…>, 8 years ago

Remove SYS_DEVICE_ASSIGN_DEVNO

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup driver_serial
30 * @{
31 */
32/**
33 * @file
34 * @brief Samsung S3C24xx on-chip UART driver.
35 *
36 * This UART is present on the Samsung S3C24xx CPU (on the gta02 platform).
37 */
38
39#include <ddi.h>
40#include <loc.h>
41#include <ipc/char.h>
42#include <async.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <sysinfo.h>
46#include <errno.h>
47#include <inttypes.h>
48#include "s3c24xx_uart.h"
49
50#define NAME "s3c24ser"
51#define NAMESPACE "char"
52
53static irq_cmd_t uart_irq_cmds[] = {
54 {
55 .cmd = CMD_ACCEPT
56 }
57};
58
59static irq_code_t uart_irq_code = {
60 0,
61 NULL,
62 sizeof(uart_irq_cmds) / sizeof(irq_cmd_t),
63 uart_irq_cmds
64};
65
66/** S3C24xx UART instance structure */
67static s3c24xx_uart_t *uart;
68
69static void s3c24xx_uart_connection(ipc_callid_t, ipc_call_t *, void *);
70static void s3c24xx_uart_irq_handler(ipc_callid_t, ipc_call_t *, void *);
71static int s3c24xx_uart_init(s3c24xx_uart_t *);
72static void s3c24xx_uart_sendb(s3c24xx_uart_t *, uint8_t);
73
74int main(int argc, char *argv[])
75{
76 printf("%s: S3C24xx on-chip UART driver\n", NAME);
77
78 async_set_fallback_port_handler(s3c24xx_uart_connection, NULL);
79 int rc = loc_server_register(NAME);
80 if (rc != EOK) {
81 printf("%s: Unable to register server.\n", NAME);
82 return rc;
83 }
84
85 uart = malloc(sizeof(s3c24xx_uart_t));
86 if (uart == NULL)
87 return -1;
88
89 if (s3c24xx_uart_init(uart) != EOK)
90 return -1;
91
92 rc = loc_service_register(NAMESPACE "/" NAME, &uart->service_id);
93 if (rc != EOK) {
94 printf(NAME ": Unable to register device %s.\n",
95 NAMESPACE "/" NAME);
96 return -1;
97 }
98
99 printf(NAME ": Registered device %s.\n", NAMESPACE "/" NAME);
100
101 printf(NAME ": Accepting connections\n");
102 task_retval(0);
103 async_manager();
104
105 /* Not reached */
106 return 0;
107}
108
109/** Character device connection handler. */
110static void s3c24xx_uart_connection(ipc_callid_t iid, ipc_call_t *icall,
111 void *arg)
112{
113 /* Answer the IPC_M_CONNECT_ME_TO call. */
114 async_answer_0(iid, EOK);
115
116 while (true) {
117 ipc_call_t call;
118 ipc_callid_t callid = async_get_call(&call);
119 sysarg_t method = IPC_GET_IMETHOD(call);
120
121 if (!method) {
122 /* The other side has hung up. */
123 async_answer_0(callid, EOK);
124 return;
125 }
126
127 async_sess_t *sess =
128 async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
129 if (sess != NULL) {
130 if (uart->client_sess == NULL) {
131 uart->client_sess = sess;
132 async_answer_0(callid, EOK);
133 } else
134 async_answer_0(callid, ELIMIT);
135 } else {
136 switch (method) {
137 case CHAR_WRITE_BYTE:
138 printf(NAME ": write %" PRIun " to device\n",
139 IPC_GET_ARG1(call));
140 s3c24xx_uart_sendb(uart, (uint8_t) IPC_GET_ARG1(call));
141 async_answer_0(callid, EOK);
142 break;
143 default:
144 async_answer_0(callid, EINVAL);
145 }
146 }
147 }
148}
149
150static void s3c24xx_uart_irq_handler(ipc_callid_t iid, ipc_call_t *call,
151 void *arg)
152{
153 (void) iid;
154 (void) call;
155 (void) arg;
156
157 while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_RX_COUNT) != 0) {
158 uint32_t data = pio_read_32(&uart->io->urxh) & 0xff;
159 uint32_t status = pio_read_32(&uart->io->uerstat);
160
161 if (uart->client_sess != NULL) {
162 async_exch_t *exch = async_exchange_begin(uart->client_sess);
163 async_msg_1(exch, CHAR_NOTIF_BYTE, data);
164 async_exchange_end(exch);
165 }
166
167 if (status != 0)
168 printf(NAME ": Error status 0x%x\n", status);
169 }
170}
171
172/** Initialize S3C24xx on-chip UART. */
173static int s3c24xx_uart_init(s3c24xx_uart_t *uart)
174{
175 void *vaddr;
176 sysarg_t inr;
177
178 if (sysinfo_get_value("s3c24xx_uart.address.physical",
179 &uart->paddr) != EOK)
180 return -1;
181
182 if (pio_enable((void *) uart->paddr, sizeof(s3c24xx_uart_io_t),
183 &vaddr) != 0)
184 return -1;
185
186 if (sysinfo_get_value("s3c24xx_uart.inr", &inr) != EOK)
187 return -1;
188
189 uart->io = vaddr;
190 uart->client_sess = NULL;
191
192 printf(NAME ": device at physical address %p, inr %" PRIun ".\n",
193 (void *) uart->paddr, inr);
194
195 async_irq_subscribe(inr, s3c24xx_uart_irq_handler, NULL, &uart_irq_code);
196
197 /* Enable FIFO, Tx trigger level: empty, Rx trigger level: 1 byte. */
198 pio_write_32(&uart->io->ufcon, UFCON_FIFO_ENABLE |
199 UFCON_TX_FIFO_TLEVEL_EMPTY | UFCON_RX_FIFO_TLEVEL_1B);
200
201 /* Set RX interrupt to pulse mode */
202 pio_write_32(&uart->io->ucon,
203 pio_read_32(&uart->io->ucon) & ~UCON_RX_INT_LEVEL);
204
205 return EOK;
206}
207
208/** Send a byte to the UART. */
209static void s3c24xx_uart_sendb(s3c24xx_uart_t *uart, uint8_t byte)
210{
211 /* Wait for space becoming available in Tx FIFO. */
212 while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_TX_FULL) != 0)
213 ;
214
215 pio_write_32(&uart->io->utxh, byte);
216}
217
218/** @}
219 */
Note: See TracBrowser for help on using the repository browser.