onegray commented on code in PR #8055: URL: https://github.com/apache/nuttx/pull/8055#discussion_r1064195422
########## arch/arm/src/stm32wb/stm32wb_i2c.c: ########## @@ -0,0 +1,2650 @@ +/**************************************************************************** + * arch/arm/src/stm32wb/stm32wb_i2c.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* -------------------------------------------------------------------------- + * + * STM32 WB I2C Driver based on L4 I2C Driver: + * + * STM32 WB and L4 have identical I2C hardware, differences are only in + * clocking. + * + * Supports: + * - Master operation: + * Standard-mode (up to 100 kHz) + * Fast-mode (up to 400 kHz) + * Fast-mode+ (up to 1 MHz) + * Clock source selection is based on STM32WB_RCC_CCIPR register + * + * - Multiple instances (shared bus) + * - Interrupt based operation + * - RELOAD support + * - I2C_M_NOSTART support + * + * Test Environment: + * - STM32WB55RG based board + * + * Unsupported, possible future work: + * - Wakeup from Stop mode + * - More effective error reporting to higher layers + * - Slave operation + * - Support of clock source frequencies other than 64MHz + * - Polled operation (code present but untested) + * - SMBus support + * - Multi-master support + * - IPMI + * + * Implementation: + * + * - Device: structure as defined by the nuttx/i2c/i2c_master.h + * + * - Instance: represents each individual access to the I2C driver, obtained + * by the i2c_init(); it extends the Device structure from the + * nuttx/i2c/i2c_master.h; + * Instance points to OPS, to common I2C Hardware private data and + * contains its own private data including frequency, address and mode + * of operation. + * + * - Private: Private data of an I2C Hardware + * + * High Level Functional Description + * + * This driver works with I2C "messages" (struct i2c_msg_s), which carry a + * buffer intended to transfer data to, or store data read from, the I2C bus. + * + * As the hardware can only transmit or receive one byte at a time the basic + * job of the driver (and the ISR specifically) is to process each message in + * the order they are stored in the message list, one byte at a time. When + * no messages are left the ISR exits and returns the result to the caller. + * + * The order of the list of I2C messages provided to the driver is important + * and dependent upon the hardware in use. A typical I2C transaction between + * the F3 as an I2C Master and some other IC as a I2C Slave requires two + * messages that communicate the: + * + * 1) Subaddress (register offset on the slave device) + * 2) Data sent to or read from the device + * + * These messages will typically be one byte in length but may be up to 2^31 + * bytes in length. Incidentally, the maximum length is limited only because + * i2c_msg_s.length is a signed int for some odd reason. + * + * Interrupt mode relies on the following interrupt events: + * + * TXIS - Transmit interrupt + * (data transmitted to bus and acknowledged) + * NACKF - Not Acknowledge Received + * (data transmitted to bus and NOT acknowledged) + * RXNE - Receive interrupt + * (data received from bus) + * TC - Transfer Complete + * (All bytes in message transferred) + * TCR - Transfer Complete (Reload) + * (Current batch of bytes in message transferred) + * + * The driver currently supports Single Master mode only. Slave mode is not + * supported. Additionally, the driver runs in Software End Mode (AUTOEND + * disabled) so the driver is responsible for telling the hardware what to + * do at the end of a transfer. + * + * -------------------------------------------------------------------------- + * + * Configuration: + * + * To use this driver, enable the following configuration variable: + * + * CONFIG_STM32WB_I2C + * + * and one or more interfaces: + * + * CONFIG_STM32WB_I2C1 + * CONFIG_STM32WB_I2C3 + * + * To configure the ISR timeout using fixed values + * (CONFIG_STM32WB_I2C_DYNTIMEO=n): + * + * CONFIG_STM32WB_I2CTIMEOSEC (Timeout in seconds) + * CONFIG_STM32WB_I2CTIMEOMS (Timeout in milliseconds) + * CONFIG_STM32WB_I2CTIMEOTICKS (Timeout in ticks) + * + * To configure the ISR timeout using dynamic values + * (CONFIG_STM32WB_I2C_DYNTIMEO=y): + * + * CONFIG_STM32WB_I2C_DYNTIMEO_USECPERBYTE + * (Timeout in microseconds per byte) + * CONFIG_STM32WB_I2C_DYNTIMEO_STARTSTOP + * (Timeout for start/stop in milliseconds) + * + * Debugging output enabled with: + * + * CONFIG_DEBUG_FEATURES and CONFIG_DEBUG_I2C_{ERROR|WARN|INFO} + * + * ISR Debugging output may be enabled with: + * + * CONFIG_DEBUG_FEATURES and CONFIG_DEBUG_I2C_INFO + * + * -------------------------------------------------------------------------- + * + * References (STM32WB): + * + * RM0434: + * ST STM32WB55xx and STM32WB35xx Reference Manual + * + * RM0471: + * ST STM32WB50CG and STM32WB30CE Reference Manual + * + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/irq.h> +#include <nuttx/clock.h> +#include <nuttx/mutex.h> +#include <nuttx/semaphore.h> +#include <nuttx/kmalloc.h> +#include <nuttx/power/pm.h> +#include <nuttx/i2c/i2c_master.h> + +#include <arch/board/board.h> + +#include "arm_internal.h" +#include "stm32wb_gpio.h" +#include "stm32wb_rcc.h" +#include "stm32wb_i2c.h" +#include "stm32wb_waste.h" + +/* At least one I2C peripheral must be enabled */ + +#if defined(CONFIG_STM32WB_I2C1) || defined(CONFIG_STM32WB_I2C3) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. + * Instead, CPU-intensive polling will be used. + */ + +/* Interrupt wait timeout in seconds and milliseconds */ + +#if !defined(CONFIG_STM32WB_I2CTIMEOSEC) && !defined(CONFIG_STM32WB_I2CTIMEOMS) +# define CONFIG_STM32WB_I2CTIMEOSEC 0 +# define CONFIG_STM32WB_I2CTIMEOMS 500 /* Default is 500 milliseconds */ +# warning "Using Default 500 Ms Timeout" +#elif !defined(CONFIG_STM32WB_I2CTIMEOSEC) +# define CONFIG_STM32WB_I2CTIMEOSEC 0 /* User provided milliseconds */ +#elif !defined(CONFIG_STM32WB_I2CTIMEOMS) +# define CONFIG_STM32WB_I2CTIMEOMS 0 /* User provided seconds */ +#endif + +/* Interrupt wait time timeout in system timer ticks */ + +#ifndef CONFIG_STM32WB_I2CTIMEOTICKS +# define CONFIG_STM32WB_I2CTIMEOTICKS \ + (SEC2TICK(CONFIG_STM32WB_I2CTIMEOSEC) + MSEC2TICK(CONFIG_STM32WB_I2CTIMEOMS)) +#endif + +#ifndef CONFIG_STM32WB_I2C_DYNTIMEO_STARTSTOP +# define CONFIG_STM32WB_I2C_DYNTIMEO_STARTSTOP TICK2USEC(CONFIG_STM32WB_I2CTIMEOTICKS) +#endif + +/* Macros to convert a I2C pin to a GPIO output */ + +#define I2C_OUTPUT (GPIO_OUTPUT | GPIO_FLOAT | GPIO_OPENDRAIN | \ + GPIO_SPEED_50MHz | GPIO_OUTPUT_SET) + +#define MKI2C_OUTPUT(p) (((p) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | I2C_OUTPUT) + +#define I2C_CR1_TXRX (I2C_CR1_RXIE | I2C_CR1_TXIE) +#define I2C_CR1_ALLINTS (I2C_CR1_TXRX | I2C_CR1_TCIE | I2C_CR1_ERRIE) + +/* I2C event tracing + * + * To enable tracing statements which show the details of the state machine + * enable the following configuration variable: + * + * CONFIG_I2C_TRACE + * + * Note: This facility uses syslog, which sends output to the console by + * default. No other debug configuration variables are required. + */ + +#ifndef CONFIG_I2C_TRACE +# define stm32wb_i2c_tracereset(p) +# define stm32wb_i2c_tracenew(p,s) +# define stm32wb_i2c_traceevent(p,e,a) +# define stm32wb_i2c_tracedump(p) +#endif + +#ifndef CONFIG_I2C_NTRACE +# define CONFIG_I2C_NTRACE 32 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Interrupt state */ + +enum stm32wb_intstate_e +{ + INTSTATE_IDLE = 0, /* No I2C activity */ + INTSTATE_WAITING, /* Waiting for completion of interrupt activity */ + INTSTATE_DONE, /* Interrupt activity complete */ +}; + +/* Trace events */ + +enum stm32wb_trace_e +{ + I2CEVENT_NONE = 0, + I2CEVENT_STATE_ERROR, + I2CEVENT_ISR_SHUTDOWN, + I2CEVENT_ISR_CALL, + I2CEVENT_ISR_EMPTY_CALL, + I2CEVENT_POLL_DEV_NOT_RDY, + I2CEVENT_ADDRESS_ACKED, + I2CEVENT_ADDRESS_NACKED, + I2CEVENT_RCVBYTE, + I2CEVENT_READ, + I2CEVENT_READ_ERROR, + I2CEVENT_WRITE, + I2CEVENT_WRITE_TO_DR, + I2CEVENT_WRITE_STOP, + I2CEVENT_WRITE_ERROR, + I2CEVENT_TC_NO_RESTART, + I2CEVENT_STOP +}; + +/* Trace data */ + +struct stm32wb_trace_s +{ + uint32_t status; /* I2C 32-bit SR2|SR1 status */ + uint32_t count; /* Interrupt count when status change */ + enum stm32wb_intstate_e event; /* Last event that occurred with this status */ + uint32_t parm; /* Parameter associated with the event */ + clock_t time; /* First of event or first status */ +}; + +/* I2C Device hardware configuration */ + +struct stm32wb_i2c_config_s +{ + uint32_t base; /* I2C base address */ + uint32_t clk_bit; /* Clock enable bit */ + uint32_t reset_bit; /* Reset bit */ + uint32_t scl_pin; /* GPIO configuration for SCL as SCL */ + uint32_t sda_pin; /* GPIO configuration for SDA as SDA */ +#ifndef CONFIG_I2C_POLLED + uint32_t ev_irq; /* Event IRQ */ + uint32_t er_irq; /* Error IRQ */ +#endif +}; + +/* I2C Device Private Data */ + +struct stm32wb_i2c_priv_s +{ + /* Port configuration */ + + const struct stm32wb_i2c_config_s *config; + + int refs; /* Reference count */ + mutex_t lock; /* Mutual exclusion mutex */ +#ifndef CONFIG_I2C_POLLED + sem_t sem_isr; /* Interrupt wait semaphore */ +#endif + volatile uint8_t intstate; /* Interrupt handshake (see enum stm32wb_intstate_e) */ + + uint8_t msgc; /* Message count */ + struct i2c_msg_s *msgv; /* Message list */ + uint8_t *ptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ + int dcnt; /* Current message bytes remaining to transfer */ + uint16_t flags; /* Current message flags */ + bool astart; /* START sent */ + + /* I2C trace support */ + +#ifdef CONFIG_I2C_TRACE + int tndx; /* Trace array index */ + clock_t start_time; /* Time when the trace was started */ + + /* The actual trace data */ + + struct stm32wb_trace_s trace[CONFIG_I2C_NTRACE]; +#endif + + uint32_t status; /* End of transfer SR2|SR1 status */ + +#ifdef CONFIG_PM + struct pm_callback_s pm_cb; /* PM callbacks */ +#endif +}; + +/* I2C Device, Instance */ + +struct stm32wb_i2c_inst_s +{ + const struct i2c_ops_s *ops; /* Standard I2C operations */ + struct stm32wb_i2c_priv_s *priv; /* Common driver private data structure */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline +uint16_t stm32wb_i2c_getreg(struct stm32wb_i2c_priv_s *priv, + uint8_t offset); +static inline +void stm32wb_i2c_putreg(struct stm32wb_i2c_priv_s *priv, + uint8_t offset, uint16_t value); +static inline +void stm32wb_i2c_putreg32(struct stm32wb_i2c_priv_s *priv, + uint8_t offset, uint32_t value); +static inline +void stm32wb_i2c_modifyreg32(struct stm32wb_i2c_priv_s *priv, + uint8_t offset, uint32_t clearbits, + uint32_t setbits); +#ifdef CONFIG_STM32WB_I2C_DYNTIMEO +static uint32_t stm32wb_i2c_toticks(int msgc, struct i2c_msg_s *msgs); +#endif /* CONFIG_STM32WB_I2C_DYNTIMEO */ +static inline +int stm32wb_i2c_sem_waitdone(struct stm32wb_i2c_priv_s *priv); +static inline +void stm32wb_i2c_sem_waitstop(struct stm32wb_i2c_priv_s *priv); +#ifdef CONFIG_I2C_TRACE +static void stm32wb_i2c_tracereset(struct stm32wb_i2c_priv_s *priv); +static void stm32wb_i2c_tracenew(struct stm32wb_i2c_priv_s *priv, + uint32_t status); +static void +stm32wb_i2c_traceevent(struct stm32wb_i2c_priv_s *priv, + enum stm32wb_trace_e event, uint32_t parm); +static void stm32wb_i2c_tracedump(struct stm32wb_i2c_priv_s *priv); +#endif /* CONFIG_I2C_TRACE */ +static void stm32wb_i2c_setclock(struct stm32wb_i2c_priv_s *priv, + uint32_t frequency); +static inline +void stm32wb_i2c_sendstart(struct stm32wb_i2c_priv_s *priv); +static inline void stm32wb_i2c_sendstop(struct stm32wb_i2c_priv_s *priv); +static inline +uint32_t stm32wb_i2c_getstatus(struct stm32wb_i2c_priv_s *priv); +static int stm32wb_i2c_isr_process(struct stm32wb_i2c_priv_s *priv); +#ifndef CONFIG_I2C_POLLED +static int stm32wb_i2c_isr(int irq, void *context, void *arg); +#endif +static int stm32wb_i2c_init(struct stm32wb_i2c_priv_s *priv); +static int stm32wb_i2c_deinit(struct stm32wb_i2c_priv_s *priv); + +static int stm32wb_i2c_process(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count); +static int stm32wb_i2c_transfer(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int stm32wb_i2c_reset(struct i2c_master_s *dev); +#endif +#ifdef CONFIG_PM +static int stm32wb_i2c_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_STM32WB_I2C1 +static const struct stm32wb_i2c_config_s stm32wb_i2c1_config = +{ + .base = STM32WB_I2C1_BASE, + .clk_bit = RCC_APB1ENR1_I2C1EN, + .reset_bit = RCC_APB1RSTR1_I2C1RST, + .scl_pin = GPIO_I2C1_SCL, + .sda_pin = GPIO_I2C1_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = STM32WB_IRQ_I2C1EV, + .er_irq = STM32WB_IRQ_I2C1ER +#endif +}; + +static struct stm32wb_i2c_priv_s stm32wb_i2c1_priv = +{ + .config = &stm32wb_i2c1_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32wb_i2c_pm_prepare, +#endif +}; +#endif + +#ifdef CONFIG_STM32WB_I2C3 +static const struct stm32wb_i2c_config_s stm32wb_i2c3_config = +{ + .base = STM32WB_I2C3_BASE, + .clk_bit = RCC_APB1ENR1_I2C3EN, + .reset_bit = RCC_APB1RSTR1_I2C3RST, + .scl_pin = GPIO_I2C3_SCL, + .sda_pin = GPIO_I2C3_SDA, +#ifndef CONFIG_I2C_POLLED + .ev_irq = STM32WB_IRQ_I2C3EV, + .er_irq = STM32WB_IRQ_I2C3ER +#endif +}; + +static struct stm32wb_i2c_priv_s stm32wb_i2c3_priv = +{ + .config = &stm32wb_i2c3_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .frequency = 0, + .dcnt = 0, + .flags = 0, + .status = 0, +#ifdef CONFIG_PM + .pm_cb.prepare = stm32wb_i2c_pm_prepare, +#endif +}; +#endif + +/* Device Structures, Instantiation */ + +static const struct i2c_ops_s stm32wb_i2c_ops = +{ + .transfer = stm32wb_i2c_transfer, +#ifdef CONFIG_I2C_RESET + .reset = stm32wb_i2c_reset +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32wb_i2c_getreg + * + * Description: + * Get a 16-bit register value by offset + * + ****************************************************************************/ + +static inline +uint16_t stm32wb_i2c_getreg(struct stm32wb_i2c_priv_s *priv, + uint8_t offset) +{ + return getreg16(priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32wb_i2c_getreg32 + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline +uint32_t stm32wb_i2c_getreg32(struct stm32wb_i2c_priv_s *priv, + uint8_t offset) +{ + return getreg32(priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32wb_i2c_putreg + * + * Description: + * Put a 16-bit register value by offset + * + ****************************************************************************/ + +static inline void stm32wb_i2c_putreg(struct stm32wb_i2c_priv_s *priv, + uint8_t offset, uint16_t value) +{ + putreg16(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32wb_i2c_putreg32 + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void stm32wb_i2c_putreg32(struct stm32wb_i2c_priv_s *priv, + uint8_t offset, uint32_t value) +{ + putreg32(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: stm32wb_i2c_modifyreg32 + * + * Description: + * Modify a 32-bit register value by offset + * + ****************************************************************************/ + +static inline +void stm32wb_i2c_modifyreg32(struct stm32wb_i2c_priv_s *priv, + uint8_t offset, uint32_t clearbits, + uint32_t setbits) +{ + modifyreg32(priv->config->base + offset, clearbits, setbits); +} + +/**************************************************************************** + * Name: stm32wb_i2c_toticks + * + * Description: + * Return a micro-second delay based on the number of bytes left to be + * processed. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32WB_I2C_DYNTIMEO +static uint32_t stm32wb_i2c_toticks(int msgc, struct i2c_msg_s *msgs) +{ + size_t bytecount = 0; + int i; + + /* Count the number of bytes left to process */ + + for (i = 0; i < msgc; i++) + { + bytecount += msgs[i].length; + } + + /* Then return a number of microseconds based on a user provided scaling + * factor. + */ + + return USEC2TICK(CONFIG_STM32WB_I2C_DYNTIMEO_USECPERBYTE * bytecount); +} +#endif + +/**************************************************************************** + * Name: stm32wb_i2c_enableinterrupts + * + * Description: + * Enable I2C interrupts + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static inline +void stm32wb_i2c_enableinterrupts(struct stm32wb_i2c_priv_s *priv) +{ + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR1_OFFSET, 0, + (I2C_CR1_TXRX | I2C_CR1_NACKIE)); +} +#endif + +/**************************************************************************** + * Name: stm32wb_i2c_sem_waitdone + * + * Description: + * Wait for a transfer to complete + * + * There are two versions of this function. The first is included when using + * interrupts while the second is used if polling (CONFIG_I2C_POLLED=y). + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static inline +int stm32wb_i2c_sem_waitdone(struct stm32wb_i2c_priv_s *priv) +{ + irqstate_t flags; + int ret; + + flags = enter_critical_section(); + + /* Enable I2C interrupts */ + + /* The TXIE and RXIE interrupts are enabled initially in + * stm32wb_i2c_process. The remainder of the interrupts, including + * error-related, are enabled here. + */ + + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR1_OFFSET, 0, + (I2C_CR1_ALLINTS & ~I2C_CR1_TXRX)); + + /* Signal the interrupt handler that we are waiting */ + + priv->intstate = INTSTATE_WAITING; + do + { + /* Wait until either the transfer is complete or the timeout expires */ + +#ifdef CONFIG_STM32WB_I2C_DYNTIMEO + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + stm32wb_i2c_toticks(priv->msgc, priv->msgv)); +#else + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + CONFIG_STM32WB_I2CTIMEOTICKS); +#endif + if (ret < 0) + { + /* Break out of the loop on irrecoverable errors. This would + * include timeouts and mystery errors reported by + * nxsem_tickwait_uninterruptible. + */ + + break; + } + } + + /* Loop until the interrupt level transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE); + + /* Set the interrupt state back to IDLE */ + + priv->intstate = INTSTATE_IDLE; + + /* Disable I2C interrupts */ + + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR1_OFFSET, I2C_CR1_ALLINTS, 0); + + leave_critical_section(flags); + return ret; +} +#else +static inline +int stm32wb_i2c_sem_waitdone(struct stm32wb_i2c_priv_s *priv) +{ + clock_t timeout; + clock_t start; + clock_t elapsed; + int ret; + + /* Get the timeout value */ + +#ifdef CONFIG_STM32WB_I2C_DYNTIMEO + timeout = stm32wb_i2c_toticks(priv->msgc, priv->msgv); +#else + timeout = CONFIG_STM32WB_I2CTIMEOTICKS; +#endif + + /* Signal the interrupt handler that we are waiting. NOTE: Interrupts + * are currently disabled but will be temporarily re-enabled below when + * nxsem_tickwait_uninterruptible() sleeps. + */ + + priv->intstate = INTSTATE_WAITING; + start = clock_systime_ticks(); + + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Poll by simply calling the timer interrupt handler until it + * reports that it is done. + */ + + stm32wb_i2c_isr_process(priv); + } + + /* Loop until the transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE && elapsed < timeout); + + i2cinfo("intstate: %d elapsed: %ld timeout: %ld status: 0x%08" PRIx32 "\n", + priv->intstate, (long)elapsed, (long)timeout, priv->status); + + /* Set the interrupt state back to IDLE */ + + ret = priv->intstate == INTSTATE_DONE ? OK : -ETIMEDOUT; + priv->intstate = INTSTATE_IDLE; + return ret; +} +#endif + +/**************************************************************************** + * Name: stm32wb_i2c_set_7bit_address + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32wb_i2c_set_7bit_address(struct stm32wb_i2c_priv_s *priv) +{ + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR2_OFFSET, I2C_CR2_SADD7_MASK, + ((priv->msgv->addr & 0x7f) << I2C_CR2_SADD7_SHIFT)); +} + +/**************************************************************************** + * Name: stm32wb_i2c_set_bytes_to_transfer + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32wb_i2c_set_bytes_to_transfer(struct stm32wb_i2c_priv_s *priv, + uint8_t n_bytes) +{ + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR2_OFFSET, I2C_CR2_NBYTES_MASK, + (n_bytes << I2C_CR2_NBYTES_SHIFT)); +} + +/**************************************************************************** + * Name: stm32wb_i2c_set_write_transfer_dir + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32wb_i2c_set_write_transfer_dir(struct stm32wb_i2c_priv_s *priv) +{ + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR2_OFFSET, I2C_CR2_RD_WRN, 0); +} + +/**************************************************************************** + * Name: stm32wb_i2c_set_read_transfer_dir + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32wb_i2c_set_read_transfer_dir(struct stm32wb_i2c_priv_s *priv) +{ + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR2_OFFSET, + 0, I2C_CR2_RD_WRN); +} + +/**************************************************************************** + * Name: stm32wb_i2c_enable_reload + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32wb_i2c_enable_reload(struct stm32wb_i2c_priv_s *priv) +{ + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR2_OFFSET, + 0, I2C_CR2_RELOAD); +} + +/**************************************************************************** + * Name: stm32wb_i2c_disable_reload + * + * Description: + * + ****************************************************************************/ + +static inline void +stm32wb_i2c_disable_reload(struct stm32wb_i2c_priv_s *priv) +{ + stm32wb_i2c_modifyreg32(priv, STM32WB_I2C_CR2_OFFSET, + I2C_CR2_RELOAD, 0); +} + +/**************************************************************************** + * Name: stm32wb_i2c_sem_waitstop + * + * Description: + * Wait for a STOP to complete + * + ****************************************************************************/ + +static inline +void stm32wb_i2c_sem_waitstop(struct stm32wb_i2c_priv_s *priv) +{ + clock_t start; + clock_t elapsed; + clock_t timeout; + uint32_t cr; + uint32_t sr; + + /* Select a timeout */ + +#ifdef CONFIG_STM32WB_I2C_DYNTIMEO + timeout = USEC2TICK(CONFIG_STM32WB_I2C_DYNTIMEO_STARTSTOP); +#else + timeout = CONFIG_STM32WB_I2CTIMEOTICKS; +#endif + + /* Wait as stop might still be in progress */ + + start = clock_systime_ticks(); + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Check for STOP condition */ + + cr = stm32wb_i2c_getreg32(priv, STM32WB_I2C_CR2_OFFSET); + if ((cr & I2C_CR2_STOP) == 0) + { + return; Review Comment: Actually this `return` is a successful flow. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
