diff --git a/cpu/nrf52/include/periph_cpu.h b/cpu/nrf52/include/periph_cpu.h index 7f3bef6051..ae3ca87a8f 100644 --- a/cpu/nrf52/include/periph_cpu.h +++ b/cpu/nrf52/include/periph_cpu.h @@ -264,6 +264,38 @@ void spi_twi_irq_register_spi(NRF_SPIM_Type *bus, void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); +/** + * @brief Acquire the shared I2C/SPI peripheral in I2C mode + * + * @param bus bus to acquire exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument + */ +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); + +/** + * @brief Release the shared I2C/SPI peripheral in I2C mode + * + * @param bus bus to release exclusive access on + */ +void nrf5x_i2c_release(NRF_TWIM_Type *bus); + +/** + * @brief Acquire the shared I2C/SPI peripheral in SPI mode + * + * @param bus bus to release exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument + */ +void nrf5x_spi_acquire(NRF_SPIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); + +/** + * @brief Acquire the shared I2C/SPI peripheral in SPI mode + * + * @param bus bus to release exclusive access on + */ +void nrf5x_spi_release(NRF_SPIM_Type *bus); + /** * @brief USBDEV buffers must be word aligned because of DMA restrictions */ diff --git a/cpu/nrf52/spi_twi_irq.c b/cpu/nrf52/spi_twi_irq.c index 73fa24751d..30083c16a9 100644 --- a/cpu/nrf52/spi_twi_irq.c +++ b/cpu/nrf52/spi_twi_irq.c @@ -24,6 +24,7 @@ #include #include "cpu.h" +#include "mutex.h" #include "periph_cpu.h" #if NRF_SPIM0_BASE != NRF_TWIM0_BASE @@ -59,6 +60,8 @@ static spi_twi_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) { @@ -137,9 +140,40 @@ void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, _irq[num] = cb; _irq_arg[num] = arg; + NVIC_EnableIRQ(_isr[num]); } +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, + spi_twi_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, + spi_twi_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]); diff --git a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c index 8069051535..0c9070ad16 100644 --- a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c +++ b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c @@ -102,8 +102,18 @@ static void _init_pins(i2c_t dev) { gpio_init(i2c_config[dev].scl, GPIO_IN_OD_PU); gpio_init(i2c_config[dev].sda, GPIO_IN_OD_PU); +} + +/* Beware: This needs to be kept in sync with the SPI version of this. + * Specifically, when registers are configured that are valid to the peripheral + * in both SPI and I2C mode, the register needs to be configured in both the I2C + * and the SPI variant of _setup_shared_peripheral() to avoid from parameters + * leaking from one bus into the other */ +static void _setup_shared_peripheral(i2c_t dev) +{ bus(dev)->PSEL.SCL = i2c_config[dev].scl; bus(dev)->PSEL.SDA = i2c_config[dev].sda; + bus(dev)->FREQUENCY = i2c_config[dev].speed; } void i2c_init(i2c_t dev) @@ -111,7 +121,6 @@ void i2c_init(i2c_t dev) assert(dev < I2C_NUMOF); /* Initialize mutex */ - mutex_init(&locks[dev]); mutex_init(&busy[dev]); mutex_lock(&busy[dev]); @@ -122,8 +131,8 @@ void i2c_init(i2c_t dev) /* configure pins */ _init_pins(dev); - /* configure dev clock speed */ - bus(dev)->FREQUENCY = i2c_config[dev].speed; + /* configure shared periphal speed */ + _setup_shared_peripheral(dev); spi_twi_irq_register_i2c(bus(dev), i2c_isr_handler, (void *)(uintptr_t)dev); @@ -158,7 +167,13 @@ void i2c_acquire(i2c_t dev) { assert(dev < I2C_NUMOF); - mutex_lock(&locks[dev]); + if (IS_USED(MODULE_PERIPH_I2C_RECONFIGURE)) { + mutex_lock(&locks[dev]); + } + + nrf5x_i2c_acquire(bus(dev), i2c_isr_handler, (void *)(uintptr_t)dev); + _setup_shared_peripheral(dev); + bus(dev)->ENABLE = TWIM_ENABLE_ENABLE_Enabled; DEBUG("[i2c] acquired dev %i\n", (int)dev); @@ -169,7 +184,12 @@ void i2c_release(i2c_t dev) assert(dev < I2C_NUMOF); bus(dev)->ENABLE = TWIM_ENABLE_ENABLE_Disabled; - mutex_unlock(&locks[dev]); + + if (IS_USED(MODULE_PERIPH_I2C_RECONFIGURE)) { + mutex_unlock(&locks[dev]); + } + + nrf5x_i2c_release(bus(dev)); DEBUG("[i2c] released dev %i\n", (int)dev); } diff --git a/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c b/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c index 6161a2fb1f..e14e8d7062 100644 --- a/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c +++ b/cpu/nrf5x_common/periph/spi_nrf52_nrf9160.c @@ -123,16 +123,28 @@ static void _clear_workaround(spi_t bus) #endif } +/* Beware: This needs to be kept in sync with the I2C version of this. + * Specifically, when registers are configured that are valid to the peripheral + * in both SPI and I2C mode, the register needs to be configured in both the I2C + * and the SPI variant of _setup_shared_peripheral() to avoid from parameters + * leaking from one bus into the other */ +static void _setup_shared_peripheral(spi_t bus) +{ + SPI_SCKSEL = spi_config[bus].sclk; + SPI_MOSISEL = spi_config[bus].mosi; + SPI_MISOSEL = spi_config[bus].miso; +} + void spi_init(spi_t bus) { assert(bus < SPI_NUMOF); /* initialize mutex */ - mutex_init(&locks[bus]); mutex_init(&busy[bus]); mutex_lock(&busy[bus]); /* initialize pins */ spi_init_pins(bus); + _setup_shared_peripheral(bus); } int spi_init_with_gpio_mode(spi_t bus, const spi_gpio_mode_t* mode) @@ -165,9 +177,6 @@ void spi_init_pins(spi_t bus) spi_init_with_gpio_mode(bus, &gpio_modes); /* select pins for the SPI device */ - SPI_SCKSEL = spi_config[bus].sclk; - SPI_MOSISEL = spi_config[bus].mosi; - SPI_MISOSEL = spi_config[bus].miso; _setup_workaround_for_ftpan_58(bus); spi_twi_irq_register_spi(dev(bus), spi_isr_handler, (void *)(uintptr_t)bus); } @@ -177,7 +186,13 @@ void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) (void)cs; assert((unsigned)bus < SPI_NUMOF); - mutex_lock(&locks[bus]); + if (IS_USED(MODULE_PERIPH_SPI_RECONFIGURE)) { + mutex_lock(&locks[bus]); + } + + nrf5x_spi_acquire(dev(bus), spi_isr_handler, (void *)(uintptr_t)bus); + _setup_shared_peripheral(bus); + /* configure bus */ dev(bus)->CONFIG = mode; dev(bus)->FREQUENCY = clk; @@ -189,7 +204,12 @@ void spi_release(spi_t bus) { /* power off everything */ dev(bus)->ENABLE = 0; - mutex_unlock(&locks[bus]); + + if (IS_USED(MODULE_PERIPH_SPI_RECONFIGURE)) { + mutex_unlock(&locks[bus]); + } + + nrf5x_spi_release(dev(bus)); } static size_t _transfer(spi_t bus, const uint8_t *out_buf, uint8_t *in_buf, diff --git a/cpu/nrf9160/include/periph_cpu.h b/cpu/nrf9160/include/periph_cpu.h index a0576bc217..7e162da886 100644 --- a/cpu/nrf9160/include/periph_cpu.h +++ b/cpu/nrf9160/include/periph_cpu.h @@ -208,6 +208,38 @@ void spi_twi_irq_register_spi(NRF_SPIM_Type *bus, void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); +/** + * @brief Acquire the shared I2C/SPI peripheral in I2C mode + * + * @param bus bus to acquire exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument + */ +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); + +/** + * @brief Release the shared I2C/SPI peripheral in I2C mode + * + * @param bus bus to release exclusive access on + */ +void nrf5x_i2c_release(NRF_TWIM_Type *bus); + +/** + * @brief Acquire the shared I2C/SPI peripheral in SPI mode + * + * @param bus bus to release exclusive access on + * @param cb ISR handler to call on IRQ + * @param arg ISR handler argument + */ +void nrf5x_spi_acquire(NRF_SPIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); + +/** + * @brief Acquire the shared I2C/SPI peripheral in SPI mode + * + * @param bus bus to release exclusive access on + */ +void nrf5x_spi_release(NRF_SPIM_Type *bus); + #ifdef __cplusplus } #endif diff --git a/cpu/nrf9160/spi_twi_irq.c b/cpu/nrf9160/spi_twi_irq.c index 8aad154a9f..ee98dfea06 100644 --- a/cpu/nrf9160/spi_twi_irq.c +++ b/cpu/nrf9160/spi_twi_irq.c @@ -24,12 +24,15 @@ #include #include "cpu.h" +#include "mutex.h" #include "periph_cpu.h" #include "periph_conf.h" static spi_twi_irq_cb_t _irq[TWIM_COUNT]; static void *_irq_arg[TWIM_COUNT]; +static mutex_t _locks[SPIM_COUNT]; + #if TWIM_COUNT != SPIM_COUNT #error Possible configuration issue, please update this file #endif @@ -88,6 +91,36 @@ void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, NVIC_EnableIRQ(_isr[num]); } +void nrf5x_i2c_acquire(NRF_TWIM_Type *bus, + spi_twi_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, + spi_twi_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]); +} + /* Check if UART driver doesn't already use the same IRQ */ #ifndef UART_0_ISR void isr_uarte0_spim0_spis0_twim0_twis0(void)