blob: f235115c34e2720d50a56a6415eddf9ffddb9cdb [file] [log] [blame]
Kévin Redon4cd3f7d2019-01-24 17:57:13 +01001
2/**
3 * \file
4 *
5 * \brief SAM Serial Communication Interface
6 *
7 * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
8 *
9 * \asf_license_start
10 *
11 * \page License
12 *
13 * Subject to your compliance with these terms, you may use Microchip
14 * software and any derivatives exclusively with Microchip products.
15 * It is your responsibility to comply with third party license terms applicable
16 * to your use of third party software (including open source software) that
17 * may accompany Microchip software.
18 *
19 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
21 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
22 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
23 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
24 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
25 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
26 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
27 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
28 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
29 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
30 *
31 * \asf_license_stop
32 *
33 */
34#include <hpl_dma.h>
35#include <hpl_i2c_m_async.h>
36#include <hpl_i2c_m_sync.h>
37#include <hpl_i2c_s_async.h>
38#include <hpl_sercom_config.h>
39#include <hpl_spi_m_async.h>
40#include <hpl_spi_m_sync.h>
41#include <hpl_spi_s_async.h>
42#include <hpl_spi_s_sync.h>
43#include <hpl_usart_async.h>
44#include <hpl_usart_sync.h>
45#include <utils.h>
46#include <utils_assert.h>
47
48#ifndef CONF_SERCOM_0_USART_ENABLE
49#define CONF_SERCOM_0_USART_ENABLE 0
50#endif
51#ifndef CONF_SERCOM_1_USART_ENABLE
52#define CONF_SERCOM_1_USART_ENABLE 0
53#endif
54#ifndef CONF_SERCOM_2_USART_ENABLE
55#define CONF_SERCOM_2_USART_ENABLE 0
56#endif
57#ifndef CONF_SERCOM_3_USART_ENABLE
58#define CONF_SERCOM_3_USART_ENABLE 0
59#endif
60#ifndef CONF_SERCOM_4_USART_ENABLE
61#define CONF_SERCOM_4_USART_ENABLE 0
62#endif
63#ifndef CONF_SERCOM_5_USART_ENABLE
64#define CONF_SERCOM_5_USART_ENABLE 0
65#endif
66#ifndef CONF_SERCOM_6_USART_ENABLE
67#define CONF_SERCOM_6_USART_ENABLE 0
68#endif
69#ifndef CONF_SERCOM_7_USART_ENABLE
70#define CONF_SERCOM_7_USART_ENABLE 0
71#endif
72
73/** Amount of SERCOM that is used as USART. */
74#define SERCOM_USART_AMOUNT \
75 (CONF_SERCOM_0_USART_ENABLE + CONF_SERCOM_1_USART_ENABLE + CONF_SERCOM_2_USART_ENABLE + CONF_SERCOM_3_USART_ENABLE \
76 + CONF_SERCOM_4_USART_ENABLE + CONF_SERCOM_5_USART_ENABLE + CONF_SERCOM_6_USART_ENABLE \
77 + CONF_SERCOM_7_USART_ENABLE)
78
79/**
80 * \brief Macro is used to fill usart configuration structure based on
81 * its number
82 *
83 * \param[in] n The number of structures
84 */
85#define SERCOM_CONFIGURATION(n) \
86 { \
87 n, \
88 SERCOM_USART_CTRLA_MODE(CONF_SERCOM_##n##_USART_MODE) \
89 | (CONF_SERCOM_##n##_USART_RUNSTDBY << SERCOM_USART_CTRLA_RUNSTDBY_Pos) \
90 | (CONF_SERCOM_##n##_USART_IBON << SERCOM_USART_CTRLA_IBON_Pos) \
91 | (CONF_SERCOM_##n##_USART_TXINV << SERCOM_USART_CTRLA_TXINV_Pos) \
92 | (CONF_SERCOM_##n##_USART_RXINV << SERCOM_USART_CTRLA_RXINV_Pos) \
93 | SERCOM_USART_CTRLA_SAMPR(CONF_SERCOM_##n##_USART_SAMPR) \
94 | SERCOM_USART_CTRLA_TXPO(CONF_SERCOM_##n##_USART_TXPO) \
95 | SERCOM_USART_CTRLA_RXPO(CONF_SERCOM_##n##_USART_RXPO) \
96 | SERCOM_USART_CTRLA_SAMPA(CONF_SERCOM_##n##_USART_SAMPA) \
97 | SERCOM_USART_CTRLA_FORM(CONF_SERCOM_##n##_USART_FORM) \
98 | (CONF_SERCOM_##n##_USART_CMODE << SERCOM_USART_CTRLA_CMODE_Pos) \
99 | (CONF_SERCOM_##n##_USART_CPOL << SERCOM_USART_CTRLA_CPOL_Pos) \
100 | (CONF_SERCOM_##n##_USART_DORD << SERCOM_USART_CTRLA_DORD_Pos), \
101 SERCOM_USART_CTRLB_CHSIZE(CONF_SERCOM_##n##_USART_CHSIZE) \
102 | (CONF_SERCOM_##n##_USART_SBMODE << SERCOM_USART_CTRLB_SBMODE_Pos) \
103 | (CONF_SERCOM_##n##_USART_CLODEN << SERCOM_USART_CTRLB_COLDEN_Pos) \
104 | (CONF_SERCOM_##n##_USART_SFDE << SERCOM_USART_CTRLB_SFDE_Pos) \
105 | (CONF_SERCOM_##n##_USART_ENC << SERCOM_USART_CTRLB_ENC_Pos) \
106 | (CONF_SERCOM_##n##_USART_PMODE << SERCOM_USART_CTRLB_PMODE_Pos) \
107 | (CONF_SERCOM_##n##_USART_TXEN << SERCOM_USART_CTRLB_TXEN_Pos) \
108 | (CONF_SERCOM_##n##_USART_RXEN << SERCOM_USART_CTRLB_RXEN_Pos), \
109 SERCOM_USART_CTRLC_GTIME(CONF_SERCOM_##n##_USART_GTIME) \
110 | (CONF_SERCOM_##n##_USART_DSNACK << SERCOM_USART_CTRLC_DSNACK_Pos) \
111 | (CONF_SERCOM_##n##_USART_INACK << SERCOM_USART_CTRLC_INACK_Pos) \
112 | SERCOM_USART_CTRLC_MAXITER(CONF_SERCOM_##n##_USART_MAXITER), \
113 (uint16_t)(CONF_SERCOM_##n##_USART_BAUD_RATE), CONF_SERCOM_##n##_USART_FRACTIONAL, \
114 CONF_SERCOM_##n##_USART_RECEIVE_PULSE_LENGTH, CONF_SERCOM_##n##_USART_DEBUG_STOP_MODE, \
115 }
116
117/**
118 * \brief SERCOM USART configuration type
119 */
120struct usart_configuration {
121 uint8_t number;
122 hri_sercomusart_ctrla_reg_t ctrl_a;
123 hri_sercomusart_ctrlb_reg_t ctrl_b;
124 hri_sercomusart_ctrlc_reg_t ctrl_c;
125 hri_sercomusart_baud_reg_t baud;
126 uint8_t fractional;
127 hri_sercomusart_rxpl_reg_t rxpl;
128 hri_sercomusart_dbgctrl_reg_t debug_ctrl;
129};
130
131#if SERCOM_USART_AMOUNT < 1
132/** Dummy array to pass compiling. */
133static struct usart_configuration _usarts[1] = {{0}};
134#else
135/**
136 * \brief Array of SERCOM USART configurations
137 */
138static struct usart_configuration _usarts[] = {
139#if CONF_SERCOM_0_USART_ENABLE == 1
140 SERCOM_CONFIGURATION(0),
141#endif
142#if CONF_SERCOM_1_USART_ENABLE == 1
143 SERCOM_CONFIGURATION(1),
144#endif
145#if CONF_SERCOM_2_USART_ENABLE == 1
146 SERCOM_CONFIGURATION(2),
147#endif
148#if CONF_SERCOM_3_USART_ENABLE == 1
149 SERCOM_CONFIGURATION(3),
150#endif
151#if CONF_SERCOM_4_USART_ENABLE == 1
152 SERCOM_CONFIGURATION(4),
153#endif
154#if CONF_SERCOM_5_USART_ENABLE == 1
155 SERCOM_CONFIGURATION(5),
156#endif
157#if CONF_SERCOM_6_USART_ENABLE == 1
158 SERCOM_CONFIGURATION(6),
159#endif
160#if CONF_SERCOM_7_USART_ENABLE == 1
161 SERCOM_CONFIGURATION(7),
162#endif
163};
164#endif
165
Kévin Redon1f8ecef2019-01-31 13:36:12 +0100166static struct _usart_async_device *_sercom0_dev = NULL;
167
168static struct _usart_async_device *_sercom1_dev = NULL;
169
170static struct _usart_async_device *_sercom2_dev = NULL;
171
172static struct _usart_async_device *_sercom3_dev = NULL;
173
174static struct _usart_async_device *_sercom4_dev = NULL;
175
176static struct _usart_async_device *_sercom5_dev = NULL;
177
178static struct _usart_async_device *_sercom6_dev = NULL;
179
Kévin Redonba3a2fa2019-03-07 15:52:27 +0100180static struct _usart_async_device *_sercom7_dev = NULL;
181
Kévin Redon4cd3f7d2019-01-24 17:57:13 +0100182static uint8_t _get_sercom_index(const void *const hw);
183static uint8_t _sercom_get_irq_num(const void *const hw);
184static void _sercom_init_irq_param(const void *const hw, void *dev);
185static uint8_t _sercom_get_hardware_index(const void *const hw);
186
187static int32_t _usart_init(void *const hw);
188static inline void _usart_deinit(void *const hw);
189static uint16_t _usart_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
190 const enum usart_baud_rate_mode mode, const uint8_t fraction);
191static void _usart_set_baud_rate(void *const hw, const uint32_t baud_rate);
192static void _usart_set_data_order(void *const hw, const enum usart_data_order order);
193static void _usart_set_mode(void *const hw, const enum usart_mode mode);
194static void _usart_set_parity(void *const hw, const enum usart_parity parity);
195static void _usart_set_stop_bits(void *const hw, const enum usart_stop_bits stop_bits);
196static void _usart_set_character_size(void *const hw, const enum usart_character_size size);
197
198/**
199 * \brief Initialize synchronous SERCOM USART
200 */
201int32_t _usart_sync_init(struct _usart_sync_device *const device, void *const hw)
202{
203 ASSERT(device);
204
205 device->hw = hw;
206
207 return _usart_init(hw);
208}
209
210/**
211 * \brief Initialize asynchronous SERCOM USART
212 */
213int32_t _usart_async_init(struct _usart_async_device *const device, void *const hw)
214{
215 int32_t init_status;
216
217 ASSERT(device);
218
219 init_status = _usart_init(hw);
220 if (init_status) {
221 return init_status;
222 }
223 device->hw = hw;
224 _sercom_init_irq_param(hw, (void *)device);
225 uint8_t irq = _sercom_get_irq_num(hw);
226 for (uint32_t i = 0; i < 4; i++) {
227 NVIC_DisableIRQ((IRQn_Type)irq);
228 NVIC_ClearPendingIRQ((IRQn_Type)irq);
229 NVIC_EnableIRQ((IRQn_Type)irq);
230 irq++;
231 }
232 return ERR_NONE;
233}
234
235/**
236 * \brief De-initialize SERCOM USART
237 */
238void _usart_sync_deinit(struct _usart_sync_device *const device)
239{
240 _usart_deinit(device->hw);
241}
242
243/**
244 * \brief De-initialize SERCOM USART
245 */
246void _usart_async_deinit(struct _usart_async_device *const device)
247{
248 NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(device->hw));
249 _usart_deinit(device->hw);
250}
251
252/**
253 * \brief Calculate baud rate register value
254 */
255uint16_t _usart_sync_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
256 const enum usart_baud_rate_mode mode, const uint8_t fraction)
257{
258 return _usart_calculate_baud_rate(baud, clock_rate, samples, mode, fraction);
259}
260
261/**
262 * \brief Calculate baud rate register value
263 */
264uint16_t _usart_async_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
265 const enum usart_baud_rate_mode mode, const uint8_t fraction)
266{
267 return _usart_calculate_baud_rate(baud, clock_rate, samples, mode, fraction);
268}
269
270/**
271 * \brief Enable SERCOM module
272 */
273void _usart_sync_enable(struct _usart_sync_device *const device)
274{
275 hri_sercomusart_set_CTRLA_ENABLE_bit(device->hw);
276}
277
278/**
279 * \brief Enable SERCOM module
280 */
281void _usart_async_enable(struct _usart_async_device *const device)
282{
283 hri_sercomusart_set_CTRLA_ENABLE_bit(device->hw);
284}
285
286/**
287 * \brief Disable SERCOM module
288 */
289void _usart_sync_disable(struct _usart_sync_device *const device)
290{
291 hri_sercomusart_clear_CTRLA_ENABLE_bit(device->hw);
292}
293
294/**
295 * \brief Disable SERCOM module
296 */
297void _usart_async_disable(struct _usart_async_device *const device)
298{
299 hri_sercomusart_clear_CTRLA_ENABLE_bit(device->hw);
300}
301
302/**
303 * \brief Set baud rate
304 */
305void _usart_sync_set_baud_rate(struct _usart_sync_device *const device, const uint32_t baud_rate)
306{
307 _usart_set_baud_rate(device->hw, baud_rate);
308}
309
310/**
311 * \brief Set baud rate
312 */
313void _usart_async_set_baud_rate(struct _usart_async_device *const device, const uint32_t baud_rate)
314{
315 _usart_set_baud_rate(device->hw, baud_rate);
316}
317
318/**
319 * \brief Set data order
320 */
321void _usart_sync_set_data_order(struct _usart_sync_device *const device, const enum usart_data_order order)
322{
323 _usart_set_data_order(device->hw, order);
324}
325
326/**
327 * \brief Set data order
328 */
329void _usart_async_set_data_order(struct _usart_async_device *const device, const enum usart_data_order order)
330{
331 _usart_set_data_order(device->hw, order);
332}
333
334/**
335 * \brief Set mode
336 */
337void _usart_sync_set_mode(struct _usart_sync_device *const device, const enum usart_mode mode)
338{
339 _usart_set_mode(device->hw, mode);
340}
341
342/**
343 * \brief Set mode
344 */
345void _usart_async_set_mode(struct _usart_async_device *const device, const enum usart_mode mode)
346{
347 _usart_set_mode(device->hw, mode);
348}
349
350/**
351 * \brief Set parity
352 */
353void _usart_sync_set_parity(struct _usart_sync_device *const device, const enum usart_parity parity)
354{
355 _usart_set_parity(device->hw, parity);
356}
357
358/**
359 * \brief Set parity
360 */
361void _usart_async_set_parity(struct _usart_async_device *const device, const enum usart_parity parity)
362{
363 _usart_set_parity(device->hw, parity);
364}
365
366/**
367 * \brief Set stop bits mode
368 */
369void _usart_sync_set_stop_bits(struct _usart_sync_device *const device, const enum usart_stop_bits stop_bits)
370{
371 _usart_set_stop_bits(device->hw, stop_bits);
372}
373
374/**
375 * \brief Set stop bits mode
376 */
377void _usart_async_set_stop_bits(struct _usart_async_device *const device, const enum usart_stop_bits stop_bits)
378{
379 _usart_set_stop_bits(device->hw, stop_bits);
380}
381
382/**
383 * \brief Set character size
384 */
385void _usart_sync_set_character_size(struct _usart_sync_device *const device, const enum usart_character_size size)
386{
387 _usart_set_character_size(device->hw, size);
388}
389
390/**
391 * \brief Set character size
392 */
393void _usart_async_set_character_size(struct _usart_async_device *const device, const enum usart_character_size size)
394{
395 _usart_set_character_size(device->hw, size);
396}
397
398/**
399 * \brief Retrieve SERCOM usart status
400 */
401uint32_t _usart_sync_get_status(const struct _usart_sync_device *const device)
402{
403 return hri_sercomusart_read_STATUS_reg(device->hw);
404}
405
406/**
407 * \brief Retrieve SERCOM usart status
408 */
409uint32_t _usart_async_get_status(const struct _usart_async_device *const device)
410{
411 return hri_sercomusart_read_STATUS_reg(device->hw);
412}
413
414/**
415 * \brief Write a byte to the given SERCOM USART instance
416 */
417void _usart_sync_write_byte(struct _usart_sync_device *const device, uint8_t data)
418{
419 hri_sercomusart_write_DATA_reg(device->hw, data);
420}
421
422/**
423 * \brief Write a byte to the given SERCOM USART instance
424 */
425void _usart_async_write_byte(struct _usart_async_device *const device, uint8_t data)
426{
427 hri_sercomusart_write_DATA_reg(device->hw, data);
428}
429
430/**
431 * \brief Read a byte from the given SERCOM USART instance
432 */
433uint8_t _usart_sync_read_byte(const struct _usart_sync_device *const device)
434{
435 return hri_sercomusart_read_DATA_reg(device->hw);
436}
437
438/**
439 * \brief Check if USART is ready to send next byte
440 */
441bool _usart_sync_is_ready_to_send(const struct _usart_sync_device *const device)
442{
443 return hri_sercomusart_get_interrupt_DRE_bit(device->hw);
444}
445
446/**
447 * \brief Check if USART transmission complete
448 */
449bool _usart_sync_is_transmit_done(const struct _usart_sync_device *const device)
450{
451 return hri_sercomusart_get_interrupt_TXC_bit(device->hw);
452}
453
454/**
455 * \brief Check if USART is ready to send next byte
456 */
457bool _usart_async_is_byte_sent(const struct _usart_async_device *const device)
458{
459 return hri_sercomusart_get_interrupt_DRE_bit(device->hw);
460}
461
462/**
463 * \brief Check if there is data received by USART
464 */
465bool _usart_sync_is_byte_received(const struct _usart_sync_device *const device)
466{
467 return hri_sercomusart_get_interrupt_RXC_bit(device->hw);
468}
469
470/**
471 * \brief Set the state of flow control pins
472 */
473void _usart_sync_set_flow_control_state(struct _usart_sync_device *const device,
474 const union usart_flow_control_state state)
475{
476 (void)device;
477 (void)state;
478}
479
480/**
481 * \brief Set the state of flow control pins
482 */
483void _usart_async_set_flow_control_state(struct _usart_async_device *const device,
484 const union usart_flow_control_state state)
485{
486 (void)device;
487 (void)state;
488}
489
490/**
491 * \brief Retrieve the state of flow control pins
492 */
493union usart_flow_control_state _usart_sync_get_flow_control_state(const struct _usart_sync_device *const device)
494{
495 (void)device;
496 union usart_flow_control_state state;
497
498 state.value = 0;
499 state.bit.unavailable = 1;
500 return state;
501}
502
503/**
504 * \brief Retrieve the state of flow control pins
505 */
506union usart_flow_control_state _usart_async_get_flow_control_state(const struct _usart_async_device *const device)
507{
508 (void)device;
509 union usart_flow_control_state state;
510
511 state.value = 0;
512 state.bit.unavailable = 1;
513 return state;
514}
515
516/**
517 * \brief Enable data register empty interrupt
518 */
519void _usart_async_enable_byte_sent_irq(struct _usart_async_device *const device)
520{
521 hri_sercomusart_set_INTEN_DRE_bit(device->hw);
522}
523
524/**
525 * \brief Enable transmission complete interrupt
526 */
527void _usart_async_enable_tx_done_irq(struct _usart_async_device *const device)
528{
529 hri_sercomusart_set_INTEN_TXC_bit(device->hw);
530}
531
532/**
533 * \brief Retrieve ordinal number of the given sercom hardware instance
534 */
535static uint8_t _sercom_get_hardware_index(const void *const hw)
536{
537 Sercom *const sercom_modules[] = SERCOM_INSTS;
538 /* Find index for SERCOM instance. */
539 for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) {
540 if ((uint32_t)hw == (uint32_t)sercom_modules[i]) {
541 return i;
542 }
543 }
544 return 0;
545}
546
547/**
548 * \brief Retrieve ordinal number of the given SERCOM USART hardware instance
549 */
550uint8_t _usart_sync_get_hardware_index(const struct _usart_sync_device *const device)
551{
552 return _sercom_get_hardware_index(device->hw);
553}
554
555/**
556 * \brief Retrieve ordinal number of the given SERCOM USART hardware instance
557 */
558uint8_t _usart_async_get_hardware_index(const struct _usart_async_device *const device)
559{
560 return _sercom_get_hardware_index(device->hw);
561}
562
563/**
564 * \brief Enable/disable USART interrupt
565 */
566void _usart_async_set_irq_state(struct _usart_async_device *const device, const enum _usart_async_callback_type type,
567 const bool state)
568{
569 ASSERT(device);
570
571 if (USART_ASYNC_BYTE_SENT == type || USART_ASYNC_TX_DONE == type) {
572 hri_sercomusart_write_INTEN_DRE_bit(device->hw, state);
573 hri_sercomusart_write_INTEN_TXC_bit(device->hw, state);
574 } else if (USART_ASYNC_RX_DONE == type) {
575 hri_sercomusart_write_INTEN_RXC_bit(device->hw, state);
576 } else if (USART_ASYNC_ERROR == type) {
577 hri_sercomusart_write_INTEN_ERROR_bit(device->hw, state);
578 }
579}
580
581/**
Kévin Redonccbed0b2019-01-24 18:30:26 +0100582 * \internal Sercom interrupt handler
583 *
584 * \param[in] p The pointer to interrupt parameter
585 */
586static void _sercom_usart_interrupt_handler(struct _usart_async_device *device)
587{
588 void *hw = device->hw;
589
590 if (hri_sercomusart_get_interrupt_DRE_bit(hw) && hri_sercomusart_get_INTEN_DRE_bit(hw)) {
591 hri_sercomusart_clear_INTEN_DRE_bit(hw);
592 device->usart_cb.tx_byte_sent(device);
593 } else if (hri_sercomusart_get_interrupt_TXC_bit(hw) && hri_sercomusart_get_INTEN_TXC_bit(hw)) {
594 hri_sercomusart_clear_INTEN_TXC_bit(hw);
595 device->usart_cb.tx_done_cb(device);
596 } else if (hri_sercomusart_get_interrupt_RXC_bit(hw)) {
597 if (hri_sercomusart_read_STATUS_reg(hw)
598 & (SERCOM_USART_STATUS_PERR | SERCOM_USART_STATUS_FERR | SERCOM_USART_STATUS_BUFOVF
599 | SERCOM_USART_STATUS_ISF | SERCOM_USART_STATUS_COLL)) {
600 hri_sercomusart_clear_STATUS_reg(hw, SERCOM_USART_STATUS_MASK);
601 return;
602 }
603
604 device->usart_cb.rx_done_cb(device, hri_sercomusart_read_DATA_reg(hw));
605 } else if (hri_sercomusart_get_interrupt_ERROR_bit(hw)) {
606 uint32_t status;
607
608 hri_sercomusart_clear_interrupt_ERROR_bit(hw);
609 device->usart_cb.error_cb(device);
610 status = hri_sercomusart_read_STATUS_reg(hw);
611 hri_sercomusart_clear_STATUS_reg(hw, status);
612 }
613}
614
615/**
Kévin Redon4cd3f7d2019-01-24 17:57:13 +0100616 * \internal Retrieve ordinal number of the given sercom hardware instance
617 *
618 * \param[in] hw The pointer to hardware instance
619
620 * \return The ordinal number of the given sercom hardware instance
621 */
622static uint8_t _get_sercom_index(const void *const hw)
623{
624 uint8_t sercom_offset = _sercom_get_hardware_index(hw);
625 uint8_t i;
626
627 for (i = 0; i < ARRAY_SIZE(_usarts); i++) {
628 if (_usarts[i].number == sercom_offset) {
629 return i;
630 }
631 }
632
633 ASSERT(false);
634 return 0;
635}
636
637/**
638 * \brief Init irq param with the given sercom hardware instance
639 */
640static void _sercom_init_irq_param(const void *const hw, void *dev)
641{
Kévin Redonccbed0b2019-01-24 18:30:26 +0100642
Kévin Redon1f8ecef2019-01-31 13:36:12 +0100643 if (hw == SERCOM0) {
644 _sercom0_dev = (struct _usart_async_device *)dev;
645 }
646
647 if (hw == SERCOM1) {
648 _sercom1_dev = (struct _usart_async_device *)dev;
649 }
650
651 if (hw == SERCOM2) {
652 _sercom2_dev = (struct _usart_async_device *)dev;
653 }
654
655 if (hw == SERCOM3) {
656 _sercom3_dev = (struct _usart_async_device *)dev;
657 }
658
659 if (hw == SERCOM4) {
660 _sercom4_dev = (struct _usart_async_device *)dev;
661 }
662
663 if (hw == SERCOM5) {
664 _sercom5_dev = (struct _usart_async_device *)dev;
665 }
666
667 if (hw == SERCOM6) {
668 _sercom6_dev = (struct _usart_async_device *)dev;
669 }
Kévin Redonba3a2fa2019-03-07 15:52:27 +0100670
671 if (hw == SERCOM7) {
672 _sercom7_dev = (struct _usart_async_device *)dev;
673 }
Kévin Redon4cd3f7d2019-01-24 17:57:13 +0100674}
675
676/**
677 * \internal Initialize SERCOM USART
678 *
679 * \param[in] hw The pointer to hardware instance
680 *
681 * \return The status of initialization
682 */
683static int32_t _usart_init(void *const hw)
684{
685 uint8_t i = _get_sercom_index(hw);
686
687 if (!hri_sercomusart_is_syncing(hw, SERCOM_USART_SYNCBUSY_SWRST)) {
688 uint32_t mode = _usarts[i].ctrl_a & SERCOM_USART_CTRLA_MODE_Msk;
689 if (hri_sercomusart_get_CTRLA_reg(hw, SERCOM_USART_CTRLA_ENABLE)) {
690 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
691 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
692 }
693 hri_sercomusart_write_CTRLA_reg(hw, SERCOM_USART_CTRLA_SWRST | mode);
694 }
695 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_SWRST);
696
697 hri_sercomusart_write_CTRLA_reg(hw, _usarts[i].ctrl_a);
698 hri_sercomusart_write_CTRLB_reg(hw, _usarts[i].ctrl_b);
699 hri_sercomusart_write_CTRLC_reg(hw, _usarts[i].ctrl_c);
700 if ((_usarts[i].ctrl_a & SERCOM_USART_CTRLA_SAMPR(0x1)) || (_usarts[i].ctrl_a & SERCOM_USART_CTRLA_SAMPR(0x3))) {
701 ((Sercom *)hw)->USART.BAUD.FRAC.BAUD = _usarts[i].baud;
702 ((Sercom *)hw)->USART.BAUD.FRAC.FP = _usarts[i].fractional;
703 } else {
704 hri_sercomusart_write_BAUD_reg(hw, _usarts[i].baud);
705 }
706
707 hri_sercomusart_write_RXPL_reg(hw, _usarts[i].rxpl);
708 hri_sercomusart_write_DBGCTRL_reg(hw, _usarts[i].debug_ctrl);
709
710 return ERR_NONE;
711}
712
713/**
714 * \internal De-initialize SERCOM USART
715 *
716 * \param[in] hw The pointer to hardware instance
717 */
718static inline void _usart_deinit(void *const hw)
719{
720 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
721 hri_sercomusart_set_CTRLA_SWRST_bit(hw);
722}
723
724/**
725 * \internal Calculate baud rate register value
726 *
727 * \param[in] baud Required baud rate
728 * \param[in] clock_rate SERCOM clock frequency
729 * \param[in] samples The number of samples
730 * \param[in] mode USART mode
731 * \param[in] fraction A fraction value
732 *
733 * \return Calculated baud rate register value
734 */
735static uint16_t _usart_calculate_baud_rate(const uint32_t baud, const uint32_t clock_rate, const uint8_t samples,
736 const enum usart_baud_rate_mode mode, const uint8_t fraction)
737{
738 if (USART_BAUDRATE_ASYNCH_ARITHMETIC == mode) {
739 return 65536 - ((uint64_t)65536 * samples * baud) / clock_rate;
740 }
741
742 if (USART_BAUDRATE_ASYNCH_FRACTIONAL == mode) {
743 return clock_rate / baud / samples + SERCOM_USART_BAUD_FRACFP_FP(fraction);
744 }
745
746 if (USART_BAUDRATE_SYNCH == mode) {
747 return clock_rate / baud / 2 - 1;
748 }
749
750 return 0;
751}
752
753/**
754 * \internal Set baud rate
755 *
756 * \param[in] device The pointer to USART device instance
757 * \param[in] baud_rate A baud rate to set
758 */
759static void _usart_set_baud_rate(void *const hw, const uint32_t baud_rate)
760{
761 bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
762
763 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
764
765 CRITICAL_SECTION_ENTER()
766 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
767 hri_sercomusart_write_BAUD_reg(hw, baud_rate);
768 CRITICAL_SECTION_LEAVE()
769
770 hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
771}
772
773/**
774 * \internal Set data order
775 *
776 * \param[in] device The pointer to USART device instance
777 * \param[in] order A data order to set
778 */
779static void _usart_set_data_order(void *const hw, const enum usart_data_order order)
780{
781 bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
782
783 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
784
785 CRITICAL_SECTION_ENTER()
786 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
787 hri_sercomusart_write_CTRLA_DORD_bit(hw, order);
788 CRITICAL_SECTION_LEAVE()
789
790 hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
791}
792
793/**
794 * \internal Set mode
795 *
796 * \param[in] device The pointer to USART device instance
797 * \param[in] mode A mode to set
798 */
799static void _usart_set_mode(void *const hw, const enum usart_mode mode)
800{
801 bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
802
803 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
804
805 CRITICAL_SECTION_ENTER()
806 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
807 hri_sercomusart_write_CTRLA_CMODE_bit(hw, mode);
808 CRITICAL_SECTION_LEAVE()
809
810 hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
811}
812
813/**
814 * \internal Set parity
815 *
816 * \param[in] device The pointer to USART device instance
817 * \param[in] parity A parity to set
818 */
819static void _usart_set_parity(void *const hw, const enum usart_parity parity)
820{
821 bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
822
823 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
824
825 CRITICAL_SECTION_ENTER()
826 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
827
828 if (USART_PARITY_NONE != parity) {
829 hri_sercomusart_set_CTRLA_FORM_bf(hw, 1);
830 } else {
831 hri_sercomusart_clear_CTRLA_FORM_bf(hw, 1);
832 }
833
834 hri_sercomusart_write_CTRLB_PMODE_bit(hw, parity);
835 CRITICAL_SECTION_LEAVE()
836
837 hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
838}
839
840/**
841 * \internal Set stop bits mode
842 *
843 * \param[in] device The pointer to USART device instance
844 * \param[in] stop_bits A stop bits mode to set
845 */
846static void _usart_set_stop_bits(void *const hw, const enum usart_stop_bits stop_bits)
847{
848 bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
849
850 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
851
852 CRITICAL_SECTION_ENTER()
853 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
854 hri_sercomusart_write_CTRLB_SBMODE_bit(hw, stop_bits);
855 CRITICAL_SECTION_LEAVE()
856
857 hri_sercomusart_write_CTRLA_ENABLE_bit(hw, enabled);
858}
859
860/**
861 * \internal Set character size
862 *
863 * \param[in] device The pointer to USART device instance
864 * \param[in] size A character size to set
865 */
866static void _usart_set_character_size(void *const hw, const enum usart_character_size size)
867{
868 bool enabled = hri_sercomusart_get_CTRLA_ENABLE_bit(hw);
869
870 hri_sercomusart_clear_CTRLA_ENABLE_bit(hw);
871
872 CRITICAL_SECTION_ENTER()
873 hri_sercomusart_wait_for_sync(hw, SERCOM_USART_SYNCBUSY_ENABLE);
874 hri_sercomusart_write_CTRLB_CHSIZE_bf(hw, size);
875 CRITICAL_SECTION_LEAVE()
876
877 if (enabled) {
878 hri_sercomusart_set_CTRLA_ENABLE_bit(hw);
879 }
880}
881
882 /* Sercom I2C implementation */
883
884#ifndef CONF_SERCOM_0_I2CM_ENABLE
885#define CONF_SERCOM_0_I2CM_ENABLE 0
886#endif
887#ifndef CONF_SERCOM_1_I2CM_ENABLE
888#define CONF_SERCOM_1_I2CM_ENABLE 0
889#endif
890#ifndef CONF_SERCOM_2_I2CM_ENABLE
891#define CONF_SERCOM_2_I2CM_ENABLE 0
892#endif
893#ifndef CONF_SERCOM_3_I2CM_ENABLE
894#define CONF_SERCOM_3_I2CM_ENABLE 0
895#endif
896#ifndef CONF_SERCOM_4_I2CM_ENABLE
897#define CONF_SERCOM_4_I2CM_ENABLE 0
898#endif
899#ifndef CONF_SERCOM_5_I2CM_ENABLE
900#define CONF_SERCOM_5_I2CM_ENABLE 0
901#endif
902#ifndef CONF_SERCOM_6_I2CM_ENABLE
903#define CONF_SERCOM_6_I2CM_ENABLE 0
904#endif
905#ifndef CONF_SERCOM_7_I2CM_ENABLE
906#define CONF_SERCOM_7_I2CM_ENABLE 0
907#endif
908
909/** Amount of SERCOM that is used as I2C Master. */
910#define SERCOM_I2CM_AMOUNT \
911 (CONF_SERCOM_0_I2CM_ENABLE + CONF_SERCOM_1_I2CM_ENABLE + CONF_SERCOM_2_I2CM_ENABLE + CONF_SERCOM_3_I2CM_ENABLE \
912 + CONF_SERCOM_4_I2CM_ENABLE + CONF_SERCOM_5_I2CM_ENABLE + CONF_SERCOM_6_I2CM_ENABLE + CONF_SERCOM_7_I2CM_ENABLE)
913
914/**
915 * \brief Macro is used to fill i2cm configuration structure based on
916 * its number
917 *
918 * \param[in] n The number of structures
919 */
920#define I2CM_CONFIGURATION(n) \
921 { \
922 (n), \
923 (SERCOM_I2CM_CTRLA_MODE_I2C_MASTER) | (CONF_SERCOM_##n##_I2CM_RUNSTDBY << SERCOM_I2CM_CTRLA_RUNSTDBY_Pos) \
924 | (CONF_SERCOM_##n##_I2CM_SPEED << SERCOM_I2CM_CTRLA_SPEED_Pos) \
925 | (CONF_SERCOM_##n##_I2CM_MEXTTOEN << SERCOM_I2CM_CTRLA_MEXTTOEN_Pos) \
926 | (CONF_SERCOM_##n##_I2CM_SEXTTOEN << SERCOM_I2CM_CTRLA_SEXTTOEN_Pos) \
927 | (CONF_SERCOM_##n##_I2CM_INACTOUT << SERCOM_I2CM_CTRLA_INACTOUT_Pos) \
928 | (CONF_SERCOM_##n##_I2CM_LOWTOUT << SERCOM_I2CM_CTRLA_LOWTOUTEN_Pos) \
929 | (CONF_SERCOM_##n##_I2CM_SDAHOLD << SERCOM_I2CM_CTRLA_SDAHOLD_Pos), \
930 SERCOM_I2CM_CTRLB_SMEN, (uint32_t)(CONF_SERCOM_##n##_I2CM_BAUD_RATE), \
931 CONF_SERCOM_##n##_I2CM_DEBUG_STOP_MODE, CONF_SERCOM_##n##_I2CM_TRISE, CONF_GCLK_SERCOM##n##_CORE_FREQUENCY \
932 }
933
934#define ERROR_FLAG (1 << 7)
935#define SB_FLAG (1 << 1)
936#define MB_FLAG (1 << 0)
937
938#define CMD_STOP 0x3
939#define I2C_IDLE 0x1
940#define I2C_SM 0x0
941#define I2C_FM 0x1
942#define I2C_HS 0x2
943#define TEN_ADDR_FRAME 0x78
944#define TEN_ADDR_MASK 0x3ff
945#define SEVEN_ADDR_MASK 0x7f
946
947/**
948 * \brief SERCOM I2CM configuration type
949 */
950struct i2cm_configuration {
951 uint8_t number;
952 hri_sercomi2cm_ctrla_reg_t ctrl_a;
953 hri_sercomi2cm_ctrlb_reg_t ctrl_b;
954 hri_sercomi2cm_baud_reg_t baud;
955 hri_sercomi2cm_dbgctrl_reg_t dbgctrl;
956 uint16_t trise;
957 uint32_t clk; /* SERCOM peripheral clock frequency */
958};
959
960static inline void _i2c_m_enable_implementation(void *hw);
961static int32_t _i2c_m_sync_init_impl(struct _i2c_m_service *const service, void *const hw);
962
963#if SERCOM_I2CM_AMOUNT < 1
964/** Dummy array to pass compiling. */
965static struct i2cm_configuration _i2cms[1] = {{0}};
966#else
967/**
968 * \brief Array of SERCOM I2CM configurations
969 */
970static struct i2cm_configuration _i2cms[] = {
971#if CONF_SERCOM_0_I2CM_ENABLE == 1
972 I2CM_CONFIGURATION(0),
973#endif
974#if CONF_SERCOM_1_I2CM_ENABLE == 1
975 I2CM_CONFIGURATION(1),
976#endif
977#if CONF_SERCOM_2_I2CM_ENABLE == 1
978 I2CM_CONFIGURATION(2),
979#endif
980#if CONF_SERCOM_3_I2CM_ENABLE == 1
981 I2CM_CONFIGURATION(3),
982#endif
983#if CONF_SERCOM_4_I2CM_ENABLE == 1
984 I2CM_CONFIGURATION(4),
985#endif
986#if CONF_SERCOM_5_I2CM_ENABLE == 1
987 I2CM_CONFIGURATION(5),
988#endif
989#if CONF_SERCOM_6_I2CM_ENABLE == 1
990 I2CM_CONFIGURATION(6),
991#endif
992#if CONF_SERCOM_7_I2CM_ENABLE == 1
993 I2CM_CONFIGURATION(7),
994#endif
995};
996#endif
997
998/**
999 * \internal Retrieve ordinal number of the given sercom hardware instance
1000 *
1001 * \param[in] hw The pointer to hardware instance
1002
1003 * \return The ordinal number of the given sercom hardware instance
1004 */
1005static int8_t _get_i2cm_index(const void *const hw)
1006{
1007 uint8_t sercom_offset = _sercom_get_hardware_index(hw);
1008 uint8_t i;
1009
1010 for (i = 0; i < ARRAY_SIZE(_i2cms); i++) {
1011 if (_i2cms[i].number == sercom_offset) {
1012 return i;
1013 }
1014 }
1015
1016 ASSERT(false);
1017 return -1;
1018}
1019
1020static inline void _sercom_i2c_send_stop(void *const hw)
1021{
1022 hri_sercomi2cm_set_CTRLB_CMD_bf(hw, CMD_STOP);
1023}
1024
1025/**
1026 * \brief SERCOM I2CM analyze hardware status and transfer next byte
1027 */
1028static inline int32_t _sercom_i2c_sync_analyse_flags(void *const hw, uint32_t flags, struct _i2c_m_msg *const msg)
1029{
1030 int sclsm = hri_sercomi2cm_get_CTRLA_SCLSM_bit(hw);
1031 uint16_t status = hri_sercomi2cm_read_STATUS_reg(hw);
1032
1033 if (flags & MB_FLAG) {
1034 /* tx error */
1035 if (status & SERCOM_I2CM_STATUS_ARBLOST) {
1036 hri_sercomi2cm_clear_interrupt_MB_bit(hw);
1037 msg->flags |= I2C_M_FAIL;
1038 msg->flags &= ~I2C_M_BUSY;
1039
1040 if (status & SERCOM_I2CM_STATUS_BUSERR) {
1041 return I2C_ERR_BUS;
1042 }
1043
1044 return I2C_ERR_BAD_ADDRESS;
1045 } else {
1046 if (status & SERCOM_I2CM_STATUS_RXNACK) {
1047
1048 /* Slave rejects to receive more data */
1049 if (msg->len > 0) {
1050 msg->flags |= I2C_M_FAIL;
1051 }
1052
1053 if (msg->flags & I2C_M_STOP) {
1054 _sercom_i2c_send_stop(hw);
1055 }
1056
1057 msg->flags &= ~I2C_M_BUSY;
1058
1059 return I2C_NACK;
1060 }
1061
1062 if (msg->flags & I2C_M_TEN) {
1063 hri_sercomi2cm_write_ADDR_reg(hw,
1064 ((((msg->addr & TEN_ADDR_MASK) >> 8) | TEN_ADDR_FRAME) << 1) | I2C_M_RD
1065 | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
1066 msg->flags &= ~I2C_M_TEN;
1067
1068 return I2C_OK;
1069 }
1070
1071 if (msg->len == 0) {
1072 if (msg->flags & I2C_M_STOP) {
1073 _sercom_i2c_send_stop(hw);
1074 }
1075
1076 msg->flags &= ~I2C_M_BUSY;
1077 } else {
1078 hri_sercomi2cm_write_DATA_reg(hw, *msg->buffer);
1079 msg->buffer++;
1080 msg->len--;
1081 }
1082
1083 return I2C_OK;
1084 }
1085 } else if (flags & SB_FLAG) {
1086 if ((msg->len) && !(status & SERCOM_I2CM_STATUS_RXNACK)) {
1087 msg->len--;
1088
1089 /* last byte, send nack */
1090 if ((msg->len == 0 && !sclsm) || (msg->len == 1 && sclsm)) {
1091 hri_sercomi2cm_set_CTRLB_ACKACT_bit(hw);
1092 }
1093
1094 if (msg->len == 0) {
1095 if (msg->flags & I2C_M_STOP) {
1096 hri_sercomi2cm_clear_CTRLB_SMEN_bit(hw);
1097 _sercom_i2c_send_stop(hw);
1098 }
1099
1100 msg->flags &= ~I2C_M_BUSY;
1101 }
1102
1103 /* Accessing DATA.DATA auto-triggers I2C bus operations.
1104 * The operation performed depends on the state of
1105 * CTRLB.ACKACT, CTRLB.SMEN
1106 **/
1107 *msg->buffer++ = hri_sercomi2cm_read_DATA_reg(hw);
1108 } else {
1109 hri_sercomi2cm_clear_interrupt_SB_bit(hw);
1110 return I2C_NACK;
1111 }
1112
1113 hri_sercomi2cm_clear_interrupt_SB_bit(hw);
1114 }
1115
1116 return I2C_OK;
1117}
1118
1119/**
1120 * \brief Enable the i2c master module
1121 *
1122 * \param[in] i2c_dev The pointer to i2c device
1123 */
1124int32_t _i2c_m_async_enable(struct _i2c_m_async_device *const i2c_dev)
1125{
1126 ASSERT(i2c_dev);
1127
1128 _i2c_m_enable_implementation(i2c_dev->hw);
1129
1130 return ERR_NONE;
1131}
1132
1133/**
1134 * \brief Disable the i2c master module
1135 *
1136 * \param[in] i2c_dev The pointer to i2c device
1137 */
1138int32_t _i2c_m_async_disable(struct _i2c_m_async_device *const i2c_dev)
1139{
1140 void *hw = i2c_dev->hw;
1141
1142 ASSERT(i2c_dev);
1143 ASSERT(i2c_dev->hw);
1144
1145 NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(hw));
1146 hri_sercomi2cm_clear_CTRLA_ENABLE_bit(hw);
1147
1148 return ERR_NONE;
1149}
1150
1151/**
1152 * \brief Set baudrate of master
1153 *
1154 * \param[in] i2c_dev The pointer to i2c device
1155 * \param[in] clkrate The clock rate of i2c master, in KHz
1156 * \param[in] baudrate The baud rate desired for i2c master, in KHz
1157 */
1158int32_t _i2c_m_async_set_baudrate(struct _i2c_m_async_device *const i2c_dev, uint32_t clkrate, uint32_t baudrate)
1159{
1160 uint32_t tmp;
1161 void * hw = i2c_dev->hw;
1162
1163 if (hri_sercomi2cm_get_CTRLA_ENABLE_bit(hw)) {
1164 return ERR_DENIED;
1165 }
1166
1167 tmp = _get_i2cm_index(hw);
1168 clkrate = _i2cms[tmp].clk / 1000;
1169
1170 if (i2c_dev->service.mode == I2C_STANDARD_MODE) {
1171 tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
1172 / (2 * baudrate));
1173 hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
1174 } else if (i2c_dev->service.mode == I2C_FASTMODE) {
1175 tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
1176 / (2 * baudrate));
1177 hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
1178 } else if (i2c_dev->service.mode == I2C_HIGHSPEED_MODE) {
1179 tmp = (clkrate - 2 * baudrate) / (2 * baudrate);
1180 hri_sercomi2cm_write_BAUD_HSBAUD_bf(hw, tmp);
1181 } else {
1182 /* error baudrate */
1183 return ERR_INVALID_ARG;
1184 }
1185
1186 return ERR_NONE;
1187}
1188
1189/**
1190 * \brief Retrieve IRQ number for the given hardware instance
1191 */
1192static uint8_t _sercom_get_irq_num(const void *const hw)
1193{
1194 return SERCOM0_0_IRQn + (_sercom_get_hardware_index(hw) << 2);
1195}
1196
1197/**
1198 * \brief Initialize sercom i2c module to use in async mode
1199 *
1200 * \param[in] i2c_dev The pointer to i2c device
1201 */
1202int32_t _i2c_m_async_init(struct _i2c_m_async_device *const i2c_dev, void *const hw)
1203{
1204 int32_t init_status;
1205
1206 ASSERT(i2c_dev);
1207
1208 i2c_dev->hw = hw;
1209
1210 init_status = _i2c_m_sync_init_impl(&i2c_dev->service, hw);
1211 if (init_status) {
1212 return init_status;
1213 }
1214
1215 _sercom_init_irq_param(hw, (void *)i2c_dev);
1216 uint8_t irq = _sercom_get_irq_num(hw);
1217 for (uint32_t i = 0; i < 4; i++) {
1218 NVIC_DisableIRQ((IRQn_Type)irq);
1219 NVIC_ClearPendingIRQ((IRQn_Type)irq);
1220 NVIC_EnableIRQ((IRQn_Type)irq);
1221 irq++;
1222 }
1223 return ERR_NONE;
1224}
1225
1226/**
1227 * \brief Deinitialize sercom i2c module
1228 *
1229 * \param[in] i2c_dev The pointer to i2c device
1230 */
1231int32_t _i2c_m_async_deinit(struct _i2c_m_async_device *const i2c_dev)
1232{
1233 ASSERT(i2c_dev);
1234
1235 hri_sercomi2cm_clear_CTRLA_ENABLE_bit(i2c_dev->hw);
1236 hri_sercomi2cm_set_CTRLA_SWRST_bit(i2c_dev->hw);
1237
1238 return ERR_NONE;
1239}
1240
1241/**
1242 * \brief Transfer the slave address to bus, which will start the transfer
1243 *
1244 * \param[in] i2c_dev The pointer to i2c device
1245 */
1246static int32_t _sercom_i2c_send_address(struct _i2c_m_async_device *const i2c_dev)
1247{
1248 void * hw = i2c_dev->hw;
1249 struct _i2c_m_msg *msg = &i2c_dev->service.msg;
1250 int sclsm = hri_sercomi2cm_get_CTRLA_SCLSM_bit(hw);
1251
1252 ASSERT(i2c_dev);
1253
1254 if (msg->len == 1 && sclsm) {
1255 hri_sercomi2cm_set_CTRLB_ACKACT_bit(hw);
1256 } else {
1257 hri_sercomi2cm_clear_CTRLB_ACKACT_bit(hw);
1258 }
1259
1260 /* ten bit address */
1261 if (msg->addr & I2C_M_TEN) {
1262 if (msg->flags & I2C_M_RD) {
1263 msg->flags |= I2C_M_TEN;
1264 }
1265
1266 hri_sercomi2cm_write_ADDR_reg(hw,
1267 ((msg->addr & TEN_ADDR_MASK) << 1) | SERCOM_I2CM_ADDR_TENBITEN
1268 | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
1269 } else {
1270 hri_sercomi2cm_write_ADDR_reg(hw,
1271 ((msg->addr & SEVEN_ADDR_MASK) << 1) | (msg->flags & I2C_M_RD ? I2C_M_RD : 0x0)
1272 | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
1273 }
1274
1275 return ERR_NONE;
1276}
1277
1278/**
1279 * \brief Transfer data specified by msg
1280 *
1281 * \param[in] i2c_dev The pointer to i2c device
1282 * \param[in] msg The pointer to i2c message
1283 *
1284 * \return Transfer status.
1285 * \retval 0 Transfer success
1286 * \retval <0 Transfer fail, return the error code
1287 */
1288int32_t _i2c_m_async_transfer(struct _i2c_m_async_device *i2c_dev, struct _i2c_m_msg *msg)
1289{
1290 int ret;
1291
1292 ASSERT(i2c_dev);
1293 ASSERT(i2c_dev->hw);
1294 ASSERT(msg);
1295
1296 if (msg->len == 0) {
1297 return ERR_NONE;
1298 }
1299
1300 if (i2c_dev->service.msg.flags & I2C_M_BUSY) {
1301 return ERR_BUSY;
1302 }
1303
1304 msg->flags |= I2C_M_BUSY;
1305 i2c_dev->service.msg = *msg;
1306 hri_sercomi2cm_set_CTRLB_SMEN_bit(i2c_dev->hw);
1307
1308 ret = _sercom_i2c_send_address(i2c_dev);
1309
1310 if (ret) {
1311 i2c_dev->service.msg.flags &= ~I2C_M_BUSY;
1312
1313 return ret;
1314 }
1315
1316 return ERR_NONE;
1317}
1318
1319/**
1320 * \brief Set callback to be called in interrupt handler
1321 *
1322 * \param[in] i2c_dev The pointer to master i2c device
1323 * \param[in] type The callback type
1324 * \param[in] func The callback function pointer
1325 */
1326int32_t _i2c_m_async_register_callback(struct _i2c_m_async_device *const i2c_dev, enum _i2c_m_async_callback_type type,
1327 FUNC_PTR func)
1328{
1329 switch (type) {
1330 case I2C_M_ASYNC_DEVICE_ERROR:
1331 i2c_dev->cb.error = (_i2c_error_cb_t)func;
1332 break;
1333 case I2C_M_ASYNC_DEVICE_TX_COMPLETE:
1334 i2c_dev->cb.tx_complete = (_i2c_complete_cb_t)func;
1335 break;
1336 case I2C_M_ASYNC_DEVICE_RX_COMPLETE:
1337 i2c_dev->cb.rx_complete = (_i2c_complete_cb_t)func;
1338 break;
1339 default:
1340 /* error */
1341 break;
1342 }
1343
1344 return ERR_NONE;
1345}
1346
1347/**
1348 * \brief Set stop condition on I2C
1349 *
1350 * \param i2c_dev Pointer to master i2c device
1351 *
1352 * \return Operation status
1353 * \retval I2C_OK Operation was successfull
1354 */
1355int32_t _i2c_m_async_send_stop(struct _i2c_m_async_device *const i2c_dev)
1356{
1357 void *hw = i2c_dev->hw;
1358
1359 _sercom_i2c_send_stop(hw);
1360
1361 return I2C_OK;
1362}
1363
1364/**
1365 * \brief Get number of bytes left in transfer buffer
1366 *
1367 * \param i2c_dev Pointer to i2c master device
1368 *
1369 * \return Bytes left in buffer
1370 * \retval =>0 Bytes left in buffer
1371 */
1372int32_t _i2c_m_async_get_bytes_left(struct _i2c_m_async_device *const i2c_dev)
1373{
1374 if (i2c_dev->service.msg.flags & I2C_M_BUSY) {
1375 return i2c_dev->service.msg.len;
1376 }
1377
1378 return 0;
1379}
1380
1381/**
1382 * \brief Initialize sercom i2c module to use in sync mode
1383 *
1384 * \param[in] i2c_dev The pointer to i2c device
1385 */
1386int32_t _i2c_m_sync_init(struct _i2c_m_sync_device *const i2c_dev, void *const hw)
1387{
1388 ASSERT(i2c_dev);
1389
1390 i2c_dev->hw = hw;
1391
1392 return _i2c_m_sync_init_impl(&i2c_dev->service, hw);
1393}
1394
1395/**
1396 * \brief Deinitialize sercom i2c module
1397 *
1398 * \param[in] i2c_dev The pointer to i2c device
1399 */
1400int32_t _i2c_m_sync_deinit(struct _i2c_m_sync_device *const i2c_dev)
1401{
1402 ASSERT(i2c_dev);
1403
1404 hri_sercomi2cm_clear_CTRLA_ENABLE_bit(i2c_dev->hw);
1405 hri_sercomi2cm_set_CTRLA_SWRST_bit(i2c_dev->hw);
1406
1407 return ERR_NONE;
1408}
1409
1410/**
1411 * \brief Enable the i2c master module
1412 *
1413 * \param[in] i2c_dev The pointer to i2c device
1414 */
1415int32_t _i2c_m_sync_enable(struct _i2c_m_sync_device *const i2c_dev)
1416{
1417 ASSERT(i2c_dev);
1418
1419 _i2c_m_enable_implementation(i2c_dev->hw);
1420
1421 return ERR_NONE;
1422}
1423
1424/**
1425 * \brief Disable the i2c master module
1426 *
1427 * \param[in] i2c_dev The pointer to i2c device
1428 */
1429int32_t _i2c_m_sync_disable(struct _i2c_m_sync_device *const i2c_dev)
1430{
1431 void *hw = i2c_dev->hw;
1432
1433 ASSERT(i2c_dev);
1434 ASSERT(i2c_dev->hw);
1435
1436 hri_sercomi2cm_clear_CTRLA_ENABLE_bit(hw);
1437
1438 return ERR_NONE;
1439}
1440
1441/**
1442 * \brief Set baudrate of master
1443 *
1444 * \param[in] i2c_dev The pointer to i2c device
1445 * \param[in] clkrate The clock rate of i2c master, in KHz
1446 * \param[in] baudrate The baud rate desired for i2c master, in KHz
1447 */
1448int32_t _i2c_m_sync_set_baudrate(struct _i2c_m_sync_device *const i2c_dev, uint32_t clkrate, uint32_t baudrate)
1449{
1450 uint32_t tmp;
1451 void * hw = i2c_dev->hw;
1452
1453 if (hri_sercomi2cm_get_CTRLA_ENABLE_bit(hw)) {
1454 return ERR_DENIED;
1455 }
1456
1457 tmp = _get_i2cm_index(hw);
1458 clkrate = _i2cms[tmp].clk / 1000;
1459
1460 if (i2c_dev->service.mode == I2C_STANDARD_MODE) {
1461 tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
1462 / (2 * baudrate));
1463 hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
1464 } else if (i2c_dev->service.mode == I2C_FASTMODE) {
1465 tmp = (uint32_t)((clkrate - 10 * baudrate - baudrate * clkrate * (i2c_dev->service.trise * 0.000000001))
1466 / (2 * baudrate));
1467 hri_sercomi2cm_write_BAUD_BAUD_bf(hw, tmp);
1468 } else if (i2c_dev->service.mode == I2C_HIGHSPEED_MODE) {
1469 tmp = (clkrate - 2 * baudrate) / (2 * baudrate);
1470 hri_sercomi2cm_write_BAUD_HSBAUD_bf(hw, tmp);
1471 } else {
1472 /* error baudrate */
1473 return ERR_INVALID_ARG;
1474 }
1475
1476 return ERR_NONE;
1477}
1478
1479/**
1480 * \brief Enable/disable I2C master interrupt
1481 */
1482void _i2c_m_async_set_irq_state(struct _i2c_m_async_device *const device, const enum _i2c_m_async_callback_type type,
1483 const bool state)
1484{
1485 if (I2C_M_ASYNC_DEVICE_TX_COMPLETE == type || I2C_M_ASYNC_DEVICE_RX_COMPLETE == type) {
1486 hri_sercomi2cm_write_INTEN_SB_bit(device->hw, state);
1487 hri_sercomi2cm_write_INTEN_MB_bit(device->hw, state);
1488 } else if (I2C_M_ASYNC_DEVICE_ERROR == type) {
1489 hri_sercomi2cm_write_INTEN_ERROR_bit(device->hw, state);
1490 }
1491}
1492
1493/**
1494 * \brief Wait for bus response
1495 *
1496 * \param[in] i2c_dev The pointer to i2c device
1497 * \param[in] flags Store the hardware response
1498 *
1499 * \return Bus response status.
1500 * \retval 0 Bus response status OK
1501 * \retval <0 Bus response fail
1502 */
1503inline static int32_t _sercom_i2c_sync_wait_bus(struct _i2c_m_sync_device *const i2c_dev, uint32_t *flags)
1504{
1505 uint32_t timeout = 65535;
1506 void * hw = i2c_dev->hw;
1507
1508 do {
1509 *flags = hri_sercomi2cm_read_INTFLAG_reg(hw);
1510
1511 if (timeout-- == 0) {
1512 return I2C_ERR_BUS;
1513 }
1514 } while (!(*flags & MB_FLAG) && !(*flags & SB_FLAG));
1515
1516 return I2C_OK;
1517}
1518
1519/**
1520 * \brief Send the slave address to bus, which will start the transfer
1521 *
1522 * \param[in] i2c_dev The pointer to i2c device
1523 */
1524static int32_t _sercom_i2c_sync_send_address(struct _i2c_m_sync_device *const i2c_dev)
1525{
1526 void * hw = i2c_dev->hw;
1527 struct _i2c_m_msg *msg = &i2c_dev->service.msg;
1528 int sclsm = hri_sercomi2cm_get_CTRLA_SCLSM_bit(hw);
1529 uint32_t flags;
1530
1531 ASSERT(i2c_dev);
1532
1533 if (msg->len == 1 && sclsm) {
1534 hri_sercomi2cm_set_CTRLB_ACKACT_bit(hw);
1535 } else {
1536 hri_sercomi2cm_clear_CTRLB_ACKACT_bit(hw);
1537 }
1538
1539 /* ten bit address */
1540 if (msg->addr & I2C_M_TEN) {
1541 if (msg->flags & I2C_M_RD) {
1542 msg->flags |= I2C_M_TEN;
1543 }
1544
1545 hri_sercomi2cm_write_ADDR_reg(hw,
1546 ((msg->addr & TEN_ADDR_MASK) << 1) | SERCOM_I2CM_ADDR_TENBITEN
1547 | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
1548 } else {
1549 hri_sercomi2cm_write_ADDR_reg(hw,
1550 ((msg->addr & SEVEN_ADDR_MASK) << 1) | (msg->flags & I2C_M_RD ? I2C_M_RD : 0x0)
1551 | (hri_sercomi2cm_read_ADDR_reg(hw) & SERCOM_I2CM_ADDR_HS));
1552 }
1553
1554 _sercom_i2c_sync_wait_bus(i2c_dev, &flags);
1555 return _sercom_i2c_sync_analyse_flags(hw, flags, msg);
1556}
1557
1558/**
1559 * \brief Transfer data specified by msg
1560 *
1561 * \param[in] i2c_dev The pointer to i2c device
1562 * \param[in] msg The pointer to i2c message
1563 *
1564 * \return Transfer status.
1565 * \retval 0 Transfer success
1566 * \retval <0 Transfer fail or partial fail, return the error code
1567 */
1568int32_t _i2c_m_sync_transfer(struct _i2c_m_sync_device *const i2c_dev, struct _i2c_m_msg *msg)
1569{
1570 uint32_t flags;
1571 int ret;
1572 void * hw = i2c_dev->hw;
1573
1574 ASSERT(i2c_dev);
1575 ASSERT(i2c_dev->hw);
1576 ASSERT(msg);
1577
1578 if (i2c_dev->service.msg.flags & I2C_M_BUSY) {
1579 return I2C_ERR_BUSY;
1580 }
1581
1582 msg->flags |= I2C_M_BUSY;
1583 i2c_dev->service.msg = *msg;
1584 hri_sercomi2cm_set_CTRLB_SMEN_bit(hw);
1585
1586 ret = _sercom_i2c_sync_send_address(i2c_dev);
1587
1588 if (ret) {
1589 i2c_dev->service.msg.flags &= ~I2C_M_BUSY;
1590
1591 return ret;
1592 }
1593
1594 while (i2c_dev->service.msg.flags & I2C_M_BUSY) {
1595 ret = _sercom_i2c_sync_wait_bus(i2c_dev, &flags);
1596
1597 if (ret) {
1598 if (msg->flags & I2C_M_STOP) {
1599 _sercom_i2c_send_stop(hw);
1600 }
1601
1602 i2c_dev->service.msg.flags &= ~I2C_M_BUSY;
1603
1604 return ret;
1605 }
1606
1607 ret = _sercom_i2c_sync_analyse_flags(hw, flags, &i2c_dev->service.msg);
1608 }
1609
1610 return ret;
1611}
1612
1613int32_t _i2c_m_sync_send_stop(struct _i2c_m_sync_device *const i2c_dev)
1614{
1615 void *hw = i2c_dev->hw;
1616
1617 _sercom_i2c_send_stop(hw);
1618
1619 return I2C_OK;
1620}
1621
1622static inline void _i2c_m_enable_implementation(void *const hw)
1623{
1624 int timeout = 65535;
1625
1626 ASSERT(hw);
1627
1628 /* Enable interrupts */
1629 hri_sercomi2cm_set_CTRLA_ENABLE_bit(hw);
1630
1631 while (hri_sercomi2cm_read_STATUS_BUSSTATE_bf(hw) != I2C_IDLE) {
1632 timeout--;
1633
1634 if (timeout <= 0) {
1635 hri_sercomi2cm_clear_STATUS_reg(hw, SERCOM_I2CM_STATUS_BUSSTATE(I2C_IDLE));
1636 }
1637 }
1638}
1639
1640static int32_t _i2c_m_sync_init_impl(struct _i2c_m_service *const service, void *const hw)
1641{
1642 uint8_t i = _get_i2cm_index(hw);
1643
1644 if (!hri_sercomi2cm_is_syncing(hw, SERCOM_I2CM_SYNCBUSY_SWRST)) {
1645 uint32_t mode = _i2cms[i].ctrl_a & SERCOM_I2CM_CTRLA_MODE_Msk;
1646 if (hri_sercomi2cm_get_CTRLA_reg(hw, SERCOM_I2CM_CTRLA_ENABLE)) {
1647 hri_sercomi2cm_clear_CTRLA_ENABLE_bit(hw);
1648 hri_sercomi2cm_wait_for_sync(hw, SERCOM_I2CM_SYNCBUSY_ENABLE);
1649 }
1650 hri_sercomi2cm_write_CTRLA_reg(hw, SERCOM_I2CM_CTRLA_SWRST | mode);
1651 }
1652 hri_sercomi2cm_wait_for_sync(hw, SERCOM_I2CM_SYNCBUSY_SWRST);
1653
1654 hri_sercomi2cm_write_CTRLA_reg(hw, _i2cms[i].ctrl_a);
1655 hri_sercomi2cm_write_CTRLB_reg(hw, _i2cms[i].ctrl_b);
1656 hri_sercomi2cm_write_BAUD_reg(hw, _i2cms[i].baud);
1657
1658 service->mode = (_i2cms[i].ctrl_a & SERCOM_I2CM_CTRLA_SPEED_Msk) >> SERCOM_I2CM_CTRLA_SPEED_Pos;
1659 hri_sercomi2cm_write_ADDR_HS_bit(hw, service->mode < I2C_HS ? 0 : 1);
1660
1661 service->trise = _i2cms[i].trise;
1662
1663 return ERR_NONE;
1664}
1665
1666 /* SERCOM I2C slave */
1667
1668#ifndef CONF_SERCOM_0_I2CS_ENABLE
1669#define CONF_SERCOM_0_I2CS_ENABLE 0
1670#endif
1671#ifndef CONF_SERCOM_1_I2CS_ENABLE
1672#define CONF_SERCOM_1_I2CS_ENABLE 0
1673#endif
1674#ifndef CONF_SERCOM_2_I2CS_ENABLE
1675#define CONF_SERCOM_2_I2CS_ENABLE 0
1676#endif
1677#ifndef CONF_SERCOM_3_I2CS_ENABLE
1678#define CONF_SERCOM_3_I2CS_ENABLE 0
1679#endif
1680#ifndef CONF_SERCOM_4_I2CS_ENABLE
1681#define CONF_SERCOM_4_I2CS_ENABLE 0
1682#endif
1683#ifndef CONF_SERCOM_5_I2CS_ENABLE
1684#define CONF_SERCOM_5_I2CS_ENABLE 0
1685#endif
1686#ifndef CONF_SERCOM_6_I2CS_ENABLE
1687#define CONF_SERCOM_6_I2CS_ENABLE 0
1688#endif
1689#ifndef CONF_SERCOM_7_I2CS_ENABLE
1690#define CONF_SERCOM_7_I2CS_ENABLE 0
1691#endif
1692
1693/** Amount of SERCOM that is used as I2C Slave. */
1694#define SERCOM_I2CS_AMOUNT \
1695 (CONF_SERCOM_0_I2CS_ENABLE + CONF_SERCOM_1_I2CS_ENABLE + CONF_SERCOM_2_I2CS_ENABLE + CONF_SERCOM_3_I2CS_ENABLE \
1696 + CONF_SERCOM_4_I2CS_ENABLE + CONF_SERCOM_5_I2CS_ENABLE + CONF_SERCOM_6_I2CS_ENABLE + CONF_SERCOM_7_I2CS_ENABLE)
1697
1698/**
1699 * \brief Macro is used to fill I2C slave configuration structure based on
1700 * its number
1701 *
1702 * \param[in] n The number of structures
1703 */
1704#define I2CS_CONFIGURATION(n) \
1705 { \
1706 n, \
1707 SERCOM_I2CM_CTRLA_MODE_I2C_SLAVE | (CONF_SERCOM_##n##_I2CS_RUNSTDBY << SERCOM_I2CS_CTRLA_RUNSTDBY_Pos) \
1708 | SERCOM_I2CS_CTRLA_SDAHOLD(CONF_SERCOM_##n##_I2CS_SDAHOLD) \
1709 | (CONF_SERCOM_##n##_I2CS_SEXTTOEN << SERCOM_I2CS_CTRLA_SEXTTOEN_Pos) \
1710 | (CONF_SERCOM_##n##_I2CS_SPEED << SERCOM_I2CS_CTRLA_SPEED_Pos) \
1711 | (CONF_SERCOM_##n##_I2CS_SCLSM << SERCOM_I2CS_CTRLA_SCLSM_Pos) \
1712 | (CONF_SERCOM_##n##_I2CS_LOWTOUT << SERCOM_I2CS_CTRLA_LOWTOUTEN_Pos), \
1713 SERCOM_I2CS_CTRLB_SMEN | SERCOM_I2CS_CTRLB_AACKEN | SERCOM_I2CS_CTRLB_AMODE(CONF_SERCOM_##n##_I2CS_AMODE), \
1714 (CONF_SERCOM_##n##_I2CS_GENCEN << SERCOM_I2CS_ADDR_GENCEN_Pos) \
1715 | SERCOM_I2CS_ADDR_ADDR(CONF_SERCOM_##n##_I2CS_ADDRESS) \
1716 | (CONF_SERCOM_##n##_I2CS_TENBITEN << SERCOM_I2CS_ADDR_TENBITEN_Pos) \
1717 | SERCOM_I2CS_ADDR_ADDRMASK(CONF_SERCOM_##n##_I2CS_ADDRESS_MASK) \
1718 }
1719
1720/**
1721 * \brief Macro to check 10-bit addressing
1722 */
1723#define I2CS_7BIT_ADDRESSING_MASK 0x7F
1724
1725static int32_t _i2c_s_init(void *const hw);
1726static int8_t _get_i2c_s_index(const void *const hw);
1727static inline void _i2c_s_deinit(void *const hw);
1728static int32_t _i2c_s_set_address(void *const hw, const uint16_t address);
1729
1730/**
1731 * \brief SERCOM I2C slave configuration type
1732 */
1733struct i2cs_configuration {
1734 uint8_t number;
1735 hri_sercomi2cs_ctrla_reg_t ctrl_a;
1736 hri_sercomi2cs_ctrlb_reg_t ctrl_b;
1737 hri_sercomi2cs_addr_reg_t address;
1738};
1739
1740#if SERCOM_I2CS_AMOUNT < 1
1741/** Dummy array for compiling. */
1742static struct i2cs_configuration _i2css[1] = {{0}};
1743#else
1744/**
1745 * \brief Array of SERCOM I2C slave configurations
1746 */
1747static struct i2cs_configuration _i2css[] = {
1748#if CONF_SERCOM_0_I2CS_ENABLE == 1
1749 I2CS_CONFIGURATION(0),
1750#endif
1751#if CONF_SERCOM_1_I2CS_ENABLE == 1
1752 I2CS_CONFIGURATION(1),
1753#endif
1754#if CONF_SERCOM_2_I2CS_ENABLE == 1
1755 I2CS_CONFIGURATION(2),
1756#endif
1757#if CONF_SERCOM_3_I2CS_ENABLE == 1
1758 I2CS_CONFIGURATION(3),
1759#endif
1760#if CONF_SERCOM_4_I2CS_ENABLE == 1
1761 I2CS_CONFIGURATION(4),
1762#endif
1763#if CONF_SERCOM_5_I2CS_ENABLE == 1
1764 I2CS_CONFIGURATION(5),
1765#endif
1766};
1767#endif
1768
1769/**
1770 * \brief Initialize synchronous I2C slave
1771 */
1772int32_t _i2c_s_sync_init(struct _i2c_s_sync_device *const device, void *const hw)
1773{
1774 int32_t status;
1775
1776 ASSERT(device);
1777
1778 status = _i2c_s_init(hw);
1779 if (status) {
1780 return status;
1781 }
1782 device->hw = hw;
1783
1784 return ERR_NONE;
1785}
1786
1787/**
1788 * \brief Initialize asynchronous I2C slave
1789 */
1790int32_t _i2c_s_async_init(struct _i2c_s_async_device *const device, void *const hw)
1791{
1792 int32_t init_status;
1793
1794 ASSERT(device);
1795
1796 init_status = _i2c_s_init(hw);
1797 if (init_status) {
1798 return init_status;
1799 }
1800
1801 device->hw = hw;
1802 _sercom_init_irq_param(hw, (void *)device);
1803 uint8_t irq = _sercom_get_irq_num(hw);
1804 for (uint32_t i = 0; i < 4; i++) {
1805 NVIC_DisableIRQ((IRQn_Type)irq);
1806 NVIC_ClearPendingIRQ((IRQn_Type)irq);
1807 NVIC_EnableIRQ((IRQn_Type)irq);
1808 irq++;
1809 }
1810
1811 return ERR_NONE;
1812}
1813
1814/**
1815 * \brief Deinitialize synchronous I2C
1816 */
1817int32_t _i2c_s_sync_deinit(struct _i2c_s_sync_device *const device)
1818{
1819 _i2c_s_deinit(device->hw);
1820
1821 return ERR_NONE;
1822}
1823
1824/**
1825 * \brief Deinitialize asynchronous I2C
1826 */
1827int32_t _i2c_s_async_deinit(struct _i2c_s_async_device *const device)
1828{
1829 NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(device->hw));
1830 _i2c_s_deinit(device->hw);
1831
1832 return ERR_NONE;
1833}
1834
1835/**
1836 * \brief Enable I2C module
1837 */
1838int32_t _i2c_s_sync_enable(struct _i2c_s_sync_device *const device)
1839{
1840 hri_sercomi2cs_set_CTRLA_ENABLE_bit(device->hw);
1841
1842 return ERR_NONE;
1843}
1844
1845/**
1846 * \brief Enable I2C module
1847 */
1848int32_t _i2c_s_async_enable(struct _i2c_s_async_device *const device)
1849{
1850 hri_sercomi2cs_set_CTRLA_ENABLE_bit(device->hw);
1851
1852 return ERR_NONE;
1853}
1854
1855/**
1856 * \brief Disable I2C module
1857 */
1858int32_t _i2c_s_sync_disable(struct _i2c_s_sync_device *const device)
1859{
1860 hri_sercomi2cs_clear_CTRLA_ENABLE_bit(device->hw);
1861
1862 return ERR_NONE;
1863}
1864
1865/**
1866 * \brief Disable I2C module
1867 */
1868int32_t _i2c_s_async_disable(struct _i2c_s_async_device *const device)
1869{
1870 hri_sercomi2cs_clear_CTRLA_ENABLE_bit(device->hw);
1871
1872 return ERR_NONE;
1873}
1874
1875/**
1876 * \brief Check if 10-bit addressing mode is on
1877 */
1878int32_t _i2c_s_sync_is_10bit_addressing_on(const struct _i2c_s_sync_device *const device)
1879{
1880 return hri_sercomi2cs_get_ADDR_TENBITEN_bit(device->hw);
1881}
1882
1883/**
1884 * \brief Check if 10-bit addressing mode is on
1885 */
1886int32_t _i2c_s_async_is_10bit_addressing_on(const struct _i2c_s_async_device *const device)
1887{
1888 return hri_sercomi2cs_get_ADDR_TENBITEN_bit(device->hw);
1889}
1890
1891/**
1892 * \brief Set I2C slave address
1893 */
1894int32_t _i2c_s_sync_set_address(struct _i2c_s_sync_device *const device, const uint16_t address)
1895{
1896 return _i2c_s_set_address(device->hw, address);
1897}
1898
1899/**
1900 * \brief Set I2C slave address
1901 */
1902int32_t _i2c_s_async_set_address(struct _i2c_s_async_device *const device, const uint16_t address)
1903{
1904 return _i2c_s_set_address(device->hw, address);
1905}
1906
1907/**
1908 * \brief Write a byte to the given I2C instance
1909 */
1910void _i2c_s_sync_write_byte(struct _i2c_s_sync_device *const device, const uint8_t data)
1911{
1912 hri_sercomi2cs_write_DATA_reg(device->hw, data);
1913}
1914
1915/**
1916 * \brief Write a byte to the given I2C instance
1917 */
1918void _i2c_s_async_write_byte(struct _i2c_s_async_device *const device, const uint8_t data)
1919{
1920 hri_sercomi2cs_write_DATA_reg(device->hw, data);
1921}
1922
1923/**
1924 * \brief Read a byte from the given I2C instance
1925 */
1926uint8_t _i2c_s_sync_read_byte(const struct _i2c_s_sync_device *const device)
1927{
1928 return hri_sercomi2cs_read_DATA_reg(device->hw);
1929}
1930
1931/**
1932 * \brief Check if I2C is ready to send next byt
1933 */
1934bool _i2c_s_sync_is_byte_sent(const struct _i2c_s_sync_device *const device)
1935{
1936 return hri_sercomi2cs_get_interrupt_DRDY_bit(device->hw);
1937}
1938
1939/**
1940 * \brief Check if there is data received by I2C
1941 */
1942bool _i2c_s_sync_is_byte_received(const struct _i2c_s_sync_device *const device)
1943{
1944 return hri_sercomi2cs_get_interrupt_DRDY_bit(device->hw);
1945}
1946
1947/**
1948 * \brief Retrieve I2C slave status
1949 */
1950i2c_s_status_t _i2c_s_sync_get_status(const struct _i2c_s_sync_device *const device)
1951{
1952 return hri_sercomi2cs_read_STATUS_reg(device->hw);
1953}
1954
1955/**
1956 * \brief Clear the Data Ready interrupt flag
1957 */
1958int32_t _i2c_s_sync_clear_data_ready_flag(const struct _i2c_s_sync_device *const device)
1959{
1960 hri_sercomi2cs_clear_INTFLAG_DRDY_bit(device->hw);
1961
1962 return ERR_NONE;
1963}
1964
1965/**
1966 * \brief Retrieve I2C slave status
1967 */
1968i2c_s_status_t _i2c_s_async_get_status(const struct _i2c_s_async_device *const device)
1969{
1970 return hri_sercomi2cs_read_STATUS_reg(device->hw);
1971}
1972
1973/**
1974 * \brief Abort data transmission
1975 */
1976int32_t _i2c_s_async_abort_transmission(const struct _i2c_s_async_device *const device)
1977{
1978 hri_sercomi2cs_clear_INTEN_DRDY_bit(device->hw);
1979
1980 return ERR_NONE;
1981}
1982
1983/**
1984 * \brief Enable/disable I2C slave interrupt
1985 */
1986int32_t _i2c_s_async_set_irq_state(struct _i2c_s_async_device *const device, const enum _i2c_s_async_callback_type type,
1987 const bool state)
1988{
1989 ASSERT(device);
1990
1991 if (I2C_S_DEVICE_TX == type || I2C_S_DEVICE_RX_COMPLETE == type) {
1992 hri_sercomi2cs_write_INTEN_DRDY_bit(device->hw, state);
1993 } else if (I2C_S_DEVICE_ERROR == type) {
1994 hri_sercomi2cs_write_INTEN_ERROR_bit(device->hw, state);
1995 }
1996
1997 return ERR_NONE;
1998}
1999
2000/**
2001 * \internal Initalize i2c slave hardware
2002 *
2003 * \param[in] p The pointer to hardware instance
2004 *
2005 *\ return status of initialization
2006 */
2007static int32_t _i2c_s_init(void *const hw)
2008{
2009 int8_t i = _get_i2c_s_index(hw);
2010 if (i == -1) {
2011 return ERR_INVALID_ARG;
2012 }
2013
2014 if (!hri_sercomi2cs_is_syncing(hw, SERCOM_I2CS_CTRLA_SWRST)) {
2015 uint32_t mode = _i2css[i].ctrl_a & SERCOM_I2CS_CTRLA_MODE_Msk;
2016 if (hri_sercomi2cs_get_CTRLA_reg(hw, SERCOM_I2CS_CTRLA_ENABLE)) {
2017 hri_sercomi2cs_clear_CTRLA_ENABLE_bit(hw);
2018 hri_sercomi2cs_wait_for_sync(hw, SERCOM_I2CS_SYNCBUSY_ENABLE);
2019 }
2020 hri_sercomi2cs_write_CTRLA_reg(hw, SERCOM_I2CS_CTRLA_SWRST | mode);
2021 }
2022 hri_sercomi2cs_wait_for_sync(hw, SERCOM_I2CS_SYNCBUSY_SWRST);
2023
2024 hri_sercomi2cs_write_CTRLA_reg(hw, _i2css[i].ctrl_a);
2025 hri_sercomi2cs_write_CTRLB_reg(hw, _i2css[i].ctrl_b);
2026 hri_sercomi2cs_write_ADDR_reg(hw, _i2css[i].address);
2027
2028 return ERR_NONE;
2029}
2030
2031/**
2032 * \internal Retrieve ordinal number of the given sercom hardware instance
2033 *
2034 * \param[in] hw The pointer to hardware instance
2035 *
2036 * \return The ordinal number of the given sercom hardware instance
2037 */
2038static int8_t _get_i2c_s_index(const void *const hw)
2039{
2040 uint8_t sercom_offset = _sercom_get_hardware_index(hw);
2041 uint8_t i;
2042
2043 for (i = 0; i < ARRAY_SIZE(_i2css); i++) {
2044 if (_i2css[i].number == sercom_offset) {
2045 return i;
2046 }
2047 }
2048
2049 ASSERT(false);
2050 return -1;
2051}
2052
2053/**
2054 * \internal De-initialize i2c slave
2055 *
2056 * \param[in] hw The pointer to hardware instance
2057 */
2058static inline void _i2c_s_deinit(void *const hw)
2059{
2060 hri_sercomi2cs_clear_CTRLA_ENABLE_bit(hw);
2061 hri_sercomi2cs_set_CTRLA_SWRST_bit(hw);
2062}
2063
2064/**
2065 * \internal De-initialize i2c slave
2066 *
2067 * \param[in] hw The pointer to hardware instance
2068 * \param[in] address Address to set
2069 */
2070static int32_t _i2c_s_set_address(void *const hw, const uint16_t address)
2071{
2072 bool enabled;
2073
2074 enabled = hri_sercomi2cs_get_CTRLA_ENABLE_bit(hw);
2075
2076 CRITICAL_SECTION_ENTER()
2077 hri_sercomi2cs_clear_CTRLA_ENABLE_bit(hw);
2078 hri_sercomi2cs_write_ADDR_ADDR_bf(hw, address);
2079 CRITICAL_SECTION_LEAVE()
2080
2081 if (enabled) {
2082 hri_sercomi2cs_set_CTRLA_ENABLE_bit(hw);
2083 }
2084
2085 return ERR_NONE;
2086}
2087
2088 /* Sercom SPI implementation */
2089
2090#ifndef SERCOM_USART_CTRLA_MODE_SPI_SLAVE
2091#define SERCOM_USART_CTRLA_MODE_SPI_SLAVE (2 << 2)
2092#endif
2093
2094#define SPI_DEV_IRQ_MODE 0x8000
2095
2096#define _SPI_CS_PORT_EXTRACT(cs) (((cs) >> 0) & 0xFF)
2097#define _SPI_CS_PIN_EXTRACT(cs) (((cs) >> 8) & 0xFF)
2098
2099COMPILER_PACK_SET(1)
2100/** Initialization configuration of registers. */
2101struct sercomspi_regs_cfg {
2102 uint32_t ctrla;
2103 uint32_t ctrlb;
2104 uint32_t addr;
2105 uint8_t baud;
2106 uint8_t dbgctrl;
2107 uint16_t dummy_byte;
2108 uint8_t n;
2109};
2110COMPILER_PACK_RESET()
2111
2112/** Build configuration from header macros. */
2113#define SERCOMSPI_REGS(n) \
2114 { \
2115 (((CONF_SERCOM_##n##_SPI_DORD) << SERCOM_SPI_CTRLA_DORD_Pos) \
2116 | (CONF_SERCOM_##n##_SPI_CPOL << SERCOM_SPI_CTRLA_CPOL_Pos) \
2117 | (CONF_SERCOM_##n##_SPI_CPHA << SERCOM_SPI_CTRLA_CPHA_Pos) \
2118 | (CONF_SERCOM_##n##_SPI_AMODE_EN ? SERCOM_SPI_CTRLA_FORM(2) : SERCOM_SPI_CTRLA_FORM(0)) \
2119 | SERCOM_SPI_CTRLA_DOPO(CONF_SERCOM_##n##_SPI_TXPO) | SERCOM_SPI_CTRLA_DIPO(CONF_SERCOM_##n##_SPI_RXPO) \
2120 | (CONF_SERCOM_##n##_SPI_IBON << SERCOM_SPI_CTRLA_IBON_Pos) \
2121 | (CONF_SERCOM_##n##_SPI_RUNSTDBY << SERCOM_SPI_CTRLA_RUNSTDBY_Pos) \
2122 | SERCOM_SPI_CTRLA_MODE(CONF_SERCOM_##n##_SPI_MODE)), /* ctrla */ \
2123 ((CONF_SERCOM_##n##_SPI_RXEN << SERCOM_SPI_CTRLB_RXEN_Pos) \
2124 | (CONF_SERCOM_##n##_SPI_MSSEN << SERCOM_SPI_CTRLB_MSSEN_Pos) \
2125 | (CONF_SERCOM_##n##_SPI_SSDE << SERCOM_SPI_CTRLB_SSDE_Pos) \
2126 | (CONF_SERCOM_##n##_SPI_PLOADEN << SERCOM_SPI_CTRLB_PLOADEN_Pos) \
2127 | SERCOM_SPI_CTRLB_AMODE(CONF_SERCOM_##n##_SPI_AMODE) \
2128 | SERCOM_SPI_CTRLB_CHSIZE(CONF_SERCOM_##n##_SPI_CHSIZE)), /* ctrlb */ \
2129 (SERCOM_SPI_ADDR_ADDR(CONF_SERCOM_##n##_SPI_ADDR) \
2130 | SERCOM_SPI_ADDR_ADDRMASK(CONF_SERCOM_##n##_SPI_ADDRMASK)), /* addr */ \
2131 ((uint8_t)CONF_SERCOM_##n##_SPI_BAUD_RATE), /* baud */ \
2132 (CONF_SERCOM_##n##_SPI_DBGSTOP << SERCOM_SPI_DBGCTRL_DBGSTOP_Pos), /* dbgctrl */ \
2133 CONF_SERCOM_##n##_SPI_DUMMYBYTE, /* Dummy byte for SPI master mode */ \
2134 n /* sercom number */ \
2135 }
2136
2137#ifndef CONF_SERCOM_0_SPI_ENABLE
2138#define CONF_SERCOM_0_SPI_ENABLE 0
2139#endif
2140#ifndef CONF_SERCOM_1_SPI_ENABLE
2141#define CONF_SERCOM_1_SPI_ENABLE 0
2142#endif
2143#ifndef CONF_SERCOM_2_SPI_ENABLE
2144#define CONF_SERCOM_2_SPI_ENABLE 0
2145#endif
2146#ifndef CONF_SERCOM_3_SPI_ENABLE
2147#define CONF_SERCOM_3_SPI_ENABLE 0
2148#endif
2149#ifndef CONF_SERCOM_4_SPI_ENABLE
2150#define CONF_SERCOM_4_SPI_ENABLE 0
2151#endif
2152#ifndef CONF_SERCOM_5_SPI_ENABLE
2153#define CONF_SERCOM_5_SPI_ENABLE 0
2154#endif
2155#ifndef CONF_SERCOM_6_SPI_ENABLE
2156#define CONF_SERCOM_6_SPI_ENABLE 0
2157#endif
2158#ifndef CONF_SERCOM_7_SPI_ENABLE
2159#define CONF_SERCOM_7_SPI_ENABLE 0
2160#endif
2161
2162/** Amount of SERCOM that is used as SPI */
2163#define SERCOM_SPI_AMOUNT \
2164 (CONF_SERCOM_0_SPI_ENABLE + CONF_SERCOM_1_SPI_ENABLE + CONF_SERCOM_2_SPI_ENABLE + CONF_SERCOM_3_SPI_ENABLE \
2165 + CONF_SERCOM_4_SPI_ENABLE + CONF_SERCOM_5_SPI_ENABLE + CONF_SERCOM_6_SPI_ENABLE + CONF_SERCOM_7_SPI_ENABLE)
2166
2167#if SERCOM_SPI_AMOUNT < 1
2168/** Dummy array for compiling. */
2169static const struct sercomspi_regs_cfg sercomspi_regs[1] = {{0}};
2170#else
2171/** The SERCOM SPI configurations of SERCOM that is used as SPI. */
2172static const struct sercomspi_regs_cfg sercomspi_regs[] = {
2173#if CONF_SERCOM_0_SPI_ENABLE
2174 SERCOMSPI_REGS(0),
2175#endif
2176#if CONF_SERCOM_1_SPI_ENABLE
2177 SERCOMSPI_REGS(1),
2178#endif
2179#if CONF_SERCOM_2_SPI_ENABLE
2180 SERCOMSPI_REGS(2),
2181#endif
2182#if CONF_SERCOM_3_SPI_ENABLE
2183 SERCOMSPI_REGS(3),
2184#endif
2185#if CONF_SERCOM_4_SPI_ENABLE
2186 SERCOMSPI_REGS(4),
2187#endif
2188#if CONF_SERCOM_5_SPI_ENABLE
2189 SERCOMSPI_REGS(5),
2190#endif
2191#if CONF_SERCOM_6_SPI_ENABLE
2192 SERCOMSPI_REGS(6),
2193#endif
2194#if CONF_SERCOM_7_SPI_ENABLE
2195 SERCOMSPI_REGS(7),
2196#endif
2197};
2198#endif
2199
2200/** \internal De-initialize SERCOM SPI
2201 *
2202 * \param[in] hw Pointer to the hardware register base.
2203 *
2204 * \return De-initialization status
2205 */
2206static int32_t _spi_deinit(void *const hw)
2207{
2208 hri_sercomspi_clear_CTRLA_ENABLE_bit(hw);
2209 hri_sercomspi_set_CTRLA_SWRST_bit(hw);
2210
2211 return ERR_NONE;
2212}
2213
2214/** \internal Enable SERCOM SPI
2215 *
2216 * \param[in] hw Pointer to the hardware register base.
2217 *
2218 * \return Enabling status
2219 */
2220static int32_t _spi_sync_enable(void *const hw)
2221{
2222 if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
2223 return ERR_BUSY;
2224 }
2225
2226 hri_sercomspi_set_CTRLA_ENABLE_bit(hw);
2227
2228 return ERR_NONE;
2229}
2230
2231/** \internal Enable SERCOM SPI
2232 *
2233 * \param[in] hw Pointer to the hardware register base.
2234 *
2235 * \return Enabling status
2236 */
2237static int32_t _spi_async_enable(void *const hw)
2238{
2239 _spi_sync_enable(hw);
2240 uint8_t irq = _sercom_get_irq_num(hw);
2241 for (uint32_t i = 0; i < 4; i++) {
2242 NVIC_EnableIRQ((IRQn_Type)irq++);
2243 }
2244
2245 return ERR_NONE;
2246}
2247
2248/** \internal Disable SERCOM SPI
2249 *
2250 * \param[in] hw Pointer to the hardware register base.
2251 *
2252 * \return Disabling status
2253 */
2254static int32_t _spi_sync_disable(void *const hw)
2255{
2256 if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
2257 return ERR_BUSY;
2258 }
2259 hri_sercomspi_clear_CTRLA_ENABLE_bit(hw);
2260
2261 return ERR_NONE;
2262}
2263
2264/** \internal Disable SERCOM SPI
2265 *
2266 * \param[in] hw Pointer to the hardware register base.
2267 *
2268 * \return Disabling status
2269 */
2270static int32_t _spi_async_disable(void *const hw)
2271{
2272 _spi_sync_disable(hw);
2273 hri_sercomspi_clear_INTEN_reg(
2274 hw, SERCOM_SPI_INTFLAG_ERROR | SERCOM_SPI_INTFLAG_RXC | SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE);
2275 uint8_t irq = _sercom_get_irq_num(hw);
2276 for (uint32_t i = 0; i < 4; i++) {
2277 NVIC_DisableIRQ((IRQn_Type)irq++);
2278 }
2279
2280 return ERR_NONE;
2281}
2282
2283/** \internal Set SERCOM SPI mode
2284 *
2285 * \param[in] hw Pointer to the hardware register base.
2286 * \param[in] mode The mode to set
2287 *
2288 * \return Setting mode status
2289 */
2290static int32_t _spi_set_mode(void *const hw, const enum spi_transfer_mode mode)
2291{
2292 uint32_t ctrla;
2293
2294 if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST | SERCOM_SPI_SYNCBUSY_ENABLE)) {
2295 return ERR_BUSY;
2296 }
2297
2298 ctrla = hri_sercomspi_read_CTRLA_reg(hw);
2299 ctrla &= ~(SERCOM_SPI_CTRLA_CPOL | SERCOM_SPI_CTRLA_CPHA);
2300 ctrla |= (mode & 0x3u) << SERCOM_SPI_CTRLA_CPHA_Pos;
2301 hri_sercomspi_write_CTRLA_reg(hw, ctrla);
2302
2303 return ERR_NONE;
2304}
2305
2306/** \internal Set SERCOM SPI baudrate
2307 *
2308 * \param[in] hw Pointer to the hardware register base.
2309 * \param[in] baud_val The baudrate to set
2310 *
2311 * \return Setting baudrate status
2312 */
2313static int32_t _spi_set_baudrate(void *const hw, const uint32_t baud_val)
2314{
2315 if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
2316 return ERR_BUSY;
2317 }
2318
2319 hri_sercomspi_write_BAUD_reg(hw, baud_val);
2320
2321 return ERR_NONE;
2322}
2323
2324/** \internal Set SERCOM SPI char size
2325 *
2326 * \param[in] hw Pointer to the hardware register base.
2327 * \param[in] baud_val The baudrate to set
2328 * \param[out] size Stored char size
2329 *
2330 * \return Setting char size status
2331 */
2332static int32_t _spi_set_char_size(void *const hw, const enum spi_char_size char_size, uint8_t *const size)
2333{
2334 /* Only 8-bit or 9-bit accepted */
2335 if (!(char_size == SPI_CHAR_SIZE_8 || char_size == SPI_CHAR_SIZE_9)) {
2336 return ERR_INVALID_ARG;
2337 }
2338
2339 if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST | SERCOM_SPI_SYNCBUSY_CTRLB)) {
2340 return ERR_BUSY;
2341 }
2342
2343 hri_sercomspi_write_CTRLB_CHSIZE_bf(hw, char_size);
2344 *size = (char_size == SPI_CHAR_SIZE_8) ? 1 : 2;
2345
2346 return ERR_NONE;
2347}
2348
2349/** \internal Set SERCOM SPI data order
2350 *
2351 * \param[in] hw Pointer to the hardware register base.
2352 * \param[in] baud_val The baudrate to set
2353 *
2354 * \return Setting data order status
2355 */
2356static int32_t _spi_set_data_order(void *const hw, const enum spi_data_order dord)
2357{
2358 uint32_t ctrla;
2359
2360 if (hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
2361 return ERR_BUSY;
2362 }
2363
2364 ctrla = hri_sercomspi_read_CTRLA_reg(hw);
2365
2366 if (dord == SPI_DATA_ORDER_LSB_1ST) {
2367 ctrla |= SERCOM_SPI_CTRLA_DORD;
2368 } else {
2369 ctrla &= ~SERCOM_SPI_CTRLA_DORD;
2370 }
2371 hri_sercomspi_write_CTRLA_reg(hw, ctrla);
2372
2373 return ERR_NONE;
2374}
2375
2376/** \brief Load SERCOM registers to init for SPI master mode
2377 * The settings will be applied with default master mode, unsupported things
2378 * are ignored.
2379 * \param[in, out] hw Pointer to the hardware register base.
2380 * \param[in] regs Pointer to register configuration values.
2381 */
2382static inline void _spi_load_regs_master(void *const hw, const struct sercomspi_regs_cfg *regs)
2383{
2384 ASSERT(hw && regs);
2385 hri_sercomspi_write_CTRLA_reg(
2386 hw, regs->ctrla & ~(SERCOM_SPI_CTRLA_IBON | SERCOM_SPI_CTRLA_ENABLE | SERCOM_SPI_CTRLA_SWRST));
2387 hri_sercomspi_write_CTRLB_reg(
2388 hw,
2389 (regs->ctrlb
2390 & ~(SERCOM_SPI_CTRLB_MSSEN | SERCOM_SPI_CTRLB_AMODE_Msk | SERCOM_SPI_CTRLB_SSDE | SERCOM_SPI_CTRLB_PLOADEN))
2391 | (SERCOM_SPI_CTRLB_RXEN));
2392 hri_sercomspi_write_BAUD_reg(hw, regs->baud);
2393 hri_sercomspi_write_DBGCTRL_reg(hw, regs->dbgctrl);
2394}
2395
2396/** \brief Load SERCOM registers to init for SPI slave mode
2397 * The settings will be applied with default slave mode, unsupported things
2398 * are ignored.
2399 * \param[in, out] hw Pointer to the hardware register base.
2400 * \param[in] regs Pointer to register configuration values.
2401 */
2402static inline void _spi_load_regs_slave(void *const hw, const struct sercomspi_regs_cfg *regs)
2403{
2404 ASSERT(hw && regs);
2405 hri_sercomspi_write_CTRLA_reg(
2406 hw, regs->ctrla & ~(SERCOM_SPI_CTRLA_IBON | SERCOM_SPI_CTRLA_ENABLE | SERCOM_SPI_CTRLA_SWRST));
2407 hri_sercomspi_write_CTRLB_reg(hw,
2408 (regs->ctrlb & ~(SERCOM_SPI_CTRLB_MSSEN))
2409 | (SERCOM_SPI_CTRLB_RXEN | SERCOM_SPI_CTRLB_SSDE | SERCOM_SPI_CTRLB_PLOADEN));
2410 hri_sercomspi_write_ADDR_reg(hw, regs->addr);
2411 hri_sercomspi_write_DBGCTRL_reg(hw, regs->dbgctrl);
2412 while (hri_sercomspi_is_syncing(hw, 0xFFFFFFFF))
2413 ;
2414}
2415
2416/** \brief Return the pointer to register settings of specific SERCOM
2417 * \param[in] hw_addr The hardware register base address.
2418 * \return Pointer to register settings of specific SERCOM.
2419 */
2420static inline const struct sercomspi_regs_cfg *_spi_get_regs(const uint32_t hw_addr)
2421{
2422 uint8_t n = _sercom_get_hardware_index((const void *)hw_addr);
2423 uint8_t i;
2424
2425 for (i = 0; i < sizeof(sercomspi_regs) / sizeof(struct sercomspi_regs_cfg); i++) {
2426 if (sercomspi_regs[i].n == n) {
2427 return &sercomspi_regs[i];
2428 }
2429 }
2430
2431 return NULL;
2432}
2433
Kévin Redonccbed0b2019-01-24 18:30:26 +01002434/**
2435 * \internal Sercom interrupt handler
2436 */
Kévin Redon1f8ecef2019-01-31 13:36:12 +01002437void SERCOM0_0_Handler(void)
2438{
2439 _sercom_usart_interrupt_handler(_sercom0_dev);
2440}
2441/**
2442 * \internal Sercom interrupt handler
2443 */
2444void SERCOM0_1_Handler(void)
2445{
2446 _sercom_usart_interrupt_handler(_sercom0_dev);
2447}
2448/**
2449 * \internal Sercom interrupt handler
2450 */
2451void SERCOM0_2_Handler(void)
2452{
2453 _sercom_usart_interrupt_handler(_sercom0_dev);
2454}
2455/**
2456 * \internal Sercom interrupt handler
2457 */
2458void SERCOM0_3_Handler(void)
2459{
2460 _sercom_usart_interrupt_handler(_sercom0_dev);
2461}
2462
2463/**
2464 * \internal Sercom interrupt handler
2465 */
2466void SERCOM1_0_Handler(void)
2467{
2468 _sercom_usart_interrupt_handler(_sercom1_dev);
2469}
2470/**
2471 * \internal Sercom interrupt handler
2472 */
2473void SERCOM1_1_Handler(void)
2474{
2475 _sercom_usart_interrupt_handler(_sercom1_dev);
2476}
2477/**
2478 * \internal Sercom interrupt handler
2479 */
2480void SERCOM1_2_Handler(void)
2481{
2482 _sercom_usart_interrupt_handler(_sercom1_dev);
2483}
2484/**
2485 * \internal Sercom interrupt handler
2486 */
2487void SERCOM1_3_Handler(void)
2488{
2489 _sercom_usart_interrupt_handler(_sercom1_dev);
2490}
2491
2492/**
2493 * \internal Sercom interrupt handler
2494 */
2495void SERCOM2_0_Handler(void)
2496{
2497 _sercom_usart_interrupt_handler(_sercom2_dev);
2498}
2499/**
2500 * \internal Sercom interrupt handler
2501 */
2502void SERCOM2_1_Handler(void)
2503{
2504 _sercom_usart_interrupt_handler(_sercom2_dev);
2505}
2506/**
2507 * \internal Sercom interrupt handler
2508 */
2509void SERCOM2_2_Handler(void)
2510{
2511 _sercom_usart_interrupt_handler(_sercom2_dev);
2512}
2513/**
2514 * \internal Sercom interrupt handler
2515 */
2516void SERCOM2_3_Handler(void)
2517{
2518 _sercom_usart_interrupt_handler(_sercom2_dev);
2519}
2520
2521/**
2522 * \internal Sercom interrupt handler
2523 */
2524void SERCOM3_0_Handler(void)
2525{
2526 _sercom_usart_interrupt_handler(_sercom3_dev);
2527}
2528/**
2529 * \internal Sercom interrupt handler
2530 */
2531void SERCOM3_1_Handler(void)
2532{
2533 _sercom_usart_interrupt_handler(_sercom3_dev);
2534}
2535/**
2536 * \internal Sercom interrupt handler
2537 */
2538void SERCOM3_2_Handler(void)
2539{
2540 _sercom_usart_interrupt_handler(_sercom3_dev);
2541}
2542/**
2543 * \internal Sercom interrupt handler
2544 */
2545void SERCOM3_3_Handler(void)
2546{
2547 _sercom_usart_interrupt_handler(_sercom3_dev);
2548}
2549
2550/**
2551 * \internal Sercom interrupt handler
2552 */
2553void SERCOM4_0_Handler(void)
2554{
2555 _sercom_usart_interrupt_handler(_sercom4_dev);
2556}
2557/**
2558 * \internal Sercom interrupt handler
2559 */
2560void SERCOM4_1_Handler(void)
2561{
2562 _sercom_usart_interrupt_handler(_sercom4_dev);
2563}
2564/**
2565 * \internal Sercom interrupt handler
2566 */
2567void SERCOM4_2_Handler(void)
2568{
2569 _sercom_usart_interrupt_handler(_sercom4_dev);
2570}
2571/**
2572 * \internal Sercom interrupt handler
2573 */
2574void SERCOM4_3_Handler(void)
2575{
2576 _sercom_usart_interrupt_handler(_sercom4_dev);
2577}
2578
2579/**
2580 * \internal Sercom interrupt handler
2581 */
2582void SERCOM5_0_Handler(void)
2583{
2584 _sercom_usart_interrupt_handler(_sercom5_dev);
2585}
2586/**
2587 * \internal Sercom interrupt handler
2588 */
2589void SERCOM5_1_Handler(void)
2590{
2591 _sercom_usart_interrupt_handler(_sercom5_dev);
2592}
2593/**
2594 * \internal Sercom interrupt handler
2595 */
2596void SERCOM5_2_Handler(void)
2597{
2598 _sercom_usart_interrupt_handler(_sercom5_dev);
2599}
2600/**
2601 * \internal Sercom interrupt handler
2602 */
2603void SERCOM5_3_Handler(void)
2604{
2605 _sercom_usart_interrupt_handler(_sercom5_dev);
2606}
2607
2608/**
2609 * \internal Sercom interrupt handler
2610 */
2611void SERCOM6_0_Handler(void)
2612{
2613 _sercom_usart_interrupt_handler(_sercom6_dev);
2614}
2615/**
2616 * \internal Sercom interrupt handler
2617 */
2618void SERCOM6_1_Handler(void)
2619{
2620 _sercom_usart_interrupt_handler(_sercom6_dev);
2621}
2622/**
2623 * \internal Sercom interrupt handler
2624 */
2625void SERCOM6_2_Handler(void)
2626{
2627 _sercom_usart_interrupt_handler(_sercom6_dev);
2628}
2629/**
2630 * \internal Sercom interrupt handler
2631 */
2632void SERCOM6_3_Handler(void)
2633{
2634 _sercom_usart_interrupt_handler(_sercom6_dev);
2635}
2636
Kévin Redonba3a2fa2019-03-07 15:52:27 +01002637/**
2638 * \internal Sercom interrupt handler
2639 */
2640void SERCOM7_0_Handler(void)
2641{
2642 _sercom_usart_interrupt_handler(_sercom7_dev);
2643}
2644/**
2645 * \internal Sercom interrupt handler
2646 */
2647void SERCOM7_1_Handler(void)
2648{
2649 _sercom_usart_interrupt_handler(_sercom7_dev);
2650}
2651/**
2652 * \internal Sercom interrupt handler
2653 */
2654void SERCOM7_2_Handler(void)
2655{
2656 _sercom_usart_interrupt_handler(_sercom7_dev);
2657}
2658/**
2659 * \internal Sercom interrupt handler
2660 */
2661void SERCOM7_3_Handler(void)
2662{
2663 _sercom_usart_interrupt_handler(_sercom7_dev);
2664}
2665
Kévin Redon4cd3f7d2019-01-24 17:57:13 +01002666int32_t _spi_m_sync_init(struct _spi_m_sync_dev *dev, void *const hw)
2667{
2668 const struct sercomspi_regs_cfg *regs = _spi_get_regs((uint32_t)hw);
2669
2670 ASSERT(dev && hw);
2671
2672 if (regs == NULL) {
2673 return ERR_INVALID_ARG;
2674 }
2675
2676 if (!hri_sercomspi_is_syncing(hw, SERCOM_SPI_SYNCBUSY_SWRST)) {
2677 uint32_t mode = regs->ctrla & SERCOM_SPI_CTRLA_MODE_Msk;
2678 if (hri_sercomspi_get_CTRLA_reg(hw, SERCOM_SPI_CTRLA_ENABLE)) {
2679 hri_sercomspi_clear_CTRLA_ENABLE_bit(hw);
2680 hri_sercomspi_wait_for_sync(hw, SERCOM_SPI_SYNCBUSY_ENABLE);
2681 }
2682 hri_sercomspi_write_CTRLA_reg(hw, SERCOM_SPI_CTRLA_SWRST | mode);
2683 }
2684 hri_sercomspi_wait_for_sync(hw, SERCOM_SPI_SYNCBUSY_SWRST);
2685
2686 dev->prvt = hw;
2687
2688 if ((regs->ctrla & SERCOM_SPI_CTRLA_MODE_Msk) == SERCOM_USART_CTRLA_MODE_SPI_SLAVE) {
2689 _spi_load_regs_slave(hw, regs);
2690 } else {
2691 _spi_load_regs_master(hw, regs);
2692 }
2693
2694 /* Load character size from default hardware configuration */
2695 dev->char_size = ((regs->ctrlb & SERCOM_SPI_CTRLB_CHSIZE_Msk) == 0) ? 1 : 2;
2696
2697 dev->dummy_byte = regs->dummy_byte;
2698
2699 return ERR_NONE;
2700}
2701
2702int32_t _spi_s_sync_init(struct _spi_s_sync_dev *dev, void *const hw)
2703{
2704 return _spi_m_sync_init(dev, hw);
2705}
2706
2707int32_t _spi_m_async_init(struct _spi_async_dev *dev, void *const hw)
2708{
2709 struct _spi_async_dev *spid = dev;
2710 /* Do hardware initialize. */
2711 int32_t rc = _spi_m_sync_init((struct _spi_m_sync_dev *)dev, hw);
2712
2713 if (rc < 0) {
2714 return rc;
2715 }
2716
2717 _sercom_init_irq_param(hw, (void *)dev);
2718 /* Initialize callbacks: must use them */
2719 spid->callbacks.complete = NULL;
2720 spid->callbacks.rx = NULL;
2721 spid->callbacks.tx = NULL;
2722 uint8_t irq = _sercom_get_irq_num(hw);
2723 for (uint32_t i = 0; i < 4; i++) {
2724 NVIC_DisableIRQ((IRQn_Type)irq);
2725 NVIC_ClearPendingIRQ((IRQn_Type)irq);
2726 irq++;
2727 }
2728
2729 return ERR_NONE;
2730}
2731
2732int32_t _spi_s_async_init(struct _spi_s_async_dev *dev, void *const hw)
2733{
2734 return _spi_m_async_init(dev, hw);
2735}
2736
2737int32_t _spi_m_async_deinit(struct _spi_async_dev *dev)
2738{
2739 NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
2740 NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
2741
2742 return _spi_deinit(dev->prvt);
2743}
2744
2745int32_t _spi_s_async_deinit(struct _spi_s_async_dev *dev)
2746{
2747 NVIC_DisableIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
2748 NVIC_ClearPendingIRQ((IRQn_Type)_sercom_get_irq_num(dev->prvt));
2749
2750 return _spi_deinit(dev->prvt);
2751}
2752
2753int32_t _spi_m_sync_deinit(struct _spi_m_sync_dev *dev)
2754{
2755 return _spi_deinit(dev->prvt);
2756}
2757
2758int32_t _spi_s_sync_deinit(struct _spi_s_sync_dev *dev)
2759{
2760 return _spi_deinit(dev->prvt);
2761}
2762
2763int32_t _spi_m_sync_enable(struct _spi_m_sync_dev *dev)
2764{
2765 ASSERT(dev && dev->prvt);
2766
2767 return _spi_sync_enable(dev->prvt);
2768}
2769
2770int32_t _spi_s_sync_enable(struct _spi_s_sync_dev *dev)
2771{
2772 ASSERT(dev && dev->prvt);
2773
2774 return _spi_sync_enable(dev->prvt);
2775}
2776
2777int32_t _spi_m_async_enable(struct _spi_async_dev *dev)
2778{
2779 ASSERT(dev && dev->prvt);
2780
2781 return _spi_async_enable(dev->prvt);
2782}
2783
2784int32_t _spi_s_async_enable(struct _spi_s_async_dev *dev)
2785{
2786 ASSERT(dev && dev->prvt);
2787
2788 return _spi_async_enable(dev->prvt);
2789}
2790
2791int32_t _spi_m_sync_disable(struct _spi_m_sync_dev *dev)
2792{
2793 ASSERT(dev && dev->prvt);
2794
2795 return _spi_sync_disable(dev->prvt);
2796}
2797
2798int32_t _spi_s_sync_disable(struct _spi_s_sync_dev *dev)
2799{
2800 ASSERT(dev && dev->prvt);
2801
2802 return _spi_sync_disable(dev->prvt);
2803}
2804
2805int32_t _spi_m_async_disable(struct _spi_async_dev *dev)
2806{
2807 ASSERT(dev && dev->prvt);
2808
2809 return _spi_async_disable(dev->prvt);
2810}
2811
2812int32_t _spi_s_async_disable(struct _spi_s_async_dev *dev)
2813{
2814 ASSERT(dev && dev->prvt);
2815
2816 return _spi_async_disable(dev->prvt);
2817}
2818
2819int32_t _spi_m_sync_set_mode(struct _spi_m_sync_dev *dev, const enum spi_transfer_mode mode)
2820{
2821 ASSERT(dev && dev->prvt);
2822
2823 return _spi_set_mode(dev->prvt, mode);
2824}
2825
2826int32_t _spi_m_async_set_mode(struct _spi_async_dev *dev, const enum spi_transfer_mode mode)
2827{
2828 ASSERT(dev && dev->prvt);
2829
2830 return _spi_set_mode(dev->prvt, mode);
2831}
2832
2833int32_t _spi_s_async_set_mode(struct _spi_s_async_dev *dev, const enum spi_transfer_mode mode)
2834{
2835 ASSERT(dev && dev->prvt);
2836
2837 return _spi_set_mode(dev->prvt, mode);
2838}
2839
2840int32_t _spi_s_sync_set_mode(struct _spi_s_sync_dev *dev, const enum spi_transfer_mode mode)
2841{
2842 ASSERT(dev && dev->prvt);
2843
2844 return _spi_set_mode(dev->prvt, mode);
2845}
2846
2847int32_t _spi_calc_baud_val(struct spi_dev *dev, const uint32_t clk, const uint32_t baud)
2848{
2849 int32_t rc;
2850 ASSERT(dev);
2851
2852 /* Not accept 0es */
2853 if (clk == 0 || baud == 0) {
2854 return ERR_INVALID_ARG;
2855 }
2856
2857 /* Check baudrate range of current assigned clock */
2858 if (!(baud <= (clk >> 1) && baud >= (clk >> 8))) {
2859 return ERR_INVALID_ARG;
2860 }
2861
2862 rc = ((clk >> 1) / baud) - 1;
2863 return rc;
2864}
2865
2866int32_t _spi_m_sync_set_baudrate(struct _spi_m_sync_dev *dev, const uint32_t baud_val)
2867{
2868 ASSERT(dev && dev->prvt);
2869
2870 return _spi_set_baudrate(dev->prvt, baud_val);
2871}
2872
2873int32_t _spi_m_async_set_baudrate(struct _spi_async_dev *dev, const uint32_t baud_val)
2874{
2875 ASSERT(dev && dev->prvt);
2876
2877 return _spi_set_baudrate(dev->prvt, baud_val);
2878}
2879
2880int32_t _spi_m_sync_set_char_size(struct _spi_m_sync_dev *dev, const enum spi_char_size char_size)
2881{
2882 ASSERT(dev && dev->prvt);
2883
2884 return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
2885}
2886
2887int32_t _spi_m_async_set_char_size(struct _spi_async_dev *dev, const enum spi_char_size char_size)
2888{
2889 ASSERT(dev && dev->prvt);
2890
2891 return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
2892}
2893
2894int32_t _spi_s_async_set_char_size(struct _spi_s_async_dev *dev, const enum spi_char_size char_size)
2895{
2896 ASSERT(dev && dev->prvt);
2897
2898 return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
2899}
2900
2901int32_t _spi_s_sync_set_char_size(struct _spi_s_sync_dev *dev, const enum spi_char_size char_size)
2902{
2903 ASSERT(dev && dev->prvt);
2904
2905 return _spi_set_char_size(dev->prvt, char_size, &dev->char_size);
2906}
2907
2908int32_t _spi_m_sync_set_data_order(struct _spi_m_sync_dev *dev, const enum spi_data_order dord)
2909{
2910 ASSERT(dev && dev->prvt);
2911
2912 return _spi_set_data_order(dev->prvt, dord);
2913}
2914
2915int32_t _spi_m_async_set_data_order(struct _spi_async_dev *dev, const enum spi_data_order dord)
2916{
2917 ASSERT(dev && dev->prvt);
2918
2919 return _spi_set_data_order(dev->prvt, dord);
2920}
2921
2922int32_t _spi_s_async_set_data_order(struct _spi_s_async_dev *dev, const enum spi_data_order dord)
2923{
2924 ASSERT(dev && dev->prvt);
2925
2926 return _spi_set_data_order(dev->prvt, dord);
2927}
2928
2929int32_t _spi_s_sync_set_data_order(struct _spi_s_sync_dev *dev, const enum spi_data_order dord)
2930{
2931 ASSERT(dev && dev->prvt);
2932
2933 return _spi_set_data_order(dev->prvt, dord);
2934}
2935
2936/** Wait until SPI bus idle. */
2937static inline void _spi_wait_bus_idle(void *const hw)
2938{
2939 while (!(hri_sercomspi_get_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE))) {
2940 ;
2941 }
2942 hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_DRE);
2943}
2944
2945/** Holds run time information for message sync transaction. */
2946struct _spi_trans_ctrl {
2947 /** Pointer to transmitting data buffer. */
2948 uint8_t *txbuf;
2949 /** Pointer to receiving data buffer. */
2950 uint8_t *rxbuf;
2951 /** Count number of data transmitted. */
2952 uint32_t txcnt;
2953 /** Count number of data received. */
2954 uint32_t rxcnt;
2955 /** Data character size. */
2956 uint8_t char_size;
2957};
2958
2959/** Check interrupt flag of RXC and update transaction runtime information. */
2960static inline bool _spi_rx_check_and_receive(void *const hw, const uint32_t iflag, struct _spi_trans_ctrl *ctrl)
2961{
2962 uint32_t data;
2963
2964 if (!(iflag & SERCOM_SPI_INTFLAG_RXC)) {
2965 return false;
2966 }
2967
2968 data = hri_sercomspi_read_DATA_reg(hw);
2969
2970 if (ctrl->rxbuf) {
2971 *ctrl->rxbuf++ = (uint8_t)data;
2972
2973 if (ctrl->char_size > 1) {
2974 *ctrl->rxbuf++ = (uint8_t)(data >> 8);
2975 }
2976 }
2977
2978 ctrl->rxcnt++;
2979
2980 return true;
2981}
2982
2983/** Check interrupt flag of DRE and update transaction runtime information. */
2984static inline void _spi_tx_check_and_send(void *const hw, const uint32_t iflag, struct _spi_trans_ctrl *ctrl,
2985 uint16_t dummy)
2986{
2987 uint32_t data;
2988
2989 if (!(SERCOM_SPI_INTFLAG_DRE & iflag)) {
2990 return;
2991 }
2992
2993 if (ctrl->txbuf) {
2994 data = *ctrl->txbuf++;
2995
2996 if (ctrl->char_size > 1) {
2997 data |= (*ctrl->txbuf) << 8;
2998 ctrl->txbuf++;
2999 }
3000 } else {
3001 data = dummy;
3002 }
3003
3004 ctrl->txcnt++;
3005 hri_sercomspi_write_DATA_reg(hw, data);
3006}
3007
3008/** Check interrupt flag of ERROR and update transaction runtime information. */
3009static inline int32_t _spi_err_check(const uint32_t iflag, void *const hw)
3010{
3011 if (SERCOM_SPI_INTFLAG_ERROR & iflag) {
3012 hri_sercomspi_clear_STATUS_reg(hw, ~0);
3013 hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_ERROR);
3014 return ERR_OVERFLOW;
3015 }
3016
3017 return ERR_NONE;
3018}
3019
3020int32_t _spi_m_sync_trans(struct _spi_m_sync_dev *dev, const struct spi_msg *msg)
3021{
3022 void * hw = dev->prvt;
3023 int32_t rc = 0;
3024 struct _spi_trans_ctrl ctrl = {msg->txbuf, msg->rxbuf, 0, 0, dev->char_size};
3025
3026 ASSERT(dev && hw);
3027
3028 /* If settings are not applied (pending), we can not go on */
3029 if (hri_sercomspi_is_syncing(
3030 hw, (SERCOM_SPI_SYNCBUSY_SWRST | SERCOM_SPI_SYNCBUSY_ENABLE | SERCOM_SPI_SYNCBUSY_CTRLB))) {
3031 return ERR_BUSY;
3032 }
3033
3034 /* SPI must be enabled to start synchronous transfer */
3035 if (!hri_sercomspi_get_CTRLA_ENABLE_bit(hw)) {
3036 return ERR_NOT_INITIALIZED;
3037 }
3038
3039 for (;;) {
3040 uint32_t iflag = hri_sercomspi_read_INTFLAG_reg(hw);
3041
3042 if (!_spi_rx_check_and_receive(hw, iflag, &ctrl)) {
3043 /* In master mode, do not start next byte before previous byte received
3044 * to make better output waveform */
3045 if (ctrl.rxcnt >= ctrl.txcnt) {
3046 _spi_tx_check_and_send(hw, iflag, &ctrl, dev->dummy_byte);
3047 }
3048 }
3049
3050 rc = _spi_err_check(iflag, hw);
3051
3052 if (rc < 0) {
3053 break;
3054 }
3055 if (ctrl.txcnt >= msg->size && ctrl.rxcnt >= msg->size) {
3056 rc = ctrl.txcnt;
3057 break;
3058 }
3059 }
3060 /* Wait until SPI bus idle */
3061 _spi_wait_bus_idle(hw);
3062
3063 return rc;
3064}
3065
3066int32_t _spi_m_async_enable_tx(struct _spi_async_dev *dev, bool state)
3067{
3068 void *hw = dev->prvt;
3069
3070 ASSERT(dev && hw);
3071
3072 if (state) {
3073 hri_sercomspi_set_INTEN_DRE_bit(hw);
3074 } else {
3075 hri_sercomspi_clear_INTEN_DRE_bit(hw);
3076 }
3077
3078 return ERR_NONE;
3079}
3080
3081int32_t _spi_s_async_enable_tx(struct _spi_s_async_dev *dev, bool state)
3082{
3083 return _spi_m_async_enable_tx(dev, state);
3084}
3085
3086int32_t _spi_m_async_enable_rx(struct _spi_async_dev *dev, bool state)
3087{
3088 void *hw = dev->prvt;
3089
3090 ASSERT(dev);
3091 ASSERT(hw);
3092
3093 if (state) {
3094 hri_sercomspi_set_INTEN_RXC_bit(hw);
3095 } else {
3096 hri_sercomspi_clear_INTEN_RXC_bit(hw);
3097 }
3098
3099 return ERR_NONE;
3100}
3101
3102int32_t _spi_s_async_enable_rx(struct _spi_s_async_dev *dev, bool state)
3103{
3104 return _spi_m_async_enable_rx(dev, state);
3105}
3106
3107int32_t _spi_m_async_enable_tx_complete(struct _spi_async_dev *dev, bool state)
3108{
3109 ASSERT(dev && dev->prvt);
3110
3111 if (state) {
3112 hri_sercomspi_set_INTEN_TXC_bit(dev->prvt);
3113 } else {
3114 hri_sercomspi_clear_INTEN_TXC_bit(dev->prvt);
3115 }
3116
3117 return ERR_NONE;
3118}
3119
3120int32_t _spi_s_async_enable_ss_detect(struct _spi_s_async_dev *dev, bool state)
3121{
3122 return _spi_m_async_enable_tx_complete(dev, state);
3123}
3124
3125int32_t _spi_m_async_write_one(struct _spi_async_dev *dev, uint16_t data)
3126{
3127 ASSERT(dev && dev->prvt);
3128
3129 hri_sercomspi_write_DATA_reg(dev->prvt, data);
3130
3131 return ERR_NONE;
3132}
3133
3134int32_t _spi_s_async_write_one(struct _spi_s_async_dev *dev, uint16_t data)
3135{
3136 ASSERT(dev && dev->prvt);
3137
3138 hri_sercomspi_write_DATA_reg(dev->prvt, data);
3139
3140 return ERR_NONE;
3141}
3142
3143int32_t _spi_s_sync_write_one(struct _spi_s_sync_dev *dev, uint16_t data)
3144{
3145 ASSERT(dev && dev->prvt);
3146
3147 hri_sercomspi_write_DATA_reg(dev->prvt, data);
3148
3149 return ERR_NONE;
3150}
3151
3152uint16_t _spi_m_async_read_one(struct _spi_async_dev *dev)
3153{
3154 ASSERT(dev && dev->prvt);
3155
3156 return hri_sercomspi_read_DATA_reg(dev->prvt);
3157}
3158
3159uint16_t _spi_s_async_read_one(struct _spi_s_async_dev *dev)
3160{
3161 ASSERT(dev && dev->prvt);
3162
3163 return hri_sercomspi_read_DATA_reg(dev->prvt);
3164}
3165
3166uint16_t _spi_s_sync_read_one(struct _spi_s_sync_dev *dev)
3167{
3168 ASSERT(dev && dev->prvt);
3169
3170 return hri_sercomspi_read_DATA_reg(dev->prvt);
3171}
3172
3173int32_t _spi_m_async_register_callback(struct _spi_async_dev *dev, const enum _spi_async_dev_cb_type cb_type,
3174 const FUNC_PTR func)
3175{
3176 typedef void (*func_t)(void);
3177 struct _spi_async_dev *spid = dev;
3178
3179 ASSERT(dev && (cb_type < SPI_DEV_CB_N));
3180
3181 func_t *p_ls = (func_t *)&spid->callbacks;
3182 p_ls[cb_type] = (func_t)func;
3183
3184 return ERR_NONE;
3185}
3186
3187int32_t _spi_s_async_register_callback(struct _spi_s_async_dev *dev, const enum _spi_s_async_dev_cb_type cb_type,
3188 const FUNC_PTR func)
3189{
3190 return _spi_m_async_register_callback(dev, cb_type, func);
3191}
3192
3193bool _spi_s_sync_is_tx_ready(struct _spi_s_sync_dev *dev)
3194{
3195 ASSERT(dev && dev->prvt);
3196
3197 return hri_sercomi2cm_get_INTFLAG_reg(dev->prvt, SERCOM_SPI_INTFLAG_DRE);
3198}
3199
3200bool _spi_s_sync_is_rx_ready(struct _spi_s_sync_dev *dev)
3201{
3202 ASSERT(dev && dev->prvt);
3203
3204 return hri_sercomi2cm_get_INTFLAG_reg(dev->prvt, SERCOM_SPI_INTFLAG_RXC);
3205}
3206
3207bool _spi_s_sync_is_ss_deactivated(struct _spi_s_sync_dev *dev)
3208{
3209 void *hw = dev->prvt;
3210
3211 ASSERT(dev && hw);
3212
3213 if (hri_sercomi2cm_get_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC)) {
3214 hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_TXC);
3215 return true;
3216 }
3217 return false;
3218}
3219
3220bool _spi_s_sync_is_error(struct _spi_s_sync_dev *dev)
3221{
3222 void *hw = dev->prvt;
3223
3224 ASSERT(dev && hw);
3225
3226 if (hri_sercomi2cm_get_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_ERROR)) {
3227 hri_sercomspi_clear_STATUS_reg(hw, SERCOM_SPI_STATUS_BUFOVF);
3228 hri_sercomspi_clear_INTFLAG_reg(hw, SERCOM_SPI_INTFLAG_ERROR);
3229 return true;
3230 }
3231 return false;
3232}
3233
3234/**
3235 * \brief Enable/disable SPI master interrupt
3236 *
3237 * param[in] device The pointer to SPI master device instance
3238 * param[in] type The type of interrupt to disable/enable if applicable
3239 * param[in] state Enable or disable
3240 */
3241void _spi_m_async_set_irq_state(struct _spi_async_dev *const device, const enum _spi_async_dev_cb_type type,
3242 const bool state)
3243{
3244 ASSERT(device);
3245
3246 if (SPI_DEV_CB_ERROR == type) {
3247 hri_sercomspi_write_INTEN_ERROR_bit(device->prvt, state);
3248 }
3249}
3250
3251/**
3252 * \brief Enable/disable SPI slave interrupt
3253 *
3254 * param[in] device The pointer to SPI slave device instance
3255 * param[in] type The type of interrupt to disable/enable if applicable
3256 * param[in] state Enable or disable
3257 */
3258void _spi_s_async_set_irq_state(struct _spi_async_dev *const device, const enum _spi_async_dev_cb_type type,
3259 const bool state)
3260{
3261 _spi_m_async_set_irq_state(device, type, state);
3262}