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 <mieszko.mierunski@nordicsemi.no>
This commit is contained in:
Mieszko Mierunski 2018-05-23 09:26:53 +02:00 committed by Carles Cufí
commit 1edc29c47f
9 changed files with 465 additions and 31 deletions

View file

@ -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)

View file

@ -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"

99
drivers/i2c/Kconfig.nrfx Normal file
View file

@ -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

163
drivers/i2c/i2c_nrfx_twi.c Normal file
View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2018, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <i2c.h>
#include <nrfx_twi.h>
#define SYS_LOG_DOMAIN "i2c_nrfx_twi"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
#include <logging/sys_log.h>
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

163
drivers/i2c/i2c_nrfx_twim.c Normal file
View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2018, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <i2c.h>
#include <nrfx_twim.h>
#define SYS_LOG_DOMAIN "i2c_nrfx_twim"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
#include <logging/sys_log.h>
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

View file

@ -19,5 +19,11 @@ config NRFX_SPIM
config NRFX_SPIS
bool
config NRFX_TWI
bool
config NRFX_TWIM
bool
config NRFX_WDT
bool

View file

@ -1287,21 +1287,21 @@
// <e> 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
// <q> 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
// <q> 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
// <o> NRFX_TWI_DEFAULT_CONFIG_FREQUENCY - Frequency

View file

@ -2210,21 +2210,21 @@
// <e> 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
// <q> 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
// <q> 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
// <o> NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY - Frequency
@ -2462,21 +2462,20 @@
// <e> 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
// <q> 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
// <q> 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
// <o> NRFX_TWI_DEFAULT_CONFIG_FREQUENCY - Frequency

View file

@ -2313,21 +2313,21 @@
// <e> 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
// <q> 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
// <q> 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
// <o> NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY - Frequency
@ -2552,21 +2552,21 @@
// <e> 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
// <q> 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
// <q> 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
// <o> NRFX_TWI_DEFAULT_CONFIG_FREQUENCY - Frequency