blob: 3be0d6536b0933bef84baf537e67e78b7bf104b0 [file] [log] [blame]
Harald Welte4aab33f2019-09-28 23:19:31 +02001/* Card (ICC) UART driver for the Atmel ASF4 asynchronous USART */
2
3#include <errno.h>
4
5#include <osmocom/core/linuxlist.h>
6#include <osmocom/core/utils.h>
7
8#include <hal_usart_async.h>
9#include <utils_ringbuffer.h>
10#include "driver_init.h"
11
12#include "ncn8025.h"
13
14#include "cuart.h"
15
16static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL};
17
18extern struct card_uart *cuart4slot_nr(uint8_t slot_nr);
19
20/***********************************************************************
21 * low-level helper routines
22 ***********************************************************************/
23
24static void _SIM_rx_cb(const struct usart_async_descriptor *const io_descr, uint8_t slot_nr)
25{
26 struct card_uart *cuart = cuart4slot_nr(slot_nr);
27 int rc;
28 OSMO_ASSERT(cuart);
29
30 if (cuart->rx_threshold == 1) {
31 /* bypass ringbuffer and report byte directly */
32 uint8_t rx[1];
33 rc = io_read((struct io_descriptor * const)&io_descr->io, rx, sizeof(rx));
34 OSMO_ASSERT(rc == sizeof(rx));
35 card_uart_notification(cuart, CUART_E_RX_SINGLE, rx);
36 } else {
37 /* go via ringbuffer and notify only after threshold */
38 if (ringbuffer_num(&io_descr->rx) >= cuart->rx_threshold)
39 card_uart_notification(cuart, CUART_E_RX_COMPLETE, NULL);
40 }
41}
42
43static void _SIM_tx_cb(const struct usart_async_descriptor *const io_descr, uint8_t slot_nr)
44{
45 struct card_uart *cuart = cuart4slot_nr(slot_nr);
46 OSMO_ASSERT(cuart);
47 card_uart_notification(cuart, CUART_E_TX_COMPLETE, io_descr->tx_buffer);
48}
49
50
51/* the below ugli-ness is required as the usart_async_descriptor doesn't have
52 * some kind of 'private' member that could provide the call-back anty kind of
53 * context */
54static void SIM0_rx_cb(const struct usart_async_descriptor *const io_descr)
55{
56 _SIM_rx_cb(io_descr, 0);
57}
58static void SIM1_rx_cb(const struct usart_async_descriptor *const io_descr)
59{
60 _SIM_rx_cb(io_descr, 1);
61}
62static void SIM2_rx_cb(const struct usart_async_descriptor *const io_descr)
63{
64 _SIM_rx_cb(io_descr, 2);
65}
66static void SIM3_rx_cb(const struct usart_async_descriptor *const io_descr)
67{
68 _SIM_rx_cb(io_descr, 3);
69}
70static void SIM4_rx_cb(const struct usart_async_descriptor *const io_descr)
71{
72 _SIM_rx_cb(io_descr, 4);
73}
74static void SIM5_rx_cb(const struct usart_async_descriptor *const io_descr)
75{
76 _SIM_rx_cb(io_descr, 5);
77}
78static void SIM6_rx_cb(const struct usart_async_descriptor *const io_descr)
79{
80 _SIM_rx_cb(io_descr, 6);
81}
82static void SIM7_rx_cb(const struct usart_async_descriptor *const io_descr)
83{
84 _SIM_rx_cb(io_descr, 7);
85}
86static usart_cb_t SIM_rx_cb[8] = {
87 SIM0_rx_cb, SIM1_rx_cb, SIM2_rx_cb, SIM3_rx_cb,
88 SIM4_rx_cb, SIM5_rx_cb, SIM6_rx_cb, SIM7_rx_cb,
89};
90static void SIM0_tx_cb(const struct usart_async_descriptor *const io_descr)
91{
92 _SIM_tx_cb(io_descr, 0);
93}
94static void SIM1_tx_cb(const struct usart_async_descriptor *const io_descr)
95{
96 _SIM_tx_cb(io_descr, 1);
97}
98static void SIM2_tx_cb(const struct usart_async_descriptor *const io_descr)
99{
100 _SIM_tx_cb(io_descr, 2);
101}
102static void SIM3_tx_cb(const struct usart_async_descriptor *const io_descr)
103{
104 _SIM_tx_cb(io_descr, 3);
105}
106static void SIM4_tx_cb(const struct usart_async_descriptor *const io_descr)
107{
108 _SIM_tx_cb(io_descr, 4);
109}
110static void SIM5_tx_cb(const struct usart_async_descriptor *const io_descr)
111{
112 _SIM_tx_cb(io_descr, 5);
113}
114static void SIM6_tx_cb(const struct usart_async_descriptor *const io_descr)
115{
116 _SIM_tx_cb(io_descr, 6);
117}
118static void SIM7_tx_cb(const struct usart_async_descriptor *const io_descr)
119{
120 _SIM_tx_cb(io_descr, 7);
121}
122static usart_cb_t SIM_tx_cb[8] = {
123 SIM0_tx_cb, SIM1_tx_cb, SIM2_tx_cb, SIM3_tx_cb,
124 SIM4_tx_cb, SIM5_tx_cb, SIM6_tx_cb, SIM7_tx_cb,
125};
126
127/***********************************************************************
128 * Interface with card_uart (cuart) core
129 ***********************************************************************/
130
131/* forward-declaration */
132static struct card_uart_driver asf4_usart_driver;
133static int asf4_usart_close(struct card_uart *cuart);
134
135static int asf4_usart_open(struct card_uart *cuart, const char *device_name)
136{
137 struct usart_async_descriptor *usa_pd;
138 int slot_nr = atoi(device_name);
139
140 if (slot_nr >= ARRAY_SIZE(SIM_peripheral_descriptors))
141 return -ENODEV;
142 usa_pd = SIM_peripheral_descriptors[slot_nr];
143 if (!usa_pd)
144 return -ENODEV;
145
146 cuart->u.asf4.usa_pd = usa_pd;
147 cuart->u.asf4.slot_nr = slot_nr;
148
149 usart_async_register_callback(usa_pd, USART_ASYNC_RXC_CB, SIM_rx_cb[slot_nr]);
150 usart_async_register_callback(usa_pd, USART_ASYNC_TXC_CB, SIM_tx_cb[slot_nr]);
151 usart_async_enable(usa_pd);
152
153 return 0;
154}
155
156static int asf4_usart_close(struct card_uart *cuart)
157{
158 struct usart_async_descriptor *usa_pd = cuart->u.asf4.usa_pd;
159
160 OSMO_ASSERT(cuart->driver == &asf4_usart_driver);
161
162 usart_async_disable(usa_pd);
163
164 return 0;
165}
166
167static int asf4_usart_async_tx(struct card_uart *cuart, const uint8_t *data, size_t len)
168{
169 struct usart_async_descriptor *usa_pd = cuart->u.asf4.usa_pd;
170 int rc;
171
172 OSMO_ASSERT(cuart->driver == &asf4_usart_driver);
173 OSMO_ASSERT(usart_async_is_tx_empty(usa_pd));
174
175 rc = io_write(&usa_pd->io, data, len);
176 if (rc < 0)
177 return rc;
178
179 cuart->tx_busy = true;
180
181 return rc;
182}
183
184static int asf4_usart_async_rx(struct card_uart *cuart, uint8_t *data, size_t len)
185{
186 struct usart_async_descriptor *usa_pd = cuart->u.asf4.usa_pd;
187
188 OSMO_ASSERT(cuart->driver == &asf4_usart_driver);
189
190 return io_read(&usa_pd->io, data, len);
191}
192
193static int asf4_usart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, int arg)
194{
195 struct ncn8025_settings settings;
196 Sercom *sercom = cuart->u.asf4.usa_pd->device.hw;
197
198 switch (ctl) {
199 case CUART_CTL_RX:
200 if (arg)
201 sercom->USART.CTRLB.bit.RXEN = 1;
202 else
203 sercom->USART.CTRLB.bit.RXEN = 0;
204 break;
205 case CUART_CTL_RST:
206 ncn8025_get(cuart->u.asf4.slot_nr, &settings);
207 settings.rstin = arg ? true : false;
208 ncn8025_set(cuart->u.asf4.slot_nr, &settings);
209 break;
210 case CUART_CTL_POWER:
211 ncn8025_get(cuart->u.asf4.slot_nr, &settings);
212 settings.cmdvcc = arg ? true : false;
213 ncn8025_set(cuart->u.asf4.slot_nr, &settings);
214 break;
215 case CUART_CTL_WTIME:
216 /* no driver-specific handling of this */
217 break;
218 case CUART_CTL_CLOCK:
219 /* FIXME */
220 default:
221 return -EINVAL;
222 }
223 return 0;
224}
225
226static const struct card_uart_ops asf4_usart_ops = {
227 .open = asf4_usart_open,
228 .close = asf4_usart_close,
229 .async_tx = asf4_usart_async_tx,
230 .async_rx = asf4_usart_async_rx,
231 .ctrl = asf4_usart_ctrl,
232};
233
234static struct card_uart_driver asf4_usart_driver = {
235 .name = "asf4",
236 .ops = &asf4_usart_ops,
237};
238
239static __attribute__((constructor)) void on_dso_load_cuart_asf4(void)
240{
241 card_uart_driver_register(&asf4_usart_driver);
242}