drivers: i2c: stm32 LL F1/F4 (v1) STM32 F3/L4X (v2)

Supports STM32 F1/F4 (v1 controller) and STM32 F3/L4X (v2
controller)

v1 could also support L1X.
v2 could also support F7X.

Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
Signed-off-by: Yannis Damigos <giannis.damigos@gmail.com>
Reviewed-by: Yannis Damigos <giannis.damigos@gmail.com>
Tested-by: Yannis Damigos <giannis.damigos@gmail.com>
Tested-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
This commit is contained in:
Jorge Ramirez-Ortiz 2017-06-23 10:51:27 +02:00 committed by Anas Nashif
commit 21fbc9b07e
12 changed files with 1040 additions and 739 deletions

View file

@ -14,5 +14,6 @@ config SOC_SERIES_STM32F1X
select HAS_STM32CUBE select HAS_STM32CUBE
select CPU_HAS_SYSTICK select CPU_HAS_SYSTICK
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
select I2C_STM32_V1 if I2C
help help
Enable support for STM32F1 MCU series Enable support for STM32F1 MCU series

View file

@ -15,5 +15,6 @@ config SOC_SERIES_STM32F3X
select CPU_HAS_SYSTICK select CPU_HAS_SYSTICK
select HAS_STM32CUBE select HAS_STM32CUBE
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
select I2C_STM32_V2 if I2C
help help
Enable support for STM32F3 MCU series Enable support for STM32F3 MCU series

View file

@ -16,5 +16,6 @@ config SOC_SERIES_STM32F4X
select CPU_HAS_MPU select CPU_HAS_MPU
select CPU_HAS_SYSTICK select CPU_HAS_SYSTICK
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
select I2C_STM32_V1 if I2C
help help
Enable support for STM32F4 MCU series Enable support for STM32F4 MCU series

View file

@ -15,5 +15,6 @@ config SOC_SERIES_STM32L4X
select CPU_HAS_MPU select CPU_HAS_MPU
select CPU_HAS_SYSTICK select CPU_HAS_SYSTICK
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
select I2C_STM32_V2 if I2C
help help
Enable support for STM32L4 MCU series Enable support for STM32L4 MCU series

View file

@ -90,19 +90,30 @@ config I2C_NRF5_GPIO_SCL_PIN
help help
The GPIO pin to use for SCL. The GPIO pin to use for SCL.
config I2C_STM32LX config I2C_STM32_V1
bool "STM32Lx MCU I2C Driver" bool "STM32 V1 Driver (F1/F4X)"
depends on SOC_FAMILY_STM32 && SOC_SERIES_STM32L4X depends on SOC_FAMILY_STM32
depends on SOC_SERIES_STM32F1X || SOC_SERIES_STM32F4X
default n default n
help help
Enable I2C support on the STM32Lxx family of processors. Enable I2C support on the STM32 F1 and F4X family of processors. This
driver also supports the F2 and L1 series.
config I2C_STM32LX_INTERRUPT config I2C_STM32_V2
bool "STM32Lx MCU I2C Interrupt Support" bool "STM32 V2 Driver (F3/L4X)"
depends on I2C_STM32LX depends on SOC_FAMILY_STM32
depends on SOC_SERIES_STM32F3X || SOC_SERIES_STM32L4X
default n default n
help help
Enable Interrupt support for the I2C Driver of STM32Lxx family. Enable I2C support on the STM32 F3 and L4X family of processors. This
driver also supports the F0, F7 and L0 series.
config I2C_STM32_INTERRUPT
bool "STM32 MCU I2C Interrupt Support"
depends on I2C_STM32_V1 || I2C_STM32_V2
default n
help
Enable Interrupt support for the I2C Driver
config I2C_BITBANG config I2C_BITBANG
bool bool
@ -252,6 +263,32 @@ config I2C_2_IRQ_PRI
help help
IRQ priority. IRQ priority.
config I2C_3
bool "Enable I2C Port 3"
default n
config I2C_3_NAME
string "Port 3 device name"
depends on I2C_3
default "I2C_3"
config I2C_3_DEFAULT_CFG
hex "Port 3 default configuration"
depends on I2C_3
default 0x0
help
Allows the I2C port to be brought up with a default configuration.
This is useful to set if other drivers depend upon using the I2C bus
before the application has a chance to custom configure the port.
Setting this value does not prohibit the application from customizing
the values later. Refer to include/i2c.h file for proper values.
config I2C_3_IRQ_PRI
int "Port 3 interrupt priority"
depends on I2C_3
help
IRQ priority.
config I2C_SS_0 config I2C_SS_0
bool "Enable I2C_SS_0" bool "Enable I2C_SS_0"
depends on I2C_QMSI_SS depends on I2C_QMSI_SS

View file

@ -7,5 +7,6 @@ obj-$(CONFIG_I2C_NRF5) += i2c_nrf5.o
obj-$(CONFIG_I2C_QMSI) += i2c_qmsi.o obj-$(CONFIG_I2C_QMSI) += i2c_qmsi.o
obj-$(CONFIG_I2C_QMSI_SS) += i2c_qmsi_ss.o obj-$(CONFIG_I2C_QMSI_SS) += i2c_qmsi_ss.o
obj-$(CONFIG_I2C_SBCON) += i2c_sbcon.o obj-$(CONFIG_I2C_SBCON) += i2c_sbcon.o
obj-$(CONFIG_I2C_STM32LX) += i2c_stm32lx.o obj-$(CONFIG_I2C_STM32_V1) += i2c_ll_stm32_v1.o i2c_ll_stm32.o
obj-$(CONFIG_I2C_STM32_V2) += i2c_ll_stm32_v2.o i2c_ll_stm32.o
obj-$(CONFIG_TWIHS_SAM) += twihs_sam.o obj-$(CONFIG_TWIHS_SAM) += twihs_sam.o

241
drivers/i2c/i2c_ll_stm32.c Normal file
View file

