Harald Welte | 4aab33f | 2019-09-28 23:19:31 +0200 | [diff] [blame^] | 1 | /* 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 | |
| 16 | static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL}; |
| 17 | |
| 18 | extern struct card_uart *cuart4slot_nr(uint8_t slot_nr); |
| 19 | |
| 20 | /*********************************************************************** |
| 21 | * low-level helper routines |
| 22 | ***********************************************************************/ |
| 23 | |
| 24 | static 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 | |
| 43 | static 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 */ |
| 54 | static void SIM0_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 55 | { |
| 56 | _SIM_rx_cb(io_descr, 0); |
| 57 | } |
| 58 | static void SIM1_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 59 | { |
| 60 | _SIM_rx_cb(io_descr, 1); |
| 61 | } |
| 62 | static void SIM2_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 63 | { |
| 64 | _SIM_rx_cb(io_descr, 2); |
| 65 | } |
| 66 | static void SIM3_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 67 | { |
| 68 | _SIM_rx_cb(io_descr, 3); |
| 69 | } |
| 70 | static void SIM4_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 71 | { |
| 72 | _SIM_rx_cb(io_descr, 4); |
| 73 | } |
| 74 | static void SIM5_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 75 | { |
| 76 | _SIM_rx_cb(io_descr, 5); |
| 77 | } |
| 78 | static void SIM6_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 79 | { |
| 80 | _SIM_rx_cb(io_descr, 6); |
| 81 | } |
| 82 | static void SIM7_rx_cb(const struct usart_async_descriptor *const io_descr) |
| 83 | { |
| 84 | _SIM_rx_cb(io_descr, 7); |
| 85 | } |
| 86 | static 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 | }; |
| 90 | static void SIM0_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 91 | { |
| 92 | _SIM_tx_cb(io_descr, 0); |
| 93 | } |
| 94 | static void SIM1_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 95 | { |
| 96 | _SIM_tx_cb(io_descr, 1); |
| 97 | } |
| 98 | static void SIM2_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 99 | { |
| 100 | _SIM_tx_cb(io_descr, 2); |
| 101 | } |
| 102 | static void SIM3_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 103 | { |
| 104 | _SIM_tx_cb(io_descr, 3); |
| 105 | } |
| 106 | static void SIM4_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 107 | { |
| 108 | _SIM_tx_cb(io_descr, 4); |
| 109 | } |
| 110 | static void SIM5_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 111 | { |
| 112 | _SIM_tx_cb(io_descr, 5); |
| 113 | } |
| 114 | static void SIM6_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 115 | { |
| 116 | _SIM_tx_cb(io_descr, 6); |
| 117 | } |
| 118 | static void SIM7_tx_cb(const struct usart_async_descriptor *const io_descr) |
| 119 | { |
| 120 | _SIM_tx_cb(io_descr, 7); |
| 121 | } |
| 122 | static 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 */ |
| 132 | static struct card_uart_driver asf4_usart_driver; |
| 133 | static int asf4_usart_close(struct card_uart *cuart); |
| 134 | |
| 135 | static 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 | |
| 156 | static 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 | |
| 167 | static 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 | |
| 184 | static 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 | |
| 193 | static 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 | |
| 226 | static 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 | |
| 234 | static struct card_uart_driver asf4_usart_driver = { |
| 235 | .name = "asf4", |
| 236 | .ops = &asf4_usart_ops, |
| 237 | }; |
| 238 | |
| 239 | static __attribute__((constructor)) void on_dso_load_cuart_asf4(void) |
| 240 | { |
| 241 | card_uart_driver_register(&asf4_usart_driver); |
| 242 | } |