From 21fbc9b07e8df888b892b2204ab873b17e26bc5b Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Fri, 23 Jun 2017 10:51:27 +0200 Subject: [PATCH] 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 Signed-off-by: Yannis Damigos Reviewed-by: Yannis Damigos Tested-by: Yannis Damigos Tested-by: Jorge Ramirez-Ortiz --- arch/arm/soc/st_stm32/stm32f1/Kconfig.series | 1 + arch/arm/soc/st_stm32/stm32f3/Kconfig.series | 1 + arch/arm/soc/st_stm32/stm32f4/Kconfig.series | 1 + arch/arm/soc/st_stm32/stm32l4/Kconfig.series | 1 + drivers/i2c/Kconfig | 53 +- drivers/i2c/Makefile | 3 +- drivers/i2c/i2c_ll_stm32.c | 241 +++++++++ drivers/i2c/i2c_ll_stm32.h | 57 ++ drivers/i2c/i2c_ll_stm32_v1.c | 375 +++++++++++++ drivers/i2c/i2c_ll_stm32_v2.c | 316 +++++++++++ drivers/i2c/i2c_stm32lx.c | 521 ------------------- drivers/i2c/i2c_stm32lx.h | 209 -------- 12 files changed, 1040 insertions(+), 739 deletions(-) create mode 100644 drivers/i2c/i2c_ll_stm32.c create mode 100644 drivers/i2c/i2c_ll_stm32.h create mode 100644 drivers/i2c/i2c_ll_stm32_v1.c create mode 100644 drivers/i2c/i2c_ll_stm32_v2.c delete mode 100644 drivers/i2c/i2c_stm32lx.c delete mode 100644 drivers/i2c/i2c_stm32lx.h diff --git a/arch/arm/soc/st_stm32/stm32f1/Kconfig.series b/arch/arm/soc/st_stm32/stm32f1/Kconfig.series index d9863ba0194..2ee2f500ec2 100644 --- a/arch/arm/soc/st_stm32/stm32f1/Kconfig.series +++ b/arch/arm/soc/st_stm32/stm32f1/Kconfig.series @@ -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 diff --git a/arch/arm/soc/st_stm32/stm32f3/Kconfig.series b/arch/arm/soc/st_stm32/stm32f3/Kconfig.series index 153b1a6adfe..1aa5b782bc3 100644 --- a/arch/arm/soc/st_stm32/stm32f3/Kconfig.series +++ b/arch/arm/soc/st_stm32/stm32f3/Kconfig.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 diff --git a/arch/arm/soc/st_stm32/stm32f4/Kconfig.series b/arch/arm/soc/st_stm32/stm32f4/Kconfig.series index 0182d1d314b..0c6d15aa152 100644 --- a/arch/arm/soc/st_stm32/stm32f4/Kconfig.series +++ b/arch/arm/soc/st_stm32/stm32f4/Kconfig.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 diff --git a/arch/arm/soc/st_stm32/stm32l4/Kconfig.series b/arch/arm/soc/st_stm32/stm32l4/Kconfig.series index a7e2c5b1ee2..abd61a82d80 100644 --- a/arch/arm/soc/st_stm32/stm32l4/Kconfig.series +++ b/arch/arm/soc/st_stm32/stm32l4/Kconfig.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 diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 9b4993892f9..804ab847146 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -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 diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index c998d3cfd93..986f8af013d 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -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 diff --git a/drivers/i2c/i2c_ll_stm32.c b/drivers/i2c/i2c_ll_stm32.c new file mode 100644 index 00000000000..28bd967f219 --- /dev/null +++ b/drivers/i2c/i2c_ll_stm32.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016 BayLibre, SAS + * Copyright (c) 2017 Linaro Ltd + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "i2c_ll_stm32.h" + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL +#include + +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 */ + + diff --git a/drivers/i2c/i2c_ll_stm32.h b/drivers/i2c/i2c_ll_stm32.h new file mode 100644 index 00000000000..a0f21b6901a --- /dev/null +++ b/drivers/i2c/i2c_ll_stm32.h @@ -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_ */ diff --git a/drivers/i2c/i2c_ll_stm32_v1.c b/drivers/i2c/i2c_ll_stm32_v1.c new file mode 100644 index 00000000000..07a49a60dbc --- /dev/null +++ b/drivers/i2c/i2c_ll_stm32_v1.c @@ -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 +#include +#include +#include +#include +#include +#include +#include "i2c_ll_stm32.h" + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL +#include + +#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; +} diff --git a/drivers/i2c/i2c_ll_stm32_v2.c b/drivers/i2c/i2c_ll_stm32_v2.c new file mode 100644 index 00000000000..9892c8f5abf --- /dev/null +++ b/drivers/i2c/i2c_ll_stm32_v2.c @@ -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 +#include +#include +#include +#include +#include +#include +#include "i2c_ll_stm32.h" + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL +#include + +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; +} diff --git a/drivers/i2c/i2c_stm32lx.c b/drivers/i2c/i2c_stm32lx.c deleted file mode 100644 index 0dd4eb4f9fe..00000000000 --- a/drivers/i2c/i2c_stm32lx.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (c) 2016 BayLibre, SAS - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include - -#include -#include -#include - -#include - -#include -#include "i2c_stm32lx.h" - -#define SYS_LOG_LEVEL CONFIG_SYS_LOG_I2C_LEVEL -#include - -/* 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 */ diff --git a/drivers/i2c/i2c_stm32lx.h b/drivers/i2c/i2c_stm32lx.h deleted file mode 100644 index 5744187bc0d..00000000000 --- a/drivers/i2c/i2c_stm32lx.h +++ /dev/null @@ -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_ */