@ -0,0 +1,241 @@
/*
* Copyright (c) 2016 BayLibre, SAS
* Copyright (c) 2017 Linaro Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <clock_control/stm32_clock_control.h>
#include <clock_control.h>
#include <misc/util.h>
#include <kernel.h>
#include <board.h>
#include <errno.h>
#include <i2c.h>
#include "i2c_ll_stm32.h"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
#include <logging/sys_log.h>
static int i2c_stm32_runtime_configure(struct device *dev, u32_t config)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
u32_t clock;
if (data->dev_config.bits.is_slave_read)
return -EINVAL;
data->dev_config.raw = config;
clock_control_get_rate(device_get_binding(STM32_CLOCK_CONTROL_NAME),
(clock_control_subsys_t *) &cfg->pclken, &clock);
LL_I2C_Disable(i2c);
LL_I2C_SetMode(i2c, LL_I2C_MODE_I2C);
return stm32_i2c_configure_timing(dev, clock);
}
#define OPERATION(msg) (((struct i2c_msg *) msg)->flags & I2C_MSG_RW_MASK)
static int i2c_stm32_transfer(struct device *dev, struct i2c_msg *msg,
u8_t num_msgs, u16_t slave)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_msg *current, *next;
I2C_TypeDef *i2c = cfg->i2c;
int ret = 0;
LL_I2C_Enable(i2c);
current = msg;
while (num_msgs > 0) {
unsigned int flags = 0;
if (current->len > 255)
return -EINVAL;
/* do NOT issue the i2c stop condition at the end of transfer */
if (num_msgs > 1) {
next = current + 1;
if (OPERATION(current) != OPERATION(next)) {
flags = I2C_MSG_RESTART;
}
}
if ((current->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
ret = stm32_i2c_msg_write(dev, current, flags, slave);
} else {
ret = stm32_i2c_msg_read(dev, current, flags, slave);
}
if (ret < 0) {
break;
}
current++;
num_msgs--;
};
LL_I2C_Disable(i2c);
return ret;
}
static const struct i2c_driver_api api_funcs = {
.configure = i2c_stm32_runtime_configure,
.transfer = i2c_stm32_transfer,
};
static int i2c_stm32_init(struct device *dev)
{
struct device *clock = device_get_binding(STM32_CLOCK_CONTROL_NAME);
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
int ret;
__ASSERT_NO_MSG(clock);
clock_control_on(clock, (clock_control_subsys_t *) &cfg->pclken);
ret = i2c_stm32_runtime_configure(dev, data->dev_config.raw);
if (ret < 0) {
SYS_LOG_ERR("i2c: failure initializing");
return ret;
}
#ifdef CONFIG_I2C_STM32_INTERRUPT
k_sem_init(&data->device_sync_sem, 0, UINT_MAX);
cfg->irq_config_func(dev);
#endif
return 0;
}
#ifdef CONFIG_I2C_1
#ifdef CONFIG_I2C_STM32_INTERRUPT
static void i2c_stm32_irq_config_func_1(struct device *port);
#endif
static const struct i2c_stm32_config i2c_stm32_cfg_1 = {
.i2c = (I2C_TypeDef *) I2C1_BASE,
.pclken = {
.enr = LL_APB1_GRP1_PERIPH_I2C1,
.bus = STM32_CLOCK_BUS_APB1,
},
#ifdef CONFIG_I2C_STM32_INTERRUPT
.irq_config_func = i2c_stm32_irq_config_func_1,
#endif
};
static struct i2c_stm32_data i2c_stm32_dev_data_1 = {
.dev_config.raw = CONFIG_I2C_1_DEFAULT_CFG,
};
DEVICE_AND_API_INIT(i2c_stm32_1, CONFIG_I2C_1_NAME, &i2c_stm32_init,
&i2c_stm32_dev_data_1, &i2c_stm32_cfg_1,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&api_funcs);
#ifdef CONFIG_I2C_STM32_INTERRUPT
static void i2c_stm32_irq_config_func_1(struct device *dev)
{
IRQ_CONNECT(I2C1_EV_IRQn, CONFIG_I2C_1_IRQ_PRI,
stm32_i2c_event_isr, DEVICE_GET(i2c_stm32_1), 0);
irq_enable(I2C1_EV_IRQn);
IRQ_CONNECT(I2C1_ER_IRQn, CONFIG_I2C_1_IRQ_PRI,
stm32_i2c_error_isr, DEVICE_GET(i2c_stm32_1), 0);
irq_enable(I2C1_ER_IRQn);
}
#endif
#endif /* CONFIG_I2C_1 */
#ifdef CONFIG_I2C_2
#ifdef CONFIG_I2C_STM32_INTERRUPT
static void i2c_stm32_irq_config_func_2(struct device *port);
#endif
static const struct i2c_stm32_config i2c_stm32_cfg_2 = {
.i2c = (I2C_TypeDef *) I2C2_BASE,
.pclken = {
.enr = LL_APB1_GRP1_PERIPH_I2C2,
.bus = STM32_CLOCK_BUS_APB1,
},
#ifdef CONFIG_I2C_STM32_INTERRUPT
.irq_config_func = i2c_stm32_irq_config_func_2,
#endif
};
static struct i2c_stm32_data i2c_stm32_dev_data_2 = {
.dev_config.raw = CONFIG_I2C_2_DEFAULT_CFG,
};
DEVICE_AND_API_INIT(i2c_stm32_2, CONFIG_I2C_2_NAME, &i2c_stm32_init,
&i2c_stm32_dev_data_2, &i2c_stm32_cfg_2,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&api_funcs);
#ifdef CONFIG_I2C_STM32_INTERRUPT
static void i2c_stm32_irq_config_func_2(struct device *dev)
{
IRQ_CONNECT(I2C2_EV_IRQn, CONFIG_I2C_2_IRQ_PRI,
stm32_i2c_event_isr, DEVICE_GET(i2c_stm32_2), 0);
irq_enable(I2C2_EV_IRQn);
IRQ_CONNECT(I2C2_ER_IRQn, CONFIG_I2C_2_IRQ_PRI,
stm32_i2c_error_isr, DEVICE_GET(i2c_stm32_2), 0);
irq_enable(I2C2_ER_IRQn);
}
#endif
#endif /* CONFIG_I2C_2 */
#ifdef CONFIG_I2C_3
#ifndef I2C3_BASE
#error "I2C_3 is not available on the platform that you selected"
#endif /* I2C3_BASE */
#ifdef CONFIG_I2C_STM32_INTERRUPT
static void i2c_stm32_irq_config_func_3(struct device *port);
#endif
static const struct i2c_stm32_config i2c_stm32_cfg_3 = {
.i2c = (I2C_TypeDef *) I2C3_BASE,
.pclken = {
.enr = LL_APB1_GRP1_PERIPH_I2C3,
.bus = STM32_CLOCK_BUS_APB1,
},
#ifdef CONFIG_I2C_STM32_INTERRUPT
.irq_config_func = i2c_stm32_irq_config_func_3,
#endif
};
static struct i2c_stm32_data i2c_stm32_dev_data_3 = {
.dev_config.raw = CONFIG_I2C_3_DEFAULT_CFG,
};
DEVICE_AND_API_INIT(i2c_stm32_3, CONFIG_I2C_3_NAME, &i2c_stm32_init,
&i2c_stm32_dev_data_3, &i2c_stm32_cfg_3,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&api_funcs);
#ifdef CONFIG_I2C_STM32_INTERRUPT
static void i2c_stm32_irq_config_func_3(struct device *dev)
{
IRQ_CONNECT(I2C3_EV_IRQn, CONFIG_I2C_3_IRQ_PRI,
stm32_i2c_event_isr, DEVICE_GET(i2c_stm32_3), 0);
irq_enable(I2C3_EV_IRQn);
IRQ_CONNECT(I2C3_ER_IRQn, CONFIG_I2C_3_IRQ_PRI,
stm32_i2c_error_isr, DEVICE_GET(i2c_stm32_3), 0);
irq_enable(I2C3_ER_IRQn);
}
#endif
#endif /* CONFIG_I2C_3 */

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016 BayLibre, SAS
* Copyright (c) 2017 Linaro Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#ifndef _STM32_I2C_H_
#define _STM32_I2C_H_
typedef void (*irq_config_func_t)(struct device *port);
struct i2c_stm32_config {
#ifdef CONFIG_I2C_STM32_INTERRUPT
irq_config_func_t irq_config_func;
#endif
struct stm32_pclken pclken;
I2C_TypeDef *i2c;
};
struct i2c_stm32_data {
#ifdef CONFIG_I2C_STM32_INTERRUPT
struct k_sem device_sync_sem;
#endif
union dev_config dev_config;
#ifdef CONFIG_I2C_STM32_V1
u16_t slave_address;
#endif
struct {
#ifdef CONFIG_I2C_STM32_V1
unsigned int is_restart;
unsigned int flags;
#endif
unsigned int is_write;
unsigned int is_nack;
unsigned int is_err;
struct i2c_msg *msg;
unsigned int len;
u8_t *buf;
} current;
};
s32_t stm32_i2c_msg_write(struct device *dev, struct i2c_msg *msg, u32_t flg,
u16_t sadr);
s32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg, u32_t flg,
u16_t sadr);
s32_t stm32_i2c_configure_timing(struct device *dev, u32_t clk);
void stm32_i2c_event_isr(void *arg);
void stm32_i2c_error_isr(void *arg);
#define DEV_DATA(dev) ((struct i2c_stm32_data * const)(dev)->driver_data)
#define DEV_CFG(dev) \
((const struct i2c_stm32_config * const)(dev)->config->config_info)
#endif /* _STM32_I2C_H_ */

