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:
parent
220ddb9738
commit
21fbc9b07e
12 changed files with 1040 additions and 739 deletions
|
@ -14,5 +14,6 @@ config SOC_SERIES_STM32F1X
|
|||
select HAS_STM32CUBE
|
||||
select CPU_HAS_SYSTICK
|
||||
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
|
||||
select I2C_STM32_V1 if I2C
|
||||
help
|
||||
Enable support for STM32F1 MCU series
|
||||
|
|
|
@ -15,5 +15,6 @@ config SOC_SERIES_STM32F3X
|
|||
select CPU_HAS_SYSTICK
|
||||
select HAS_STM32CUBE
|
||||
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
|
||||
select I2C_STM32_V2 if I2C
|
||||
help
|
||||
Enable support for STM32F3 MCU series
|
||||
|
|
|
@ -16,5 +16,6 @@ config SOC_SERIES_STM32F4X
|
|||
select CPU_HAS_MPU
|
||||
select CPU_HAS_SYSTICK
|
||||
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
|
||||
select I2C_STM32_V1 if I2C
|
||||
help
|
||||
Enable support for STM32F4 MCU series
|
||||
|
|
|
@ -15,5 +15,6 @@ config SOC_SERIES_STM32L4X
|
|||
select CPU_HAS_MPU
|
||||
select CPU_HAS_SYSTICK
|
||||
select CLOCK_CONTROL_STM32_CUBE if CLOCK_CONTROL
|
||||
select I2C_STM32_V2 if I2C
|
||||
help
|
||||
Enable support for STM32L4 MCU series
|
||||
|
|
|
@ -90,19 +90,30 @@ config I2C_NRF5_GPIO_SCL_PIN
|
|||
help
|
||||
The GPIO pin to use for SCL.
|
||||
|
||||
config I2C_STM32LX
|
||||
bool "STM32Lx MCU I2C Driver"
|
||||
depends on SOC_FAMILY_STM32 && SOC_SERIES_STM32L4X
|
||||
config I2C_STM32_V1
|
||||
bool "STM32 V1 Driver (F1/F4X)"
|
||||
depends on SOC_FAMILY_STM32
|
||||
depends on SOC_SERIES_STM32F1X || SOC_SERIES_STM32F4X
|
||||
default n
|
||||
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
|
||||
bool "STM32Lx MCU I2C Interrupt Support"
|
||||
depends on I2C_STM32LX
|
||||
config I2C_STM32_V2
|
||||
bool "STM32 V2 Driver (F3/L4X)"
|
||||
depends on SOC_FAMILY_STM32
|
||||
depends on SOC_SERIES_STM32F3X || SOC_SERIES_STM32L4X
|
||||
default n
|
||||
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
|
||||
bool
|
||||
|
@ -252,6 +263,32 @@ config I2C_2_IRQ_PRI
|
|||
help
|
||||
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
|
||||
bool "Enable I2C_SS_0"
|
||||
depends on I2C_QMSI_SS
|
||||
|
|
|
@ -7,5 +7,6 @@ obj-$(CONFIG_I2C_NRF5) += i2c_nrf5.o
|
|||
obj-$(CONFIG_I2C_QMSI) += i2c_qmsi.o
|
||||
obj-$(CONFIG_I2C_QMSI_SS) += i2c_qmsi_ss.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
|
||||
|
|
241
drivers/i2c/i2c_ll_stm32.c
Normal file
241
drivers/i2c/i2c_ll_stm32.c
Normal 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 */
|
||||
|
||||
|
57
drivers/i2c/i2c_ll_stm32.h
Normal file
57
drivers/i2c/i2c_ll_stm32.h
Normal 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_ */
|
375
drivers/i2c/i2c_ll_stm32_v1.c
Normal file
375
drivers/i2c/i2c_ll_stm32_v1.c
Normal 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;
|
||||
}
|
316
drivers/i2c/i2c_ll_stm32_v2.c
Normal file
316
drivers/i2c/i2c_ll_stm32_v2.c
Normal 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;
|
||||
}
|
|
@ -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 */
|
|
@ -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_ */
|
Loading…
Add table
Add a link
Reference in a new issue