From 1edc29c47f21ae5a9132db36698199f4df7f49bd Mon Sep 17 00:00:00 2001 From: Mieszko Mierunski Date: Wed, 23 May 2018 09:26:53 +0200 Subject: [PATCH] drivers: i2c: Add shims for nrfx TWI and TWIM drivers Changes add a translation layer to make nrfx TWI and TWIM drivers work with Zephyr API. Signed-off-by: Mieszko Mierunski --- drivers/i2c/CMakeLists.txt | 2 + drivers/i2c/Kconfig | 2 + drivers/i2c/Kconfig.nrfx | 99 ++++++++++++++++ drivers/i2c/i2c_nrfx_twi.c | 163 ++++++++++++++++++++++++++ drivers/i2c/i2c_nrfx_twim.c | 163 ++++++++++++++++++++++++++ ext/hal/nordic/Kconfig | 6 + ext/hal/nordic/nrfx_config_nrf51.h | 12 +- ext/hal/nordic/nrfx_config_nrf52832.h | 25 ++-- ext/hal/nordic/nrfx_config_nrf52840.h | 24 ++-- 9 files changed, 465 insertions(+), 31 deletions(-) create mode 100644 drivers/i2c/Kconfig.nrfx create mode 100644 drivers/i2c/i2c_nrfx_twi.c create mode 100644 drivers/i2c/i2c_nrfx_twim.c diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 7aa59137c96..df3712042ea 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -8,6 +8,8 @@ zephyr_library_sources_ifdef(CONFIG_I2C_ESP32 i2c_esp32.c) zephyr_library_sources_ifdef(CONFIG_I2C_GPIO i2c_gpio.c) zephyr_library_sources_ifdef(CONFIG_I2C_MCUX i2c_mcux.c) zephyr_library_sources_ifdef(CONFIG_I2C_NRF5 i2c_nrf5.c) +zephyr_library_sources_ifdef(CONFIG_NRFX_TWI i2c_nrfx_twi.c) +zephyr_library_sources_ifdef(CONFIG_NRFX_TWIM i2c_nrfx_twim.c) zephyr_library_sources_ifdef(CONFIG_I2C_QMSI i2c_qmsi.c) zephyr_library_sources_ifdef(CONFIG_I2C_QMSI_SS i2c_qmsi_ss.c) zephyr_library_sources_ifdef(CONFIG_I2C_SAM_TWI i2c_sam_twi.c) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index e07dc697037..7d3465f2b8b 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -231,6 +231,8 @@ source "drivers/i2c/Kconfig.gpio" source "drivers/i2c/Kconfig.nrf5" +source "drivers/i2c/Kconfig.nrfx" + source "drivers/i2c/Kconfig.qmsi" source "drivers/i2c/Kconfig.sbcon" diff --git a/drivers/i2c/Kconfig.nrfx b/drivers/i2c/Kconfig.nrfx new file mode 100644 index 00000000000..941766f738e --- /dev/null +++ b/drivers/i2c/Kconfig.nrfx @@ -0,0 +1,99 @@ +# Kconfig - nrfx I2C support +# +# Copyright (c) 2018, Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig I2C_NRFX + bool "nRF TWI nrfx drivers" + depends on SOC_FAMILY_NRF + help + Enable support for nrfx TWI drivers for nRF MCU series. + Peripherals with the same instance ID cannot be used together, + e.g. I2C_0 and SPI_0. You may need to disable SPI_0 or SPI_1. + +if I2C_NRFX + +# Nordic TWIx0 and SPIx0 instances can not be used at the same time. +if I2C_0 && !SPI_0 + +choice I2C_0_NRF_TYPE + prompt "I2C Port 0 Driver type" + +config I2C_0_NRF_TWI + bool "nRF TWI 0" + depends on SOC_SERIES_NRF52X || SOC_SERIES_NRF51X + select NRFX_TWI + help + Enable nRF TWI Master without EasyDMA on port 0. + +config I2C_0_NRF_TWIM + bool "nRF TWIM 0" + depends on SOC_SERIES_NRF52X + select NRFX_TWIM + help + Enable nRF TWI Master with EasyDMA on port 0. + This peripheral accepts transfers from RAM only, + if provided buffer is placed in flash, transfer will fail. + +endchoice + +config I2C_0_NRF_SDA_PIN + int "SDA pin number" + range 0 47 if SOC_NRF52840_QIAA + range 0 31 + help + GPIO pin number to use for SDA. + +config I2C_0_NRF_SCL_PIN + int "SCL pin number" + range 0 47 if SOC_NRF52840_QIAA + range 0 31 + help + GPIO pin number to use for SCL. + +endif # I2C_0 && !SPI_0 + +# Nordic TWIx1 and SPIx1 instances can not be used at the same time. +if I2C_1 && !SPI_1 + +choice I2C_1_NRF_TYPE + prompt "I2C Port 1 Driver type" + +config I2C_1_NRF_TWI + bool "nRF TWI 1" + depends on SOC_SERIES_NRF52X || SOC_SERIES_NRF51X + select NRFX_TWI + help + Enable nRF TWI Master without EasyDMA on port 1. + +config I2C_1_NRF_TWIM + bool "nRF TWIM 1" + depends on SOC_SERIES_NRF52X + select NRFX_TWIM + help + Enable nRF TWI Master with EasyDMA on port 1. + This peripheral accepts transfers from RAM only, + if provided buffer is placed in flash, transfer will fail. + +endchoice + +config I2C_1_NRF_SDA_PIN + int "SDA pin number" + range 0 47 if SOC_NRF52840_QIAA + range 0 31 + help + GPIO pin number to use for SDA. + +config I2C_1_NRF_SCL_PIN + int "SCL pin number" + range 0 47 if SOC_NRF52840_QIAA + range 0 31 + help + GPIO pin number to use for SCL. + +endif # I2C_1 && !SPI_1 + +endif #I2C_NRFX + diff --git a/drivers/i2c/i2c_nrfx_twi.c b/drivers/i2c/i2c_nrfx_twi.c new file mode 100644 index 00000000000..8479163defb --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twi.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include + +#define SYS_LOG_DOMAIN "i2c_nrfx_twi" +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL +#include + +struct i2c_nrfx_twi_data { + struct k_sem sync; + volatile nrfx_err_t res; +}; + +struct i2c_nrfx_twi_config { + nrfx_twi_t twi; +}; + +static inline struct i2c_nrfx_twi_data *get_dev_data(struct device *dev) +{ + return dev->driver_data; +} + +static inline +const struct i2c_nrfx_twi_config *get_dev_config(struct device *dev) +{ + return dev->config->config_info; +} + +static int i2c_nrfx_twi_transfer(struct device *dev, struct i2c_msg *msgs, + u8_t num_msgs, u16_t addr) +{ + for (size_t i = 0; i < num_msgs; i++) { + nrfx_twi_xfer_desc_t cur_xfer = { + .p_primary_buf = msgs[i].buf, + .primary_length = msgs[i].len, + .address = addr, + .type = (msgs[i].flags & I2C_MSG_READ) ? + NRFX_TWI_XFER_RX : NRFX_TWI_XFER_TX + }; + + nrfx_err_t res = nrfx_twi_xfer(&get_dev_config(dev)->twi, + &cur_xfer, + (msgs[i].flags & I2C_MSG_STOP) ? + 0 : NRFX_TWI_FLAG_TX_NO_STOP); + if (res != NRFX_SUCCESS) { + return -EIO; + } + + k_sem_take(&(get_dev_data(dev)->sync), K_FOREVER); + res = get_dev_data(dev)->res; + if (res != NRFX_SUCCESS) { + SYS_LOG_ERR("Error %d occurred for message %d", res, i); + return -EIO; + } + } + + return 0; +} + +static void event_handler(nrfx_twi_evt_t const *p_event, void *p_context) +{ + struct device *dev = p_context; + struct i2c_nrfx_twi_data *dev_data = get_dev_data(dev); + + switch (p_event->type) { + case NRFX_TWI_EVT_DONE: + dev_data->res = NRFX_SUCCESS; + break; + case NRFX_TWI_EVT_ADDRESS_NACK: + dev_data->res = NRFX_ERROR_DRV_TWI_ERR_ANACK; + break; + case NRFX_TWI_EVT_DATA_NACK: + dev_data->res = NRFX_ERROR_DRV_TWI_ERR_DNACK; + break; + default: + dev_data->res = NRFX_ERROR_INTERNAL; + break; + } + + k_sem_give(&dev_data->sync); +} + +static int i2c_nrfx_twi_configure(struct device *dev, u32_t dev_config) +{ + nrfx_twi_t const *inst = &(get_dev_config(dev)->twi); + + if (I2C_ADDR_10_BITS & dev_config) { + return -EINVAL; + } + + switch (I2C_SPEED_GET(dev_config)) { + case I2C_SPEED_STANDARD: + nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_100K); + break; + case I2C_SPEED_FAST: + nrf_twi_frequency_set(inst->p_twi, NRF_TWI_FREQ_400K); + break; + default: + SYS_LOG_ERR("unsupported speed"); + return -EINVAL; + } + + return 0; +} + +static const struct i2c_driver_api i2c_nrfx_twi_driver_api = { + .configure = i2c_nrfx_twi_configure, + .transfer = i2c_nrfx_twi_transfer, +}; + +static int init_twi(struct device *dev, const nrfx_twi_config_t *config) +{ + nrfx_err_t result = nrfx_twi_init(&get_dev_config(dev)->twi, config, + event_handler, dev); + if (result != NRFX_SUCCESS) { + SYS_LOG_ERR("Failed to initialize device: %s", + dev->config->name); + return -EBUSY; + } + + nrfx_twi_enable(&get_dev_config(dev)->twi); + return 0; +} + +#define I2C_NRFX_TWI_DEVICE(idx) \ + static int twi_##idx##_init(struct device *dev) \ + { \ + IRQ_CONNECT(CONFIG_I2C_##idx##_IRQ, \ + CONFIG_I2C_##idx##_IRQ_PRI, \ + nrfx_isr, nrfx_twi_##idx##_irq_handler, 0); \ + const nrfx_twi_config_t config = { \ + .scl = CONFIG_I2C_##idx##_NRF_SCL_PIN, \ + .sda = CONFIG_I2C_##idx##_NRF_SDA_PIN, \ + .frequency = NRF_TWI_FREQ_100K, \ + }; \ + return init_twi(dev, &config); \ + } \ + static struct i2c_nrfx_twi_data twi_##idx##_data = { \ + .sync = _K_SEM_INITIALIZER(twi_##idx##_data.sync, 0, 1) \ + }; \ + static const struct i2c_nrfx_twi_config twi_##idx##_config = { \ + .twi = NRFX_TWI_INSTANCE(idx) \ + }; \ + DEVICE_AND_API_INIT(twi_##idx, CONFIG_I2C_##idx##_NAME, \ + twi_##idx##_init, &twi_##idx##_data, \ + &twi_##idx##_config, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &i2c_nrfx_twi_driver_api) + +#ifdef CONFIG_I2C_0_NRF_TWI +I2C_NRFX_TWI_DEVICE(0); +#endif + +#ifdef CONFIG_I2C_1_NRF_TWI +I2C_NRFX_TWI_DEVICE(1); +#endif + diff --git a/drivers/i2c/i2c_nrfx_twim.c b/drivers/i2c/i2c_nrfx_twim.c new file mode 100644 index 00000000000..3c8a12d2a41 --- /dev/null +++ b/drivers/i2c/i2c_nrfx_twim.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2018, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include + +#define SYS_LOG_DOMAIN "i2c_nrfx_twim" +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL +#include + +struct i2c_nrfx_twim_data { + struct k_sem sync; + volatile nrfx_err_t res; +}; + +struct i2c_nrfx_twim_config { + nrfx_twim_t twim; +}; + +static inline struct i2c_nrfx_twim_data *get_dev_data(struct device *dev) +{ + return dev->driver_data; +} + +static inline +const struct i2c_nrfx_twim_config *get_dev_config(struct device *dev) +{ + return dev->config->config_info; +} + +static int i2c_nrfx_twim_transfer(struct device *dev, struct i2c_msg *msgs, + u8_t num_msgs, u16_t addr) +{ + for (size_t i = 0; i < num_msgs; i++) { + nrfx_twim_xfer_desc_t cur_xfer = { + .p_primary_buf = msgs[i].buf, + .primary_length = msgs[i].len, + .address = addr, + .type = (msgs[i].flags & I2C_MSG_READ) ? + NRFX_TWIM_XFER_RX : NRFX_TWIM_XFER_TX + }; + + nrfx_err_t res = nrfx_twim_xfer(&get_dev_config(dev)->twim, + &cur_xfer, + (msgs[i].flags & I2C_MSG_STOP) ? + 0 : NRFX_TWIM_FLAG_TX_NO_STOP); + if (res != NRFX_SUCCESS) { + return -EIO; + } + + k_sem_take(&(get_dev_data(dev)->sync), K_FOREVER); + res = get_dev_data(dev)->res; + if (res != NRFX_SUCCESS) { + SYS_LOG_ERR("Error %d occurred for message %d", res, i); + return -EIO; + } + } + + return 0; +} + +static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context) +{ + struct device *dev = p_context; + struct i2c_nrfx_twim_data *dev_data = get_dev_data(dev); + + switch (p_event->type) { + case NRFX_TWIM_EVT_DONE: + dev_data->res = NRFX_SUCCESS; + break; + case NRFX_TWIM_EVT_ADDRESS_NACK: + dev_data->res = NRFX_ERROR_DRV_TWI_ERR_ANACK; + break; + case NRFX_TWIM_EVT_DATA_NACK: + dev_data->res = NRFX_ERROR_DRV_TWI_ERR_DNACK; + break; + default: + dev_data->res = NRFX_ERROR_INTERNAL; + break; + } + + k_sem_give(&dev_data->sync); +} + +static int i2c_nrfx_twim_configure(struct device *dev, u32_t dev_config) +{ + nrfx_twim_t const *inst = &(get_dev_config(dev)->twim); + + if (I2C_ADDR_10_BITS & dev_config) { + return -EINVAL; + } + + switch (I2C_SPEED_GET(dev_config)) { + case I2C_SPEED_STANDARD: + nrf_twim_frequency_set(inst->p_twim, NRF_TWIM_FREQ_100K); + break; + case I2C_SPEED_FAST: + nrf_twim_frequency_set(inst->p_twim, NRF_TWIM_FREQ_400K); + break; + default: + SYS_LOG_ERR("unsupported speed"); + return -EINVAL; + } + + return 0; +} + +static const struct i2c_driver_api i2c_nrfx_twim_driver_api = { + .configure = i2c_nrfx_twim_configure, + .transfer = i2c_nrfx_twim_transfer, +}; + +static int init_twim(struct device *dev, const nrfx_twim_config_t *config) +{ + nrfx_err_t result = nrfx_twim_init(&get_dev_config(dev)->twim, config, + event_handler, dev); + if (result != NRFX_SUCCESS) { + SYS_LOG_ERR("Failed to initialize device: %s", + dev->config->name); + return -EBUSY; + } + + nrfx_twim_enable(&get_dev_config(dev)->twim); + return 0; +} + +#define I2C_NRFX_TWIM_DEVICE(idx) \ + static int twim_##idx##_init(struct device *dev) \ + { \ + IRQ_CONNECT(CONFIG_I2C_##idx##_IRQ, \ + CONFIG_I2C_##idx##_IRQ_PRI, \ + nrfx_isr, nrfx_twim_##idx##_irq_handler, 0);\ + const nrfx_twim_config_t config = { \ + .scl = CONFIG_I2C_##idx##_NRF_SCL_PIN, \ + .sda = CONFIG_I2C_##idx##_NRF_SDA_PIN, \ + .frequency = NRF_TWIM_FREQ_100K, \ + }; \ + return init_twim(dev, &config); \ + } \ + static struct i2c_nrfx_twim_data twim_##idx##_data = { \ + .sync = _K_SEM_INITIALIZER(twim_##idx##_data.sync, 0, 1)\ + }; \ + static const struct i2c_nrfx_twim_config twim_##idx##_config = {\ + .twim = NRFX_TWIM_INSTANCE(idx) \ + }; \ + DEVICE_AND_API_INIT(twim_##idx, CONFIG_I2C_##idx##_NAME, \ + twim_##idx##_init, &twim_##idx##_data, \ + &twim_##idx##_config, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, \ + &i2c_nrfx_twim_driver_api) + +#ifdef CONFIG_I2C_0_NRF_TWIM +I2C_NRFX_TWIM_DEVICE(0); +#endif + +#ifdef CONFIG_I2C_1_NRF_TWIM +I2C_NRFX_TWIM_DEVICE(1); +#endif + diff --git a/ext/hal/nordic/Kconfig b/ext/hal/nordic/Kconfig index 88532c55911..b1671939602 100644 --- a/ext/hal/nordic/Kconfig +++ b/ext/hal/nordic/Kconfig @@ -19,5 +19,11 @@ config NRFX_SPIM config NRFX_SPIS bool +config NRFX_TWI + bool + +config NRFX_TWIM + bool + config NRFX_WDT bool diff --git a/ext/hal/nordic/nrfx_config_nrf51.h b/ext/hal/nordic/nrfx_config_nrf51.h index 2fdb1cf4512..18328cd5c68 100644 --- a/ext/hal/nordic/nrfx_config_nrf51.h +++ b/ext/hal/nordic/nrfx_config_nrf51.h @@ -1287,21 +1287,21 @@ // NRFX_TWI_ENABLED - nrfx_twi - TWI peripheral driver //========================================================== -#ifndef NRFX_TWI_ENABLED -#define NRFX_TWI_ENABLED 0 +#ifdef CONFIG_NRFX_TWI +#define NRFX_TWI_ENABLED 1 #endif // NRFX_TWI0_ENABLED - Enable TWI0 instance -#ifndef NRFX_TWI0_ENABLED -#define NRFX_TWI0_ENABLED 0 +#ifdef CONFIG_I2C_0_NRF_TWI +#define NRFX_TWI0_ENABLED 1 #endif // NRFX_TWI1_ENABLED - Enable TWI1 instance -#ifndef NRFX_TWI1_ENABLED -#define NRFX_TWI1_ENABLED 0 +#ifdef CONFIG_I2C_1_NRF_TWI +#define NRFX_TWI1_ENABLED 1 #endif // NRFX_TWI_DEFAULT_CONFIG_FREQUENCY - Frequency diff --git a/ext/hal/nordic/nrfx_config_nrf52832.h b/ext/hal/nordic/nrfx_config_nrf52832.h index 04209aa3625..7f024e9578c 100644 --- a/ext/hal/nordic/nrfx_config_nrf52832.h +++ b/ext/hal/nordic/nrfx_config_nrf52832.h @@ -2210,21 +2210,21 @@ // NRFX_TWIM_ENABLED - nrfx_twim - TWIM peripheral driver //========================================================== -#ifndef NRFX_TWIM_ENABLED -#define NRFX_TWIM_ENABLED 0 +#ifdef CONFIG_NRFX_TWIM +#define NRFX_TWIM_ENABLED 1 #endif // NRFX_TWIM0_ENABLED - Enable TWIM0 instance -#ifndef NRFX_TWIM0_ENABLED -#define NRFX_TWIM0_ENABLED 0 +#ifdef CONFIG_I2C_0_NRF_TWIM +#define NRFX_TWIM0_ENABLED 1 #endif // NRFX_TWIM1_ENABLED - Enable TWIM1 instance -#ifndef NRFX_TWIM1_ENABLED -#define NRFX_TWIM1_ENABLED 0 +#ifdef CONFIG_I2C_1_NRF_TWIM +#define NRFX_TWIM1_ENABLED 1 #endif // NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY - Frequency @@ -2462,21 +2462,20 @@ // NRFX_TWI_ENABLED - nrfx_twi - TWI peripheral driver //========================================================== -#ifndef NRFX_TWI_ENABLED -#define NRFX_TWI_ENABLED 0 +#ifdef CONFIG_NRFX_TWI +#define NRFX_TWI_ENABLED 1 #endif // NRFX_TWI0_ENABLED - Enable TWI0 instance -#ifndef NRFX_TWI0_ENABLED -#define NRFX_TWI0_ENABLED 0 +#ifdef CONFIG_I2C_0_NRF_TWI +#define NRFX_TWI0_ENABLED 1 #endif // NRFX_TWI1_ENABLED - Enable TWI1 instance - -#ifndef NRFX_TWI1_ENABLED -#define NRFX_TWI1_ENABLED 0 +#ifdef CONFIG_I2C_1_NRF_TWI +#define NRFX_TWI1_ENABLED 1 #endif // NRFX_TWI_DEFAULT_CONFIG_FREQUENCY - Frequency diff --git a/ext/hal/nordic/nrfx_config_nrf52840.h b/ext/hal/nordic/nrfx_config_nrf52840.h index 749a00ccfa6..32015708014 100644 --- a/ext/hal/nordic/nrfx_config_nrf52840.h +++ b/ext/hal/nordic/nrfx_config_nrf52840.h @@ -2313,21 +2313,21 @@ // NRFX_TWIM_ENABLED - nrfx_twim - TWIM peripheral driver //========================================================== -#ifndef NRFX_TWIM_ENABLED -#define NRFX_TWIM_ENABLED 0 +#ifdef CONFIG_NRFX_TWIM +#define NRFX_TWIM_ENABLED 1 #endif // NRFX_TWIM0_ENABLED - Enable TWIM0 instance -#ifndef NRFX_TWIM0_ENABLED -#define NRFX_TWIM0_ENABLED 0 +#ifdef CONFIG_I2C_0_NRF_TWIM +#define NRFX_TWIM0_ENABLED 1 #endif // NRFX_TWIM1_ENABLED - Enable TWIM1 instance -#ifndef NRFX_TWIM1_ENABLED -#define NRFX_TWIM1_ENABLED 0 +#ifdef CONFIG_I2C_1_NRF_TWIM +#define NRFX_TWIM1_ENABLED 1 #endif // NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY - Frequency @@ -2552,21 +2552,21 @@ // NRFX_TWI_ENABLED - nrfx_twi - TWI peripheral driver //========================================================== -#ifndef NRFX_TWI_ENABLED -#define NRFX_TWI_ENABLED 0 +#ifdef CONFIG_NRFX_TWI +#define NRFX_TWI_ENABLED 1 #endif // NRFX_TWI0_ENABLED - Enable TWI0 instance -#ifndef NRFX_TWI0_ENABLED -#define NRFX_TWI0_ENABLED 0 +#ifdef CONFIG_I2C_0_NRF_TWI +#define NRFX_TWI0_ENABLED 1 #endif // NRFX_TWI1_ENABLED - Enable TWI1 instance -#ifndef NRFX_TWI1_ENABLED -#define NRFX_TWI1_ENABLED 0 +#ifdef CONFIG_I2C_1_NRF_TWI +#define NRFX_TWI1_ENABLED 1 #endif // NRFX_TWI_DEFAULT_CONFIG_FREQUENCY - Frequency