View file

@ -0,0 +1,375 @@
/*
* Copyright (c) 2017, I-SENSE group of ICCS
* Copyright (c) 2017 Linaro Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* I2C Driver for: STM32F1, STM32F2, STM32F4 and STM32L1
*
*/
#include <clock_control/stm32_clock_control.h>
#include <clock_control.h>
#include <misc/util.h>
#include <kernel.h>
#include <board.h>
#include <errno.h>
#include <i2c.h>
#include "i2c_ll_stm32.h"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
#include <logging/sys_log.h>
#define I2C_REQUEST_WRITE 0x00
#define I2C_REQUEST_READ 0x01
#define HEADER 0xF0
#ifdef CONFIG_I2C_STM32_INTERRUPT
static inline void handle_sb(I2C_TypeDef *i2c, struct i2c_stm32_data *data)
{
u16_t saddr = data->slave_address;
u8_t slave;
if (data->dev_config.bits.use_10_bit_addr) {
slave = (((saddr & 0x0300) >> 7) & 0xFF);
u8_t header = slave | HEADER;
if (data->current.is_restart == 0) {
data->current.is_restart = 1;
} else {
header |= I2C_REQUEST_READ;
data->current.is_restart = 0;
}
LL_I2C_TransmitData8(i2c, header);
return;
}
slave = (saddr << 1) & 0xFF;
if (data->current.is_write) {
LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
} else {
LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
}
}
static inline void handle_addr(I2C_TypeDef *i2c, struct i2c_stm32_data *data)
{
if (data->dev_config.bits.use_10_bit_addr) {
if (!data->current.is_write && data->current.is_restart) {
data->current.is_restart = 0;
LL_I2C_ClearFlag_ADDR(i2c);
LL_I2C_GenerateStartCondition(i2c);
return;
}
}
if (!data->current.is_write && data->current.len == 1) {
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
}
LL_I2C_ClearFlag_ADDR(i2c);
}
static inline void handle_txe(I2C_TypeDef *i2c, struct i2c_stm32_data *data)
{
if (data->current.len) {
LL_I2C_TransmitData8(i2c, *data->current.buf);
data->current.buf++;
data->current.len--;
} else if (LL_I2C_IsActiveFlag_BTF(i2c) && !data->current.len) {
if ((data->current.flags & I2C_MSG_RESTART) == 0) {
LL_I2C_GenerateStopCondition(i2c);
}
k_sem_give(&data->device_sync_sem);
}
}
static inline void handle_rxne(I2C_TypeDef *i2c, struct i2c_stm32_data *data)
{
if (data->current.len) {
*data->current.buf = LL_I2C_ReceiveData8(i2c);
data->current.buf++;
data->current.len--;
if (data->current.len == 1) {
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
if ((data->current.flags & I2C_MSG_RESTART) == 0) {
LL_I2C_GenerateStopCondition(i2c);
}
k_sem_give(&data->device_sync_sem);
}
return;
}
data->current.is_err = 1;
k_sem_give(&data->device_sync_sem);
}
void stm32_i2c_event_isr(void *arg)
{
const struct i2c_stm32_config *cfg = DEV_CFG((struct device *)arg);
struct i2c_stm32_data *data = DEV_DATA((struct device *)arg);
I2C_TypeDef *i2c = cfg->i2c;
if (LL_I2C_IsActiveFlag_SB(i2c)) {
handle_sb(i2c, data);
} else if (LL_I2C_IsActiveFlag_ADD10(i2c)) {
LL_I2C_TransmitData8(i2c, data->slave_address);
} else if (LL_I2C_IsActiveFlag_ADDR(i2c)) {
handle_addr(i2c, data);
} else if (LL_I2C_IsActiveFlag_TXE(i2c)) {
handle_txe(i2c, data);
} else if (LL_I2C_IsActiveFlag_RXNE(i2c)) {
handle_rxne(i2c, data);
}
}
void stm32_i2c_error_isr(void *arg)
{
const struct i2c_stm32_config *cfg = DEV_CFG((struct device *)arg);
struct i2c_stm32_data *data = DEV_DATA((struct device *)arg);
I2C_TypeDef *i2c = cfg->i2c;
if (LL_I2C_IsActiveFlag_AF(i2c)) {
LL_I2C_ClearFlag_AF(i2c);
data->current.is_nack = 1;
k_sem_give(&data->device_sync_sem);
return;
}
data->current.is_err = 1;
k_sem_give(&data->device_sync_sem);
}
s32_t stm32_i2c_msg_write(struct device *dev, struct i2c_msg *msg,
u32_t flags, u16_t saddr)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
s32_t ret = 0;
data->current.len = msg->len;
data->current.buf = msg->buf;
data->current.flags = flags;
data->current.is_restart = 0;
data->current.is_write = 1;
data->current.is_nack = 0;
data->current.is_err = 0;
data->slave_address = saddr;
LL_I2C_EnableIT_EVT(i2c);
LL_I2C_EnableIT_ERR(i2c);
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
LL_I2C_GenerateStartCondition(i2c);
LL_I2C_EnableIT_TX(i2c);
LL_I2C_EnableIT_ERR(i2c);
k_sem_take(&data->device_sync_sem, K_FOREVER);
if (data->current.is_nack || data->current.is_err) {
LL_I2C_DisableIT_TX(i2c);
LL_I2C_DisableIT_ERR(i2c);
if (data->current.is_nack)
SYS_LOG_DBG("%s: NACK", __func__);
if (data->current.is_err)
SYS_LOG_DBG("%s: ERR %d", __func__,
data->current.is_err);
data->current.is_nack = 0;
data->current.is_err = 0;
ret = -EIO;
goto error;
}
LL_I2C_DisableIT_TX(i2c);
LL_I2C_DisableIT_ERR(i2c);
error:
LL_I2C_DisableIT_EVT(i2c);
LL_I2C_DisableIT_ERR(i2c);
return ret;
}
s32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
u32_t flags, u16_t saddr)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
s32_t ret = 0;
data->current.len = msg->len;
data->current.buf = msg->buf;
data->current.flags = flags;
data->current.is_restart = 0;
data->current.is_write = 0;
data->current.is_err = 0;
data->slave_address = saddr;
LL_I2C_EnableIT_EVT(i2c);
LL_I2C_EnableIT_ERR(i2c);
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
LL_I2C_GenerateStartCondition(i2c);
LL_I2C_EnableIT_RX(i2c);
k_sem_take(&data->device_sync_sem, K_FOREVER);
if (data->current.is_err) {
LL_I2C_DisableIT_RX(i2c);
SYS_LOG_DBG("%s: ERR %d", __func__, data->current.is_err);
data->current.is_err = 0;
ret = -EIO;
goto error;
}
LL_I2C_DisableIT_RX(i2c);
error:
LL_I2C_DisableIT_EVT(i2c);
LL_I2C_DisableIT_ERR(i2c);
return ret;
}
#else
s32_t stm32_i2c_msg_write(struct device *dev, struct i2c_msg *msg,
u32_t flags, u16_t saddr)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
u32_t len = msg->len;
u8_t *buf = msg->buf;
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
LL_I2C_GenerateStartCondition(i2c);
while (!LL_I2C_IsActiveFlag_SB(i2c)) {
;
}
if (data->dev_config.bits.use_10_bit_addr) {
u8_t slave = (((saddr & 0x0300) >> 7) & 0xFF);
u8_t header = slave | HEADER;
LL_I2C_TransmitData8(i2c, header);
while (!LL_I2C_IsActiveFlag_ADD10(i2c)) {
;
}
slave = data->slave_address & 0xFF;
LL_I2C_TransmitData8(i2c, slave);
} else {
u8_t slave = (saddr << 1) & 0xFF;
LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_WRITE);
}
while (!LL_I2C_IsActiveFlag_ADDR(i2c)) {
;
}
LL_I2C_ClearFlag_ADDR(i2c);
while (len) {
while (1) {
if (LL_I2C_IsActiveFlag_TXE(i2c)) {
break;
}
if (LL_I2C_IsActiveFlag_AF(i2c)) {
LL_I2C_ClearFlag_AF(i2c);
SYS_LOG_DBG("%s: NACK", __func__);
return -EIO;
}
};
LL_I2C_TransmitData8(i2c, *buf);
buf++;
len--;
}
while (!LL_I2C_IsActiveFlag_BTF(i2c)) {
;
}
if ((flags & I2C_MSG_RESTART) == 0) {
LL_I2C_GenerateStopCondition(i2c);
}
return 0;
}
s32_t stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
u32_t flags, u16_t saddr)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
u32_t len = msg->len;
u8_t *buf = msg->buf;
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
LL_I2C_GenerateStartCondition(i2c);
while (!LL_I2C_IsActiveFlag_SB(i2c)) {
;
}
if (data->dev_config.bits.use_10_bit_addr) {
u8_t slave = (((saddr & 0x0300) >> 7) & 0xFF);
u8_t header = slave | HEADER;
LL_I2C_TransmitData8(i2c, header);
while (!LL_I2C_IsActiveFlag_ADD10(i2c)) {
;
}
slave = saddr & 0xFF;
LL_I2C_TransmitData8(i2c, slave);
while (!LL_I2C_IsActiveFlag_ADDR(i2c)) {
;
}
LL_I2C_ClearFlag_ADDR(i2c);
LL_I2C_GenerateStartCondition(i2c);
while (!LL_I2C_IsActiveFlag_SB(i2c)) {
;
}
header |= I2C_REQUEST_READ;
LL_I2C_TransmitData8(i2c, header);
} else {
u8_t slave = ((saddr) << 1) & 0xFF;
LL_I2C_TransmitData8(i2c, slave | I2C_REQUEST_READ);
}
while (!LL_I2C_IsActiveFlag_ADDR(i2c)) {
;
}
if (len == 1) {
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_ACK);
}
LL_I2C_ClearFlag_ADDR(i2c);
while (len) {
while (!LL_I2C_IsActiveFlag_RXNE(i2c)) {
;
}
*buf = LL_I2C_ReceiveData8(i2c);
buf++;
len--;
if (len == 1) {
LL_I2C_AcknowledgeNextData(i2c, LL_I2C_NACK);
if ((flags & I2C_MSG_RESTART) == 0) {
LL_I2C_GenerateStopCondition(i2c);
}
}
}
return 0;
}
#endif
s32_t stm32_i2c_configure_timing(struct device *dev, u32_t clock)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
switch (data->dev_config.bits.speed) {
case I2C_SPEED_STANDARD:
LL_I2C_ConfigSpeed(i2c, clock, 100000, LL_I2C_DUTYCYCLE_2);
break;
case I2C_SPEED_FAST:
LL_I2C_ConfigSpeed(i2c, clock, 400000, LL_I2C_DUTYCYCLE_2);
break;
default:
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,316 @@
/*
* Copyright (c) 2016 BayLibre, SAS
* Copyright (c) 2017 Linaro Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* I2C Driver for: STM32F0, STM32F3, STM32F7, STM32L0 and STM32L4
*
*/
#include <clock_control/stm32_clock_control.h>
#include <clock_control.h>
#include <misc/util.h>
#include <kernel.h>
#include <board.h>
#include <errno.h>
#include <i2c.h>
#include "i2c_ll_stm32.h"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
#include <logging/sys_log.h>
static inline void msg_init(struct device *dev, struct i2c_msg *msg,
unsigned int flags, u16_t slave, uint32_t transfer)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
unsigned int len = msg->len;
if (data->dev_config.bits.use_10_bit_addr) {
LL_I2C_SetMasterAddressingMode(i2c,
LL_I2C_ADDRESSING_MODE_10BIT);
LL_I2C_SetSlaveAddr(i2c, (uint32_t) slave);
} else {
LL_I2C_SetMasterAddressingMode(i2c,
LL_I2C_ADDRESSING_MODE_7BIT);
LL_I2C_SetSlaveAddr(i2c, (uint32_t) slave << 1);
}
LL_I2C_SetTransferRequest(i2c, transfer);
LL_I2C_SetTransferSize(i2c, len);
if ((flags & I2C_MSG_RESTART) == I2C_MSG_RESTART) {
LL_I2C_DisableAutoEndMode(i2c);
} else {
LL_I2C_EnableAutoEndMode(i2c);
}
LL_I2C_DisableReloadMode(i2c);
LL_I2C_GenerateStartCondition(i2c);
}
static inline void msg_done(struct device *dev, unsigned int flags)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
I2C_TypeDef *i2c = cfg->i2c;
if ((flags & I2C_MSG_RESTART) == 0) {
while (!LL_I2C_IsActiveFlag_STOP(i2c)) {
;
}
LL_I2C_GenerateStopCondition(i2c);
}
}
#ifdef CONFIG_I2C_STM32_INTERRUPT
void stm32_i2c_event_isr(void *arg)
{
const struct i2c_stm32_config *cfg = DEV_CFG((struct device *)arg);
struct i2c_stm32_data *data = DEV_DATA((struct device *)arg);
I2C_TypeDef *i2c = cfg->i2c;
if (data->current.is_write) {
if (data->current.len && LL_I2C_IsEnabledIT_TX(i2c)) {
LL_I2C_TransmitData8(i2c, *data->current.buf);
} else {
LL_I2C_DisableIT_TX(i2c);
goto error;
}
} else {
if (data->current.len && LL_I2C_IsEnabledIT_RX(i2c)) {
*data->current.buf = LL_I2C_ReceiveData8(i2c);
} else {
LL_I2C_DisableIT_RX(i2c);
goto error;
}
}
data->current.buf++;
data->current.len--;
if (!data->current.len)
k_sem_give(&data->device_sync_sem);
return;
error:
data->current.is_err = 1;
k_sem_give(&data->device_sync_sem);
}
void stm32_i2c_error_isr(void *arg)
{
const struct i2c_stm32_config *cfg = DEV_CFG((struct device *)arg);
struct i2c_stm32_data *data = DEV_DATA((struct device *)arg);
I2C_TypeDef *i2c = cfg->i2c;
if (LL_I2C_IsActiveFlag_NACK(i2c)) {
LL_I2C_ClearFlag_NACK(i2c);
data->current.is_nack = 1;
} else {
data->current.is_err = 1;
}
k_sem_give(&data->device_sync_sem);
}
int stm32_i2c_msg_write(struct device *dev, struct i2c_msg *msg,
unsigned int flags, uint16_t slave)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
data->current.len = msg->len;
data->current.buf = msg->buf;
data->current.is_write = 1;
data->current.is_nack = 0;
data->current.is_err = 0;
msg_init(dev, msg, flags, slave, LL_I2C_REQUEST_WRITE);
LL_I2C_EnableIT_TX(i2c);
LL_I2C_EnableIT_NACK(i2c);
k_sem_take(&data->device_sync_sem, K_FOREVER);
if (data->current.is_nack || data->current.is_err) {
goto error;
}
msg_done(dev, flags);
LL_I2C_DisableIT_TX(i2c);
LL_I2C_DisableIT_NACK(i2c);
return 0;
error:
LL_I2C_DisableIT_TX(i2c);
LL_I2C_DisableIT_NACK(i2c);
if (data->current.is_nack) {
SYS_LOG_DBG("%s: NACK", __func__);
data->current.is_nack = 0;
}
if (data->current.is_err) {
SYS_LOG_DBG("%s: ERR %d", __func__,
data->current.is_err);
data->current.is_err = 0;
}
return -EIO;
}
int stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
unsigned int flags, uint16_t slave)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
data->current.len = msg->len;
data->current.buf = msg->buf;
data->current.is_write = 0;
data->current.is_err = 0;
msg_init(dev, msg, flags, slave, LL_I2C_REQUEST_READ);
LL_I2C_EnableIT_RX(i2c);
k_sem_take(&data->device_sync_sem, K_FOREVER);
if (data->current.is_err) {
goto error;
}
msg_done(dev, flags | msg->flags);
LL_I2C_DisableIT_RX(i2c);
return 0;
error:
LL_I2C_DisableIT_RX(i2c);
SYS_LOG_DBG("%s: ERR %d", __func__, data->current.is_err);
data->current.is_err = 0;
return -EIO;
}
#else /* !CONFIG_I2C_STM32_INTERRUPT */
int stm32_i2c_msg_write(struct device *dev, struct i2c_msg *msg,
unsigned int flags, uint16_t slave)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
I2C_TypeDef *i2c = cfg->i2c;
unsigned int len = msg->len;
u8_t *buf = msg->buf;
msg_init(dev, msg, flags, slave, LL_I2C_REQUEST_WRITE);
while (len) {
while (1) {
if (LL_I2C_IsActiveFlag_TXIS(i2c)) {
break;
}
if (LL_I2C_IsActiveFlag_NACK(i2c)) {
goto error;
}
}
LL_I2C_TransmitData8(i2c, *buf);
buf++;
len--;
}
msg_done(dev, flags);
return 0;
error:
LL_I2C_ClearFlag_NACK(i2c);
SYS_LOG_DBG("%s: NACK", __func__);
return -EIO;
}
int stm32_i2c_msg_read(struct device *dev, struct i2c_msg *msg,
unsigned int flags, uint16_t slave)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
I2C_TypeDef *i2c = cfg->i2c;
unsigned int len = msg->len;
u8_t *buf = msg->buf;
msg_init(dev, msg, flags, slave, LL_I2C_REQUEST_READ);
while (len) {
while (!LL_I2C_IsActiveFlag_RXNE(i2c)) {
;
}
*buf = LL_I2C_ReceiveData8(i2c);
buf++;
len--;
}
msg_done(dev, flags | msg->flags);
return 0;
}
#endif
int stm32_i2c_configure_timing(struct device *dev, u32_t clock)
{
const struct i2c_stm32_config *cfg = DEV_CFG(dev);
struct i2c_stm32_data *data = DEV_DATA(dev);
I2C_TypeDef *i2c = cfg->i2c;
u32_t i2c_hold_time_min, i2c_setup_time_min;
u32_t i2c_h_min_time, i2c_l_min_time;
u32_t presc = 1;
u32_t timing;
switch (data->dev_config.bits.speed) {
case I2C_SPEED_STANDARD:
i2c_h_min_time = 4000;
i2c_l_min_time = 4700;
i2c_hold_time_min = 500;
i2c_setup_time_min = 1250;
break;
case I2C_SPEED_FAST:
i2c_h_min_time = 600;
i2c_l_min_time = 1300;
i2c_hold_time_min = 375;
i2c_setup_time_min = 500;
break;
default:
return -EINVAL;
}
/* Calculate period until prescaler matches */
do {
u32_t t_presc = clock / presc;
u32_t ns_presc = NSEC_PER_SEC / t_presc;
u32_t sclh = i2c_h_min_time / ns_presc;
u32_t scll = i2c_l_min_time / ns_presc;
u32_t sdadel = i2c_hold_time_min / ns_presc;
u32_t scldel = i2c_setup_time_min / ns_presc;
if ((sclh - 1) > 255 || (scll - 1) > 255) {
++presc;
continue;
}
if (sdadel > 15 || (scldel - 1) > 15) {
++presc;
continue;
}
timing = __LL_I2C_CONVERT_TIMINGS(presc - 1,
scldel - 1, sdadel, sclh - 1, scll - 1);
break;
} while (presc < 16);
if (presc >= 16) {
SYS_LOG_DBG("I2C:failed to find prescaler value");
return -EINVAL;
}
LL_I2C_SetTiming(i2c, timing);
return 0;
}

