1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/nrf52/spi_twi_irq.c
Dylan Laduranty 72c93a9743 cpu/nrfxx: introduce shared serial IRQ
For now, nRF53 and nRF9160 will shared UART/I2C/SPI IRQs, nRF52 will reuse the same callback but will keep its own file to avoid breakage. This can be continue in a followup PR

Signed-off-by: Dylan Laduranty <dylan.laduranty@mesotic.com>
2023-07-11 22:39:23 +02:00

204 lines
4.0 KiB
C

/*
* Copyright (C) 2020 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_nrf52
* @{
*
* @file
* @brief Shared IRQ handling between SPI and TWI peripherals on the nRF52
* devices
*
* I2C is called TWI (Two Wire Interface) in the datasheets from Nordic
*
* @author Koen Zandberg <koen@bergzand.net>
*
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "mutex.h"
#include "periph_cpu.h"
#if NRF_SPIM0_BASE != NRF_TWIM0_BASE
#define ISR_SPIM0 isr_spi0
#if defined(NRF_SPIM1)
#define ISR_SPIM1 isr_spi1_twi0
#else
#define ISR_SPIM1 isr_twi0
#endif
/* nRF52832 and nRF52840 ISR names */
#else
#define ISR_SPIM0 isr_spi0_twi0
#define ISR_SPIM1 isr_spi1_twi1
#endif
/**
* The vendor file is weird here. nRF52805 is the only other MCU
* that has only 1 SPI and separate 1 TWI interface, but define
* SPIM_COUNT = 2, which is in line with how it is used here.
* nRF52810 has the same set of SPI/TWI peripherals, but defines
* SPIM_COUNT = 1 which is more logical.
* Just re-define it to work around this inconsistency.
*/
#ifdef CPU_MODEL_NRF52810XXAA
#undef SPIM_COUNT
#define SPIM_COUNT 2
#endif
static shared_irq_cb_t _irq[SPIM_COUNT];
static void *_irq_arg[SPIM_COUNT];
static mutex_t _locks[SPIM_COUNT];
/* I2C and SPI share peripheral addresses */
static size_t _spi_dev2num(void *dev)
{
if (dev == NRF_SPIM0) {
return 0;
}
#ifdef NRF_SPIM1
else if (dev == NRF_SPIM1) {
return 1;
}
#endif
#ifdef NRF_SPIM2
else if (dev == NRF_SPIM2) {
return 2;
}
#endif /* NRF_SPIM2 */
#ifdef NRF_SPIM3
else if (dev == NRF_SPIM3) {
return 3;
}
#endif /* NRF_SPIM3 */
else {
assert(false);
return 0;
}
}
static inline size_t _i2c_dev2num(void *dev)
{
if (NRF_SPIM0_BASE == NRF_TWIM0_BASE) {
return _spi_dev2num(dev);
} else {
assert(!IS_ACTIVE(NRF_TWIM1_BASE));
/* if they are not equal (nrf528105/10/11)
TWI0 is mapped to SPI1 */
return 1;
}
}
static const IRQn_Type _isr[] = {
#if NRF_SPIM0_BASE == NRF_TWIM0_BASE
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn,
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn,
#else
SPIM0_SPIS0_SPI0_IRQn,
#if defined(NRF_SPIM1)
TWIM0_TWIS0_TWI0_SPIM1_SPIS1_SPI1_IRQn,
#else
TWIM0_TWIS0_TWI0_IRQn,
#endif
#endif
#ifdef NRF_SPIM2
SPIM2_SPIS2_SPI2_IRQn,
#endif
#ifdef NRF_SPIM3
SPIM3_IRQn,
#endif /* CPU_MODEL_NRF52840XXAA */
};
void shared_irq_register_spi(NRF_SPIM_Type *bus,
shared_irq_cb_t cb, void *arg)
{
size_t num = _spi_dev2num(bus);
_irq[num] = cb;
_irq_arg[num] = arg;
NVIC_EnableIRQ(_isr[num]);
}
void shared_irq_register_i2c(NRF_TWIM_Type *bus,
shared_irq_cb_t cb, void *arg)
{
size_t num = _i2c_dev2num(bus);
_irq[num] = cb;
_irq_arg[num] = arg;
NVIC_EnableIRQ(_isr[num]);
}
void nrf5x_i2c_acquire(NRF_TWIM_Type *bus,
shared_irq_cb_t cb, void *arg)
{
size_t num = _i2c_dev2num(bus);
mutex_lock(&_locks[num]);
_irq[num] = cb;
_irq_arg[num] = arg;
}
void nrf5x_spi_acquire(NRF_SPIM_Type *bus,
shared_irq_cb_t cb, void *arg)
{
size_t num = _spi_dev2num(bus);
mutex_lock(&_locks[num]);
_irq[num] = cb;
_irq_arg[num] = arg;
}
void nrf5x_i2c_release(NRF_TWIM_Type *bus)
{
size_t num = _i2c_dev2num(bus);
mutex_unlock(&_locks[num]);
}
void nrf5x_spi_release(NRF_SPIM_Type *bus)
{
size_t num = _spi_dev2num(bus);
mutex_unlock(&_locks[num]);
}
void ISR_SPIM0(void)
{
_irq[0](_irq_arg[0]);
cortexm_isr_end();
}
void ISR_SPIM1(void)
{
_irq[1](_irq_arg[1]);
cortexm_isr_end();
}
#ifdef NRF_SPIM2
void isr_spi2(void)
{
_irq[2](_irq_arg[2]);
cortexm_isr_end();
}
#endif
#ifdef NRF_SPIM3
void isr_spi3(void)
{
_irq[3](_irq_arg[3]);
cortexm_isr_end();
}
#endif /* NRF_SPIM3 */