View file

@ -1,521 +0,0 @@
/*
* Copyright (c) 2016 BayLibre, SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <kernel.h>
#include <board.h>
#include <i2c.h>
#include <clock_control.h>
#include <misc/util.h>
#include <clock_control/stm32_clock_control.h>
#include "i2c_stm32lx.h"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL
#include <logging/sys_log.h>
/* convenience defines */
#define DEV_CFG(dev) \
((const struct i2c_stm32lx_config * const)(dev)->config->config_info)
#define DEV_DATA(dev) \
((struct i2c_stm32lx_data * const)(dev)->driver_data)
#define I2C_STRUCT(dev) \
((volatile struct i2c_stm32lx *)(DEV_CFG(dev))->base)
static int i2c_stm32lx_runtime_configure(struct device *dev, u32_t config)
{
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
struct i2c_stm32lx_data *data = DEV_DATA(dev);
const struct i2c_stm32lx_config *cfg = DEV_CFG(dev);
u32_t clock;
u32_t i2c_h_min_time, i2c_l_min_time;
u32_t i2c_hold_time_min, i2c_setup_time_min;
u32_t presc = 1;
data->dev_config.raw = config;
clock_control_get_rate(data->clock,
(clock_control_subsys_t *)&cfg->pclken, &clock);
if (data->dev_config.bits.is_slave_read)
return -EINVAL;
/* Disable peripheral */
i2c->cr1.bit.pe = 0;
while (i2c->cr1.bit.pe)
;
switch (data->dev_config.bits.speed) {
case I2C_SPEED_STANDARD:
i2c_h_min_time = 4000;
i2c_l_min_time = 4700;
i2c_hold_time_min = 500;
i2c_setup_time_min = 1250;
break;
case I2C_SPEED_FAST:
i2c_h_min_time = 600;
i2c_l_min_time = 1300;
i2c_hold_time_min = 375;
i2c_setup_time_min = 500;
break;
default:
return -EINVAL;
}
/* Calculate period until prescaler matches */
do {
u32_t t_presc = clock / presc;
u32_t ns_presc = NSEC_PER_SEC / t_presc;
u32_t sclh = i2c_h_min_time / ns_presc;
u32_t scll = i2c_l_min_time / ns_presc;
u32_t sdadel = i2c_hold_time_min / ns_presc;
u32_t scldel = i2c_setup_time_min / ns_presc;
if ((sclh - 1) > 255 ||
(scll - 1) > 255 ||
sdadel > 15 ||
(scldel - 1) > 15) {
++presc;
continue;
}
i2c->timingr.bit.presc = presc-1;
i2c->timingr.bit.scldel = scldel-1;
i2c->timingr.bit.sdadel = sdadel;
i2c->timingr.bit.sclh = sclh-1;
i2c->timingr.bit.scll = scll-1;
break;
} while (presc < 16);
if (presc >= 16) {
SYS_LOG_DBG("I2C:failed to find prescaler value");
return -EINVAL;
}
return 0;
}
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
static void i2c_stm32lx_ev_isr(void *arg)
{
struct device * const dev = (struct device *)arg;
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
struct i2c_stm32lx_data *data = DEV_DATA(dev);
if (data->current.is_write) {
if (data->current.len && i2c->isr.bit.txis) {
i2c->txdr = *data->current.buf;
data->current.buf++;
data->current.len--;
if (!data->current.len)
k_sem_give(&data->device_sync_sem);
} else {
/* Impossible situation */
data->current.is_err = 1;
i2c->cr1.bit.txie = 0;
k_sem_give(&data->device_sync_sem);
}
} else {
if (data->current.len && i2c->isr.bit.rxne) {
*data->current.buf = i2c->rxdr.bit.data;
data->current.buf++;
data->current.len--;
if (!data->current.len)
k_sem_give(&data->device_sync_sem);
} else {
/* Impossible situation */
data->current.is_err = 1;
i2c->cr1.bit.rxie = 0;
k_sem_give(&data->device_sync_sem);
}
}
}
static void i2c_stm32lx_er_isr(void *arg)
{
struct device * const dev = (struct device *)arg;
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
struct i2c_stm32lx_data *data = DEV_DATA(dev);
if (i2c->isr.bit.nackf) {
i2c->icr.bit.nack = 1;
data->current.is_nack = 1;
k_sem_give(&data->device_sync_sem);
} else {
/* Unknown Error */
data->current.is_err = 1;
k_sem_give(&data->device_sync_sem);
}
}
#endif
static inline void transfer_setup(struct device *dev, u16_t slave_address,
unsigned int read_transfer)
{
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
struct i2c_stm32lx_data *data = DEV_DATA(dev);
if (data->dev_config.bits.use_10_bit_addr) {
i2c->cr2.bit.add10 = 1;
i2c->cr2.bit.sadd = slave_address;
} else
i2c->cr2.bit.sadd = slave_address << 1;
i2c->cr2.bit.rd_wrn = !!read_transfer;
}
static inline int msg_write(struct device *dev, struct i2c_msg *msg,
unsigned int flags)
{
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
struct i2c_stm32lx_data *data = DEV_DATA(dev);
#endif
unsigned int len = msg->len;
u8_t *buf = msg->buf;
if (len > 255)
return -EINVAL;
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
data->current.len = len;
data->current.buf = buf;
data->current.is_nack = 0;
data->current.is_err = 0;
data->current.is_write = 1;
#endif
i2c->cr2.bit.nbytes = len;
if ((flags & I2C_MSG_RESTART) == I2C_MSG_RESTART)
i2c->cr2.bit.autoend = 0;
else
i2c->cr2.bit.autoend = 1;
i2c->cr2.bit.reload = 0;
i2c->cr2.bit.start = 1;
while (i2c->cr2.bit.start)
;
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
i2c->cr1.bit.txie = 1;
i2c->cr1.bit.nackie = 1;
k_sem_take(&data->device_sync_sem, K_FOREVER);
if (data->current.is_nack || data->current.is_err) {
i2c->cr1.bit.txie = 0;
i2c->cr1.bit.nackie = 0;
if (data->current.is_nack)
SYS_LOG_DBG("%s: NACK", __func__);
if (data->current.is_err)
SYS_LOG_DBG("%s: ERR %d", __func__,
data->current.is_err);
data->current.is_nack = 0;
data->current.is_err = 0;
return -EIO;
}
#else
while (len) {
do {
if (i2c->isr.bit.txis)
break;
if (i2c->isr.bit.nackf) {
i2c->icr.bit.nack = 1;
SYS_LOG_DBG("%s: NACK", __func__);
return -EIO;
}
} while (1);
i2c->txdr = *buf;
buf++;
len--;
}
#endif
if ((flags & I2C_MSG_RESTART) == 0) {
while (!i2c->isr.bit.stopf)
;
i2c->icr.bit.stop = 1;
}
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
i2c->cr1.bit.txie = 0;
i2c->cr1.bit.nackie = 0;
#endif
return 0;
}
static inline int msg_read(struct device *dev, struct i2c_msg *msg,
unsigned int flags)
{
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
struct i2c_stm32lx_data *data = DEV_DATA(dev);
#endif
unsigned int len = msg->len;
u8_t *buf = msg->buf;
if (len > 255)
return -EINVAL;
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
data->current.len = len;
data->current.buf = buf;
data->current.is_err = 0;
data->current.is_write = 0;
#endif
i2c->cr2.bit.nbytes = len;
if ((flags & I2C_MSG_RESTART) == I2C_MSG_RESTART)
i2c->cr2.bit.autoend = 0;
else
i2c->cr2.bit.autoend = 1;
i2c->cr2.bit.reload = 0;
i2c->cr2.bit.start = 1;
while (i2c->cr2.bit.start)
;
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
i2c->cr1.bit.rxie = 1;
k_sem_take(&data->device_sync_sem, K_FOREVER);
if (data->current.is_err) {
i2c->cr1.bit.rxie = 0;
if (data->current.is_err)
SYS_LOG_DBG("%s: ERR %d", __func__,
data->current.is_err);
data->current.is_err = 0;
return -EIO;
}
#else
while (len) {
while (!i2c->isr.bit.rxne)
;
*buf = i2c->rxdr.bit.data;
buf++;
len--;
}
#endif
if ((flags & I2C_MSG_RESTART) == 0) {
while (!i2c->isr.bit.stopf)
;
i2c->icr.bit.stop = 1;
}
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
i2c->cr1.bit.rxie = 0;
#endif
return 0;
}
static int i2c_stm32lx_transfer(struct device *dev,
struct i2c_msg *msgs, u8_t num_msgs,
u16_t slave_address)
{
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
struct i2c_msg *cur_msg = msgs;
u8_t msg_left = num_msgs;
int ret = 0;
/* Enable Peripheral */
i2c->cr1.bit.pe = 1;
/* Process all messages one-by-one */
while (msg_left > 0) {
unsigned int flags = 0;
if (cur_msg->len > 255)
return -EINVAL;
if (msg_left > 1 &&
(cur_msg[0].flags & I2C_MSG_RW_MASK) !=
(cur_msg[1].flags & I2C_MSG_RW_MASK))
flags |= I2C_MSG_RESTART;
if ((cur_msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
transfer_setup(dev, slave_address, 0);
ret = msg_write(dev, cur_msg, flags);
} else {
transfer_setup(dev, slave_address, 1);
ret = msg_read(dev, cur_msg, flags);
}
if (ret < 0) {
ret = -EIO;
break;
}
cur_msg++;
msg_left--;
};
/* Disable Peripheral */
i2c->cr1.bit.pe = 0;
return ret;
}
static const struct i2c_driver_api api_funcs = {
.configure = i2c_stm32lx_runtime_configure,
.transfer = i2c_stm32lx_transfer,
};
static inline void __i2c_stm32lx_get_clock(struct device *dev)
{
struct i2c_stm32lx_data *data = DEV_DATA(dev);
struct device *clk =
device_get_binding(STM32_CLOCK_CONTROL_NAME);
__ASSERT_NO_MSG(clk);
data->clock = clk;
}
static int i2c_stm32lx_init(struct device *dev)
{
volatile struct i2c_stm32lx *i2c = I2C_STRUCT(dev);
struct i2c_stm32lx_data *data = DEV_DATA(dev);
const struct i2c_stm32lx_config *cfg = DEV_CFG(dev);
k_sem_init(&data->device_sync_sem, 0, UINT_MAX);
__i2c_stm32lx_get_clock(dev);
/* enable clock */
clock_control_on(data->clock,
(clock_control_subsys_t *)&cfg->pclken);
/* Reset config */
i2c->cr1.val = 0;
i2c->cr2.val = 0;
i2c->oar1.val = 0;
i2c->oar2.val = 0;
i2c->timingr.val = 0;
i2c->timeoutr.val = 0;
i2c->pecr.val = 0;
i2c->icr.val = 0xFFFFFFFF;
/* Try to Setup HW */
i2c_stm32lx_runtime_configure(dev, data->dev_config.raw);
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
cfg->irq_config_func(dev);
#endif
return 0;
}
#ifdef CONFIG_I2C_1
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
static void i2c_stm32lx_irq_config_func_1(struct device *port);
#endif
static const struct i2c_stm32lx_config i2c_stm32lx_cfg_1 = {
.base = (u8_t *)I2C1_BASE,
.pclken = { .bus = STM32_CLOCK_BUS_APB1,
.enr = LL_APB1_GRP1_PERIPH_I2C1 },
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
.irq_config_func = i2c_stm32lx_irq_config_func_1,
#endif
};
static struct i2c_stm32lx_data i2c_stm32lx_dev_data_1 = {
.dev_config.raw = CONFIG_I2C_1_DEFAULT_CFG,
};
DEVICE_AND_API_INIT(i2c_stm32lx_1, CONFIG_I2C_1_NAME, &i2c_stm32lx_init,
&i2c_stm32lx_dev_data_1, &i2c_stm32lx_cfg_1,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&api_funcs);
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
static void i2c_stm32lx_irq_config_func_1(struct device *dev)
{
#ifdef CONFIG_SOC_SERIES_STM32L4X
#define PORT_1_EV_IRQ STM32L4_IRQ_I2C1_EV
#define PORT_1_ER_IRQ STM32L4_IRQ_I2C1_ER
#endif
IRQ_CONNECT(PORT_1_EV_IRQ, CONFIG_I2C_1_IRQ_PRI,
i2c_stm32lx_ev_isr, DEVICE_GET(i2c_stm32lx_1), 0);
irq_enable(PORT_1_EV_IRQ);
IRQ_CONNECT(PORT_1_ER_IRQ, CONFIG_I2C_1_IRQ_PRI,
i2c_stm32lx_er_isr, DEVICE_GET(i2c_stm32lx_1), 0);
irq_enable(PORT_1_ER_IRQ);
}
#endif
#endif /* CONFIG_I2C_1 */
#ifdef CONFIG_I2C_2
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
static void i2c_stm32lx_irq_config_func_2(struct device *port);
#endif
static const struct i2c_stm32lx_config i2c_stm32lx_cfg_2 = {
.base = (u8_t *)I2C2_BASE,
.pclken = { .bus = STM32_CLOCK_BUS_APB1,
.enr = LL_APB1_GRP1_PERIPH_I2C2 },
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
.irq_config_func = i2c_stm32lx_irq_config_func_2,
#endif
};
static struct i2c_stm32lx_data i2c_stm32lx_dev_data_2 = {
.dev_config.raw = CONFIG_I2C_2_DEFAULT_CFG,
};
DEVICE_AND_API_INIT(i2c_stm32lx_2, CONFIG_I2C_2_NAME, &i2c_stm32lx_init,
&i2c_stm32lx_dev_data_2, &i2c_stm32lx_cfg_2,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&api_funcs);
#ifdef CONFIG_I2C_STM32LX_INTERRUPT
static void i2c_stm32lx_irq_config_func_2(struct device *dev)
{
#ifdef CONFIG_SOC_SERIES_STM32L4X
#define PORT_2_EV_IRQ STM32L4_IRQ_I2C2_EV
#define PORT_2_ER_IRQ STM32L4_IRQ_I2C2_ER
#endif
IRQ_CONNECT(PORT_2_EV_IRQ, CONFIG_I2C_2_IRQ_PRI,
i2c_stm32lx_ev_isr, DEVICE_GET(i2c_stm32lx_2), 0);
irq_enable(PORT_2_EV_IRQ);
IRQ_CONNECT(PORT_2_ER_IRQ, CONFIG_I2C_2_IRQ_PRI,
i2c_stm32lx_er_isr, DEVICE_GET(i2c_stm32lx_2), 0);
irq_enable(PORT_2_ER_IRQ);
}
#endif
#endif /* CONFIG_I2C_2 */

View file

@ -1,209 +0,0 @@
/*
* Copyright (c) 2016 BayLibre, SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _STM32LX_I2C_H_
#define _STM32LX_I2C_H_
/* 35.6.1 Control register 1 (I2C_CR1) */
union __cr1 {
u32_t val;
struct {
u32_t pe :1 __packed;
u32_t txie :1 __packed;
u32_t rxie :1 __packed;
u32_t addrie :1 __packed;
u32_t nackie :1 __packed;
u32_t stopie :1 __packed;
u32_t tcie :1 __packed;
u32_t errie :1 __packed;
u32_t dnf :4 __packed;
u32_t anfoff :1 __packed;
u32_t rsvd__13 :1 __packed;
u32_t txdmaen :1 __packed;
u32_t rxdmaen :1 __packed;
u32_t sbc :1 __packed;
u32_t nostretch :1 __packed;
u32_t wupen :1 __packed;
u32_t gcen :1 __packed;
u32_t smbhen :1 __packed;
u32_t smbden :1 __packed;
u32_t alerten :1 __packed;
u32_t pecen :1 __packed;
u32_t rsvd__24_31 :8 __packed;
} bit;
};
/* 35.6.2 Control register 2 (I2C_CR2) */
union __cr2 {
u32_t val;
struct {
u32_t sadd :10 __packed;
u32_t rd_wrn :1 __packed;
u32_t add10 :1 __packed;
u32_t head10r :1 __packed;
u32_t start :1 __packed;
u32_t stop :1 __packed;
u32_t nack :1 __packed;
u32_t nbytes :8 __packed;
u32_t reload :1 __packed;
u32_t autoend :1 __packed;
u32_t pecbyte :1 __packed;
u32_t rsvd__27_31 :5 __packed;
} bit;
};
union __oar1 {
u32_t val;
struct {
u32_t oa1 :10 __packed;
u32_t oa1mode :1 __packed;
u32_t rsvd__11_14 :4 __packed;
u32_t oa1en :1 __packed;
u32_t rsvd__16_31 :16 __packed;
} bit;
};
union __oar2 {
u32_t val;
struct {
u32_t rsvd__0 :1 __packed;
u32_t oa2 :7 __packed;
u32_t oa2msk :3 __packed;
u32_t rsvd__11_14 :4 __packed;
u32_t oa2en :1 __packed;
u32_t rsvd__16_31 :16 __packed;
} bit;
};
union __timingr {
u32_t val;
struct {
u32_t scll :8 __packed;
u32_t sclh :8 __packed;
u32_t sdadel :4 __packed;
u32_t scldel :4 __packed;
u32_t rsvd__24_27 :4 __packed;
u32_t presc :4 __packed;
} bit;
};
union __timeoutr {
u32_t val;
struct {
u32_t timeouta :12 __packed;
u32_t tidle :1 __packed;
u32_t rsvd__13_14 :1 __packed;
u32_t timouten :1 __packed;
u32_t timeoutb :12 __packed;
u32_t rsvd__28_30 :1 __packed;
u32_t texten :1 __packed;
} bit;
};
union __isr {
u32_t val;
struct {
u32_t txe :1 __packed;
u32_t txis :1 __packed;
u32_t rxne :1 __packed;
u32_t addr :1 __packed;
u32_t nackf :1 __packed;
u32_t stopf :1 __packed;
u32_t tc :1 __packed;
u32_t tcr :1 __packed;
u32_t berr :1 __packed;
u32_t arlo :1 __packed;
u32_t ovr :1 __packed;
u32_t pecerr :1 __packed;
u32_t timeout :1 __packed;
u32_t alert :1 __packed;
u32_t rsvd__14 :1 __packed;
u32_t busy :1 __packed;
u32_t dir :1 __packed;
u32_t addcode :7 __packed;
u32_t rsvd__24_31 :8 __packed;
} bit;
};
union __icr {
u32_t val;
struct {
u32_t rsvd__0_2 :3 __packed;
u32_t addr :1 __packed;
u32_t nack :1 __packed;
u32_t stop :1 __packed;
u32_t rsvd__6_7 :2 __packed;
u32_t berr :1 __packed;
u32_t arlo :1 __packed;
u32_t ovr :1 __packed;
u32_t pec :1 __packed;
u32_t timeout :1 __packed;
u32_t alert :1 __packed;
u32_t rsvd__14_31 :17 __packed;
} bit;
};
union __pecr {
u32_t val;
struct {
u32_t pec:8 __packed;
u32_t rsvd__9_31 :24 __packed;
} bit;
};
union __dr {
u32_t val;
struct {
u32_t data:8 __packed;
u32_t rsvd__9_31 :24 __packed;
} bit;
};
/* 35.7.12 I2C register map */
struct i2c_stm32lx {
union __cr1 cr1;
union __cr2 cr2;
union __oar1 oar1;
union __oar2 oar2;
union __timingr timingr;
union __timeoutr timeoutr;
union __isr isr;
union __icr icr;
union __pecr pecr;
union __dr rxdr;
u32_t txdr;
};
typedef void (*irq_config_func_t)(struct device *port);
/* device config */
struct i2c_stm32lx_config {
void *base;
irq_config_func_t irq_config_func;
/* clock subsystem driving this peripheral */
struct stm32_pclken pclken;
};
/* driver data */
struct i2c_stm32lx_data {
/* clock device */
struct device *clock;
/* Device config */
union dev_config dev_config;
/* ISR Sync */
struct k_sem device_sync_sem;
/* Current message data */
struct {
struct i2c_msg *msg;
unsigned int len;
u8_t *buf;
unsigned int is_err;
unsigned int is_nack;
unsigned int is_write;
} current;
};
#endif /* _STM32LX_UART_H_ */