diff --git a/drivers/st/pmic/stm32_i2c.c b/drivers/st/pmic/stm32_i2c.c new file mode 100644 index 0000000..0980139 --- /dev/null +++ b/drivers/st/pmic/stm32_i2c.c @@ -0,0 +1,851 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +/* STM32 I2C registers offsets */ +#define I2C_CR1 0x00U +#define I2C_CR2 0x04U +#define I2C_OAR1 0x08U +#define I2C_OAR2 0x0CU +#define I2C_TIMINGR 0x10U +#define I2C_TIMEOUTR 0x14U +#define I2C_ISR 0x18U +#define I2C_ICR 0x1CU +#define I2C_PECR 0x20U +#define I2C_RXDR 0x24U +#define I2C_TXDR 0x28U + +#define MAX_DELAY 0xFFFFFFFFU + +/* I2C TIMING clear register Mask */ +#define TIMING_CLEAR_MASK 0xF0FFFFFFU +/* Timeout 25 ms */ +#define I2C_TIMEOUT_BUSY 25U + +#define MAX_NBYTE_SIZE 255U + +static int i2c_request_memory_write(struct i2c_handle_s *hi2c, + uint16_t dev_addr, uint16_t mem_addr, + uint16_t mem_add_size, uint32_t timeout, + uint32_t tick_start); +static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint32_t timeout, uint32_t tick_start); + +/* Private functions to handle flags during polling transfer */ +static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, + uint8_t awaited_value, uint32_t timeout, + uint32_t tick_start); +static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout, + uint32_t tick_start); +static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, + uint32_t tick_start); +static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, + uint32_t tick_start); + +/* Private function to flush TXDR register */ +static void i2c_flush_txdr(struct i2c_handle_s *hi2c); + +/* Private function to start, restart or stop a transfer */ +static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t size, uint32_t i2c_mode, + uint32_t request); + +/* + * @brief Initialize the I2C device. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @retval 0 if OK, negative value else + */ +int stm32_i2c_init(struct i2c_handle_s *hi2c) +{ + if (hi2c == NULL) { + return -ENOENT; + } + + if (hi2c->i2c_state == I2C_STATE_RESET) { + hi2c->lock = 0; + } + + hi2c->i2c_state = I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + + /* Configure I2Cx: Frequency range */ + mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR, + hi2c->i2c_init.timing & TIMING_CLEAR_MASK); + + /* Disable Own Address1 before set the Own Address1 configuration */ + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN); + + /* Configure I2Cx: Own Address1 and ack own address1 mode */ + if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { + mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, + I2C_OAR1_OA1EN | hi2c->i2c_init.own_address1); + } else { /* I2C_ADDRESSINGMODE_10BIT */ + mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1, + I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE | + hi2c->i2c_init.own_address1); + } + + /* Configure I2Cx: Addressing Master mode */ + if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_10BIT) { + mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10); + } + + /* + * Enable the AUTOEND by default, and enable NACK + * (should be disable only during Slave process) + */ + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, + I2C_CR2_AUTOEND | I2C_CR2_NACK); + + /* Disable Own Address2 before set the Own Address2 configuration */ + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE); + + /* Configure I2Cx: Dual mode and Own Address2 */ + mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2, + hi2c->i2c_init.dual_address_mode | + hi2c->i2c_init.own_address2 | + (hi2c->i2c_init.own_address2_masks << 8)); + + /* Configure I2Cx: Generalcall and NoStretch mode */ + mmio_write_32(hi2c->i2c_base_addr + I2C_CR1, + hi2c->i2c_init.general_call_mode | + hi2c->i2c_init.no_stretch_mode); + + /* Enable the selected I2C peripheral */ + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + + hi2c->i2c_err = I2C_ERROR_NONE; + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + return 0; +} + +/* + * @brief Write an amount of data in blocking mode to a specific memory address + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: size of internal memory address + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout: timeout duration + * @retval 0 if OK, negative value else + */ +int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout) +{ + uint32_t tickstart; + + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { + return -EBUSY; + } + + if ((p_data == NULL) || (size == 0U)) { + return -EINVAL; + } + + hi2c->lock = 1; + + tickstart = (uint32_t)read_cntpct_el0(); + + if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, + tickstart) != 0) { + return -EIO; + } + + hi2c->i2c_state = I2C_STATE_BUSY_TX; + hi2c->i2c_mode = I2C_MODE_MEM; + hi2c->i2c_err = I2C_ERROR_NONE; + + hi2c->p_buff = p_data; + hi2c->xfer_count = size; + + /* Send Slave Address and Memory Address */ + if (i2c_request_memory_write(hi2c, dev_addr, mem_addr, mem_add_size, + timeout, tickstart) != 0) { + hi2c->lock = 0; + return -EIO; + } + + /* + * Set NBYTES to write and reload + * if hi2c->xfer_count > MAX_NBYTE_SIZE + */ + if (hi2c->xfer_count > MAX_NBYTE_SIZE) { + hi2c->xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, + I2C_RELOAD_MODE, I2C_NO_STARTSTOP); + } else { + hi2c->xfer_size = hi2c->xfer_count; + i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, + I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); + } + + do { + if (i2c_wait_txis(hi2c, timeout, tickstart) != 0) { + return -EIO; + } + + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *hi2c->p_buff); + hi2c->p_buff++; + hi2c->xfer_count--; + hi2c->xfer_size--; + + if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { + /* Wait until TCR flag is set */ + if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, + tickstart) != 0) { + return -EIO; + } + + if (hi2c->xfer_count > MAX_NBYTE_SIZE) { + hi2c->xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, + hi2c->xfer_size, + I2C_RELOAD_MODE, + I2C_NO_STARTSTOP); + } else { + hi2c->xfer_size = hi2c->xfer_count; + i2c_transfer_config(hi2c, dev_addr, + hi2c->xfer_size, + I2C_AUTOEND_MODE, + I2C_NO_STARTSTOP); + } + } + + } while (hi2c->xfer_count > 0U); + + /* + * No need to Check TC flag, with AUTOEND mode the stop + * is automatically generated. + * Wait until STOPF flag is reset. + */ + if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) { + return -EIO; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); + + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + hi2c->lock = 0; + + return 0; +} + +/* + * @brief Read an amount of data in blocking mode from a specific memory + * address + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: size of internal memory address + * @param p_data: Pointer to data buffer + * @param size: Amount of data to be sent + * @param timeout: timeout duration + * @retval 0 if OK, negative value else + */ +int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout) +{ + uint32_t tickstart; + + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { + return -EBUSY; + } + + if ((p_data == NULL) || (size == 0U)) { + return -EINVAL; + } + + hi2c->lock = 1; + + tickstart = (uint32_t)read_cntpct_el0(); + + if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, I2C_TIMEOUT_BUSY, + tickstart) != 0) { + return -EIO; + } + + hi2c->i2c_state = I2C_STATE_BUSY_RX; + hi2c->i2c_mode = I2C_MODE_MEM; + hi2c->i2c_err = I2C_ERROR_NONE; + + hi2c->p_buff = p_data; + hi2c->xfer_count = size; + + /* Send Slave Address and Memory Address */ + if (i2c_request_memory_read(hi2c, dev_addr, mem_addr, mem_add_size, + timeout, tickstart) != 0) { + hi2c->lock = 0; + return -EIO; + } + + /* + * Send Slave Address. + * Set NBYTES to write and reload if hi2c->xfer_count > MAX_NBYTE_SIZE + * and generate RESTART. + */ + if (hi2c->xfer_count > MAX_NBYTE_SIZE) { + hi2c->xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, + I2C_RELOAD_MODE, I2C_GENERATE_START_READ); + } else { + hi2c->xfer_size = hi2c->xfer_count; + i2c_transfer_config(hi2c, dev_addr, hi2c->xfer_size, + I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); + } + + do { + if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout, + tickstart) != 0) { + return -EIO; + } + + *hi2c->p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR); + hi2c->p_buff++; + hi2c->xfer_size--; + hi2c->xfer_count--; + + if ((hi2c->xfer_count != 0U) && (hi2c->xfer_size == 0U)) { + if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, + tickstart) != 0) { + return -EIO; + } + + if (hi2c->xfer_count > MAX_NBYTE_SIZE) { + hi2c->xfer_size = MAX_NBYTE_SIZE; + i2c_transfer_config(hi2c, dev_addr, + hi2c->xfer_size, + I2C_RELOAD_MODE, + I2C_NO_STARTSTOP); + } else { + hi2c->xfer_size = hi2c->xfer_count; + i2c_transfer_config(hi2c, dev_addr, + hi2c->xfer_size, + I2C_AUTOEND_MODE, + I2C_NO_STARTSTOP); + } + } + } while (hi2c->xfer_count > 0U); + + /* + * No need to Check TC flag, with AUTOEND mode the stop + * is automatically generated + * Wait until STOPF flag is reset + */ + if (i2c_wait_stop(hi2c, timeout, tickstart) != 0) { + return -EIO; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); + + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + hi2c->lock = 0; + + return 0; +} + +/* + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param trials: Number of trials + * @param timeout: timeout duration + * @retval 0 if OK, negative value else + */ +int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, + uint16_t dev_addr, uint32_t trials, + uint32_t timeout) +{ + uint32_t i2c_trials = 0U; + + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { + return -EBUSY; + } + + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) != + 0U) { + return -EBUSY; + } + + hi2c->lock = 1; + + hi2c->i2c_state = I2C_STATE_BUSY; + hi2c->i2c_err = I2C_ERROR_NONE; + + do { + uint32_t tickstart; + + /* Generate Start */ + if (hi2c->i2c_init.addressing_mode == I2C_ADDRESSINGMODE_7BIT) { + mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, + (((uint32_t)dev_addr & I2C_CR2_SADD) | + I2C_CR2_START | I2C_CR2_AUTOEND) & + ~I2C_CR2_RD_WRN); + } else { + mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, + (((uint32_t)dev_addr & I2C_CR2_SADD) | + I2C_CR2_START | I2C_CR2_ADD10) & + ~I2C_CR2_RD_WRN); + } + + /* + * No need to Check TC flag, with AUTOEND mode the stop + * is automatically generated + * Wait until STOPF flag is set or a NACK flag is set + */ + tickstart = (uint32_t)read_cntpct_el0(); + while (((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + (I2C_FLAG_STOPF | I2C_FLAG_AF)) == 0U) && + (hi2c->i2c_state != I2C_STATE_TIMEOUT)) { + if (timeout != MAX_DELAY) { + if ((((uint32_t)read_cntpct_el0() - tickstart) > + timeout) || (timeout == 0U)) { + hi2c->i2c_state = I2C_STATE_READY; + + hi2c->i2c_err |= + I2C_ERROR_TIMEOUT; + + hi2c->lock = 0; + + return -EIO; + } + } + } + + /* Check if the NACKF flag has not been set */ + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + I2C_FLAG_AF) == 0U) { + if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, + tickstart) != 0) { + return -EIO; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, + I2C_FLAG_STOPF); + + hi2c->i2c_state = I2C_STATE_READY; + + hi2c->lock = 0; + + return 0; + } + + if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, + tickstart) != 0) { + return -EIO; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + + if (i2c_trials == trials) { + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, + I2C_CR2_STOP); + + if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout, + tickstart) != 0) { + return -EIO; + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, + I2C_FLAG_STOPF); + } + + i2c_trials++; + } while (i2c_trials < trials); + + hi2c->i2c_state = I2C_STATE_READY; + + hi2c->i2c_err |= I2C_ERROR_TIMEOUT; + + hi2c->lock = 0; + + return -EIO; +} + +/* + * @brief Master sends target device address followed by internal memory + * address for write request. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: size of internal memory address + * @param timeout: timeout duration + * @param tick_start Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_request_memory_write(struct i2c_handle_s *hi2c, + uint16_t dev_addr, uint16_t mem_addr, + uint16_t mem_add_size, uint32_t timeout, + uint32_t tick_start) +{ + i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE, + I2C_GENERATE_START_WRITE); + + if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { + return -EIO; + } + + if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { + /* Send Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } else { + /* Send MSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)((mem_addr & 0xFF00U) >> 8)); + + /* Wait until TXIS flag is set */ + if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { + return -EIO; + } + + /* Send LSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } + + if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout, tick_start) != + 0) { + return -EIO; + } + + return 0; +} + +/* + * @brief Master sends target device address followed by internal memory + * address for read request. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param dev_addr: Target device address + * @param mem_addr: Internal memory address + * @param mem_add_size: size of internal memory address + * @param timeout: timeout duration + * @param tick_start Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint32_t timeout, uint32_t tick_start) +{ + i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE, + I2C_GENERATE_START_WRITE); + + if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { + return -EIO; + } + + if (mem_add_size == I2C_MEMADD_SIZE_8BIT) { + /* Send Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } else { + /* Send MSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)((mem_addr & 0xFF00U) >> 8)); + + /* Wait until TXIS flag is set */ + if (i2c_wait_txis(hi2c, timeout, tick_start) != 0) { + return -EIO; + } + + /* Send LSB of Memory Address */ + mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, + (uint8_t)(mem_addr & 0x00FFU)); + } + + if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout, tick_start) != 0) { + return -EIO; + } + + return 0; +} + +/* + * @brief I2C Tx data register flush process. + * @param hi2c: I2C handle. + * @retval None + */ +static void i2c_flush_txdr(struct i2c_handle_s *hi2c) +{ + /* + * If a pending TXIS flag is set, + * write a dummy data in TXDR to clear it. + */ + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) != + 0U) { + mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0); + } + + /* Flush TX register if not empty */ + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) == + 0U) { + mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR, + I2C_FLAG_TXE); + } +} + +/* + * @brief This function handles I2C Communication timeout. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param flag: Specifies the I2C flag to check. + * @param awaited_value: The awaited bit value for the flag (0 or 1). + * @param timeout: timeout duration + * @param tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag, + uint8_t awaited_value, uint32_t timeout, + uint32_t tick_start) +{ + uint8_t flag_check; + + do { + flag_check = ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + flag) == flag) ? 1U : 0U; + + if (timeout != MAX_DELAY) { + if ((((uint32_t)read_cntpct_el0() - tick_start) > + timeout) || (timeout == 0U)) { + hi2c->i2c_err |= I2C_ERROR_TIMEOUT; + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + hi2c->lock = 0; + return -EIO; + } + } + } while (flag_check == awaited_value); + + return 0; +} + +/* + * @brief This function handles I2C Communication timeout for specific usage + * of TXIS flag. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param timeout: timeout duration + * @param tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint32_t timeout, + uint32_t tick_start) +{ + while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + I2C_FLAG_TXIS) == 0U) { + if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { + return -EIO; + } + + if (timeout != MAX_DELAY) { + if ((((uint32_t)read_cntpct_el0() - tick_start) > + timeout) || (timeout == 0U)) { + hi2c->i2c_err |= I2C_ERROR_TIMEOUT; + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + hi2c->lock = 0; + + return -EIO; + } + } + } + + return 0; +} + +/* + * @brief This function handles I2C Communication timeout for specific + * usage of STOP flag. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param timeout: timeout duration + * @param tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint32_t timeout, + uint32_t tick_start) +{ + while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + I2C_FLAG_STOPF) == 0U) { + if (i2c_ack_failed(hi2c, timeout, tick_start) != 0) { + return -EIO; + } + + if ((((uint32_t)read_cntpct_el0() - tick_start) > timeout) || + (timeout == 0U)) { + hi2c->i2c_err |= I2C_ERROR_TIMEOUT; + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + hi2c->lock = 0; + + return -EIO; + } + } + + return 0; +} + +/* + * @brief This function handles Acknowledge failed detection during + * an I2C Communication. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2C. + * @param timeout: timeout duration + * @param tick_start: Tick start value + * @retval 0 if OK, negative value else + */ +static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint32_t timeout, + uint32_t tick_start) +{ + if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) { + return 0; + } + + /* + * Wait until STOP Flag is reset. + * AutoEnd should be initiate after AF. + */ + while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & + I2C_FLAG_STOPF) == 0U) { + if (timeout != MAX_DELAY) { + if ((((uint32_t)read_cntpct_el0() - tick_start) > + timeout) || (timeout == 0U)) { + hi2c->i2c_err |= I2C_ERROR_TIMEOUT; + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + hi2c->lock = 0; + + return -EIO; + } + } + } + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF); + + mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF); + + i2c_flush_txdr(hi2c); + + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2); + + hi2c->i2c_err |= I2C_ERROR_AF; + hi2c->i2c_state = I2C_STATE_READY; + hi2c->i2c_mode = I2C_MODE_NONE; + + hi2c->lock = 0; + + return -EIO; +} + +/* + * @brief Handles I2Cx communication when starting transfer or during transfer + * (TC or TCR flag are set). + * @param hi2c: I2C handle. + * @param dev_addr: Specifies the slave address to be programmed. + * @param size: Specifies the number of bytes to be programmed. + * This parameter must be a value between 0 and 255. + * @param i2c_mode: New state of the I2C START condition generation. + * This parameter can be one of the following values: + * @arg @ref I2C_RELOAD_MODE: Enable Reload mode . + * @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode. + * @arg @ref I2C_SOFTEND_MODE: Enable Software end mode. + * @param request: New state of the I2C START condition generation. + * This parameter can be one of the following values: + * @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition. + * @arg @ref I2C_GENERATE_STOP: Generate stop condition + * (size should be set to 0). + * @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request. + * @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request. + * @retval None + */ +static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t size, uint32_t i2c_mode, + uint32_t request) +{ + uint32_t clr_value, set_value; + + clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | + I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) | + (I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET))); + + set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) | + (((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) | + i2c_mode | request; + + mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value); +} + +/* + * @brief Configure I2C Analog noise filter. + * @param hi2c: Pointer to a struct i2c_handle_s structure that contains + * the configuration information for the specified I2Cx peripheral + * @param analog_filter: New state of the Analog filter. + * @retval 0 if OK, negative value else + */ +int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, + uint32_t analog_filter) +{ + if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) { + return -EBUSY; + } + + hi2c->lock = 1; + + hi2c->i2c_state = I2C_STATE_BUSY; + + /* Disable the selected I2C peripheral */ + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + + /* Reset I2Cx ANOFF bit */ + mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF); + + /* Set analog filter bit*/ + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter); + + /* Enable the selected I2C peripheral */ + mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE); + + hi2c->i2c_state = I2C_STATE_READY; + + hi2c->lock = 0; + + return 0; +} diff --git a/drivers/st/pmic/stm32mp1_pmic.c b/drivers/st/pmic/stm32mp1_pmic.c new file mode 100644 index 0000000..958de08 --- /dev/null +++ b/drivers/st/pmic/stm32mp1_pmic.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */ +#define I2C_TIMING 0x10D07DB5 + +#define I2C_TIMEOUT 0xFFFFF + +#define MASK_RESET_BUCK3 BIT(2) + +#define STPMU1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2)) +#define STPMU1_LDO12356_OUTPUT_SHIFT 2 +#define STPMU1_LDO3_MODE (uint8_t)(BIT(7)) +#define STPMU1_LDO3_DDR_SEL 31U +#define STPMU1_LDO3_1800000 (9U << STPMU1_LDO12356_OUTPUT_SHIFT) + +#define STPMU1_BUCK_OUTPUT_SHIFT 2 +#define STPMU1_BUCK3_1V8 (39U << STPMU1_BUCK_OUTPUT_SHIFT) + +#define STPMU1_DEFAULT_START_UP_DELAY_MS 1 + +static struct i2c_handle_s i2c_handle; +static uint32_t pmic_i2c_addr; + +static int dt_get_pmic_node(void *fdt) +{ + return fdt_node_offset_by_compatible(fdt, -1, "st,stpmu1"); +} + +bool dt_check_pmic(void) +{ + int node; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return false; + } + + node = dt_get_pmic_node(fdt); + if (node < 0) { + VERBOSE("%s: No PMIC node found in DT\n", __func__); + return false; + } + + return fdt_check_status(node); +} + +static int dt_pmic_i2c_config(struct dt_node_info *i2c_info) +{ + int pmic_node, i2c_node; + void *fdt; + const fdt32_t *cuint; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + pmic_node = dt_get_pmic_node(fdt); + if (pmic_node < 0) { + return -FDT_ERR_NOTFOUND; + } + + cuint = fdt_getprop(fdt, pmic_node, "reg", NULL); + if (cuint == NULL) { + return -FDT_ERR_NOTFOUND; + } + + pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1; + if (pmic_i2c_addr > UINT16_MAX) { + return -EINVAL; + } + + i2c_node = fdt_parent_offset(fdt, pmic_node); + if (i2c_node < 0) { + return -FDT_ERR_NOTFOUND; + } + + dt_fill_device_info(i2c_info, i2c_node); + if (i2c_info->base == 0U) { + return -FDT_ERR_NOTFOUND; + } + + return dt_set_pinctrl_config(i2c_node); +} + +int dt_pmic_enable_boot_on_regulators(void) +{ + int pmic_node, regulators_node, regulator_node; + void *fdt; + + if (fdt_get_address(&fdt) == 0) { + return -ENOENT; + } + + pmic_node = dt_get_pmic_node(fdt); + if (pmic_node < 0) { + return -FDT_ERR_NOTFOUND; + } + + regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators"); + + fdt_for_each_subnode(regulator_node, fdt, regulators_node) { + const fdt32_t *cuint; + const char *node_name; + uint16_t voltage; + + if (fdt_getprop(fdt, regulator_node, "regulator-boot-on", + NULL) == NULL) { + continue; + } + + cuint = fdt_getprop(fdt, regulator_node, + "regulator-min-microvolt", NULL); + if (cuint == NULL) { + continue; + } + + /* DT uses microvolts, whereas driver awaits millivolts */ + voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U); + node_name = fdt_get_name(fdt, regulator_node, NULL); + + if (stpmu1_is_regulator_enabled(node_name) == 0U) { + int status; + + status = stpmu1_regulator_voltage_set(node_name, + voltage); + if (status != 0) { + return status; + } + + status = stpmu1_regulator_enable(node_name); + if (status != 0) { + return status; + } + } + } + + return 0; +} + +void initialize_pmic_i2c(void) +{ + int ret; + struct dt_node_info i2c_info; + + if (dt_pmic_i2c_config(&i2c_info) != 0) { + ERROR("I2C configuration failed\n"); + panic(); + } + + if (stm32mp1_clk_enable((uint32_t)i2c_info.clock) < 0) { + ERROR("I2C clock enable failed\n"); + panic(); + } + + /* Initialize PMIC I2C */ + i2c_handle.i2c_base_addr = i2c_info.base; + i2c_handle.i2c_init.timing = I2C_TIMING; + i2c_handle.i2c_init.own_address1 = pmic_i2c_addr; + i2c_handle.i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT; + i2c_handle.i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE; + i2c_handle.i2c_init.own_address2 = 0; + i2c_handle.i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK; + i2c_handle.i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE; + i2c_handle.i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE; + + ret = stm32_i2c_init(&i2c_handle); + if (ret != 0) { + ERROR("Cannot initialize I2C %x (%d)\n", + i2c_handle.i2c_base_addr, ret); + panic(); + } + + ret = stm32_i2c_config_analog_filter(&i2c_handle, + I2C_ANALOGFILTER_ENABLE); + if (ret != 0) { + ERROR("Cannot initialize I2C analog filter (%d)\n", ret); + panic(); + } + + ret = stm32_i2c_is_device_ready(&i2c_handle, (uint16_t)pmic_i2c_addr, 1, + I2C_TIMEOUT); + if (ret != 0) { + ERROR("I2C device not ready (%d)\n", ret); + panic(); + } + + stpmu1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr); +} + +void initialize_pmic(void) +{ + int status; + uint8_t read_val; + + initialize_pmic_i2c(); + + status = stpmu1_register_read(VERSION_STATUS_REG, &read_val); + if (status != 0) { + panic(); + } + + INFO("PMIC version = 0x%x\n", read_val); + + /* Keep VDD on during the reset cycle */ + status = stpmu1_register_update(MASK_RESET_BUCK_REG, + MASK_RESET_BUCK3, + MASK_RESET_BUCK3); + if (status != 0) { + panic(); + } +} + +int pmic_ddr_power_init(enum ddr_type ddr_type) +{ + bool buck3_at_1v8 = false; + uint8_t read_val; + int status; + + switch (ddr_type) { + case STM32MP_DDR3: + /* Set LDO3 to sync mode */ + status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val); + if (status != 0) { + return status; + } + + read_val &= ~STPMU1_LDO3_MODE; + read_val &= ~STPMU1_LDO12356_OUTPUT_MASK; + read_val |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; + + status = stpmu1_register_write(LDO3_CONTROL_REG, read_val); + if (status != 0) { + return status; + } + + status = stpmu1_regulator_voltage_set("buck2", 1350); + if (status != 0) { + return status; + } + + status = stpmu1_regulator_enable("buck2"); + if (status != 0) { + return status; + } + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + status = stpmu1_regulator_enable("vref_ddr"); + if (status != 0) { + return status; + } + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + status = stpmu1_regulator_enable("ldo3"); + if (status != 0) { + return status; + } + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + break; + + case STM32MP_LPDDR2: + /* + * Set LDO3 to 1.8V + * Set LDO3 to bypass mode if BUCK3 = 1.8V + * Set LDO3 to normal mode if BUCK3 != 1.8V + */ + status = stpmu1_register_read(BUCK3_CONTROL_REG, &read_val); + if (status != 0) { + return status; + } + + if ((read_val & STPMU1_BUCK3_1V8) == STPMU1_BUCK3_1V8) { + buck3_at_1v8 = true; + } + + status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val); + if (status != 0) { + return status; + } + + read_val &= ~STPMU1_LDO3_MODE; + read_val &= ~STPMU1_LDO12356_OUTPUT_MASK; + read_val |= STPMU1_LDO3_1800000; + if (buck3_at_1v8) { + read_val |= STPMU1_LDO3_MODE; + } + + status = stpmu1_register_write(LDO3_CONTROL_REG, read_val); + if (status != 0) { + return status; + } + + status = stpmu1_regulator_voltage_set("buck2", 1200); + if (status != 0) { + return status; + } + + status = stpmu1_regulator_enable("ldo3"); + if (status != 0) { + return status; + } + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + status = stpmu1_regulator_enable("buck2"); + if (status != 0) { + return status; + } + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + status = stpmu1_regulator_enable("vref_ddr"); + if (status != 0) { + return status; + } + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + break; + + default: + break; + }; + + return 0; +} diff --git a/drivers/st/pmic/stpmu1.c b/drivers/st/pmic/stpmu1.c new file mode 100644 index 0000000..5951899 --- /dev/null +++ b/drivers/st/pmic/stpmu1.c @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +struct regul_struct { + const char *dt_node_name; + const uint16_t *voltage_table; + uint8_t voltage_table_size; + uint8_t control_reg; + uint8_t low_power_reg; +}; + +static struct i2c_handle_s *stpmu_i2c_handle; +static uint16_t stpmu_i2c_addr; + +/* Voltage tables in mV */ +static const uint16_t buck1_voltage_table[] = { + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800, + 825, + 850, + 875, + 900, + 925, + 950, + 975, + 1000, + 1025, + 1050, + 1075, + 1100, + 1125, + 1150, + 1175, + 1200, + 1225, + 1250, + 1275, + 1300, + 1325, + 1350, + 1350, +}; + +static const uint16_t buck2_voltage_table[] = { + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1050, + 1050, + 1100, + 1100, + 1150, + 1150, + 1200, + 1200, + 1250, + 1250, + 1300, + 1300, + 1350, + 1350, + 1400, + 1400, + 1450, + 1450, + 1500, +}; + +static const uint16_t buck3_voltage_table[] = { + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1000, + 1100, + 1100, + 1100, + 1100, + 1200, + 1200, + 1200, + 1200, + 1300, + 1300, + 1300, + 1300, + 1400, + 1400, + 1400, + 1400, + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200, + 3300, + 3400, +}; + +static const uint16_t buck4_voltage_table[] = { + 600, + 625, + 650, + 675, + 700, + 725, + 750, + 775, + 800, + 825, + 850, + 875, + 900, + 925, + 950, + 975, + 1000, + 1025, + 1050, + 1075, + 1100, + 1125, + 1150, + 1175, + 1200, + 1225, + 1250, + 1275, + 1300, + 1300, + 1350, + 1350, + 1400, + 1400, + 1450, + 1450, + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200, + 3300, + 3400, + 3500, + 3600, + 3700, + 3800, + 3900, +}; + +static const uint16_t ldo1_voltage_table[] = { + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200, + 3300, +}; + +static const uint16_t ldo2_voltage_table[] = { + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200, + 3300, +}; + +static const uint16_t ldo3_voltage_table[] = { + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200, + 3300, + 3300, + 3300, + 3300, + 3300, + 3300, + 3300, + 0xFFFF, /* VREFDDR */ +}; + +static const uint16_t ldo5_voltage_table[] = { + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200, + 3300, + 3400, + 3500, + 3600, + 3700, + 3800, + 3900, +}; + +static const uint16_t ldo6_voltage_table[] = { + 900, + 1000, + 1100, + 1200, + 1300, + 1400, + 1500, + 1600, + 1700, + 1800, + 1900, + 2000, + 2100, + 2200, + 2300, + 2400, + 2500, + 2600, + 2700, + 2800, + 2900, + 3000, + 3100, + 3200, + 3300, +}; + +static const uint16_t ldo4_voltage_table[] = { + 3300, +}; + +static const uint16_t vref_ddr_voltage_table[] = { + 3300, +}; + +/* Table of Regulators in PMIC SoC */ +static const struct regul_struct regulators_table[] = { + { + .dt_node_name = "buck1", + .voltage_table = buck1_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck1_voltage_table), + .control_reg = BUCK1_CONTROL_REG, + .low_power_reg = BUCK1_PWRCTRL_REG, + }, + { + .dt_node_name = "buck2", + .voltage_table = buck2_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck2_voltage_table), + .control_reg = BUCK2_CONTROL_REG, + .low_power_reg = BUCK2_PWRCTRL_REG, + }, + { + .dt_node_name = "buck3", + .voltage_table = buck3_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck3_voltage_table), + .control_reg = BUCK3_CONTROL_REG, + .low_power_reg = BUCK3_PWRCTRL_REG, + }, + { + .dt_node_name = "buck4", + .voltage_table = buck4_voltage_table, + .voltage_table_size = ARRAY_SIZE(buck4_voltage_table), + .control_reg = BUCK4_CONTROL_REG, + .low_power_reg = BUCK4_PWRCTRL_REG, + }, + { + .dt_node_name = "ldo1", + .voltage_table = ldo1_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table), + .control_reg = LDO1_CONTROL_REG, + .low_power_reg = LDO1_PWRCTRL_REG, + }, + { + .dt_node_name = "ldo2", + .voltage_table = ldo2_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table), + .control_reg = LDO2_CONTROL_REG, + .low_power_reg = LDO2_PWRCTRL_REG, + }, + { + .dt_node_name = "ldo3", + .voltage_table = ldo3_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table), + .control_reg = LDO3_CONTROL_REG, + .low_power_reg = LDO3_PWRCTRL_REG, + }, + { + .dt_node_name = "ldo4", + .voltage_table = ldo4_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table), + .control_reg = LDO4_CONTROL_REG, + .low_power_reg = LDO4_PWRCTRL_REG, + }, + { + .dt_node_name = "ldo5", + .voltage_table = ldo5_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table), + .control_reg = LDO5_CONTROL_REG, + .low_power_reg = LDO5_PWRCTRL_REG, + }, + { + .dt_node_name = "ldo6", + .voltage_table = ldo6_voltage_table, + .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table), + .control_reg = LDO6_CONTROL_REG, + .low_power_reg = LDO6_PWRCTRL_REG, + }, + { + .dt_node_name = "vref_ddr", + .voltage_table = vref_ddr_voltage_table, + .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table), + .control_reg = VREF_DDR_CONTROL_REG, + .low_power_reg = VREF_DDR_PWRCTRL_REG, + }, +}; + +#define MAX_REGUL ARRAY_SIZE(regulators_table) + +static const struct regul_struct *stpmu1_get_regulator_data(const char *name) +{ + uint8_t i; + + for (i = 0 ; i < MAX_REGUL ; i++) { + if (strncmp(name, regulators_table[i].dt_node_name, + strlen(regulators_table[i].dt_node_name)) == 0) { + return ®ulators_table[i]; + } + } + + /* Regulator not found */ + panic(); + return NULL; +} + +static uint8_t stpmu1_voltage_find_index(const char *name, + uint16_t millivolts) +{ + const struct regul_struct *regul = stpmu1_get_regulator_data(name); + uint8_t i; + + for (i = 0 ; i < regul->voltage_table_size ; i++) { + if (regul->voltage_table[i] == millivolts) { + return i; + } + } + + /* Voltage not found */ + panic(); + + return 0; +} + +int stpmu1_switch_off(void) +{ + return stpmu1_register_update(MAIN_CONTROL_REG, 1, + SOFTWARE_SWITCH_OFF_ENABLED); +} + +int stpmu1_regulator_enable(const char *name) +{ + const struct regul_struct *regul = stpmu1_get_regulator_data(name); + + return stpmu1_register_update(regul->control_reg, BIT(0), BIT(0)); +} + +int stpmu1_regulator_disable(const char *name) +{ + const struct regul_struct *regul = stpmu1_get_regulator_data(name); + + return stpmu1_register_update(regul->control_reg, 0, BIT(0)); +} + +uint8_t stpmu1_is_regulator_enabled(const char *name) +{ + uint8_t val; + const struct regul_struct *regul = stpmu1_get_regulator_data(name); + + if (stpmu1_register_read(regul->control_reg, &val) != 0) { + panic(); + } + + return (val & 0x1U); +} + +int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts) +{ + uint8_t voltage_index = stpmu1_voltage_find_index(name, millivolts); + const struct regul_struct *regul = stpmu1_get_regulator_data(name); + + return stpmu1_register_update(regul->control_reg, voltage_index << 2, + 0xFC); +} + +int stpmu1_register_read(uint8_t register_id, uint8_t *value) +{ + return stm32_i2c_mem_read(stpmu_i2c_handle, stpmu_i2c_addr, + (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT, + value, 1, 100000); +} + +int stpmu1_register_write(uint8_t register_id, uint8_t value) +{ + int status; + + status = stm32_i2c_mem_write(stpmu_i2c_handle, stpmu_i2c_addr, + (uint16_t)register_id, + I2C_MEMADD_SIZE_8BIT, &value, 1, 100000); + + if (status != 0) { + return status; + } + + if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) { + uint8_t readval; + + status = stpmu1_register_read(register_id, &readval); + if (status != 0) { + return status; + } + + if (readval != value) { + return -1; + } + } + + return 0; +} + +int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask) +{ + int status; + uint8_t val; + + status = stpmu1_register_read(register_id, &val); + if (status != 0) { + return status; + } + + /* Clear bits to update */ + val &= ~mask; + + /* Update appropriate bits*/ + val |= (value & mask); + + /* Send new value on I2C Bus */ + return stpmu1_register_write(register_id, val); +} + +void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr) +{ + stpmu_i2c_handle = i2c_handle; + stpmu_i2c_addr = i2c_addr; +} diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h new file mode 100644 index 0000000..29b9d34 --- /dev/null +++ b/include/drivers/st/stm32_i2c.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_I2C_H +#define __STM32MP1_I2C_H + +#include +#include + +/* Bit definition for I2C_CR1 register */ +#define I2C_CR1_PE BIT(0) +#define I2C_CR1_TXIE BIT(1) +#define I2C_CR1_RXIE BIT(2) +#define I2C_CR1_ADDRIE BIT(3) +#define I2C_CR1_NACKIE BIT(4) +#define I2C_CR1_STOPIE BIT(5) +#define I2C_CR1_TCIE BIT(6) +#define I2C_CR1_ERRIE BIT(7) +#define I2C_CR1_DNF GENMASK(11, 8) +#define I2C_CR1_ANFOFF BIT(12) +#define I2C_CR1_SWRST BIT(13) +#define I2C_CR1_TXDMAEN BIT(14) +#define I2C_CR1_RXDMAEN BIT(15) +#define I2C_CR1_SBC BIT(16) +#define I2C_CR1_NOSTRETCH BIT(17) +#define I2C_CR1_WUPEN BIT(18) +#define I2C_CR1_GCEN BIT(19) +#define I2C_CR1_SMBHEN BIT(22) +#define I2C_CR1_SMBDEN BIT(21) +#define I2C_CR1_ALERTEN BIT(22) +#define I2C_CR1_PECEN BIT(23) + +/* Bit definition for I2C_CR2 register */ +#define I2C_CR2_SADD GENMASK(9, 0) +#define I2C_CR2_RD_WRN BIT(10) +#define I2C_CR2_RD_WRN_OFFSET 10U +#define I2C_CR2_ADD10 BIT(11) +#define I2C_CR2_HEAD10R BIT(12) +#define I2C_CR2_START BIT(13) +#define I2C_CR2_STOP BIT(14) +#define I2C_CR2_NACK BIT(15) +#define I2C_CR2_NBYTES GENMASK(23, 16) +#define I2C_CR2_NBYTES_OFFSET 16U +#define I2C_CR2_RELOAD BIT(24) +#define I2C_CR2_AUTOEND BIT(25) +#define I2C_CR2_PECBYTE BIT(26) + +/* Bit definition for I2C_OAR1 register */ +#define I2C_OAR1_OA1 GENMASK(9, 0) +#define I2C_OAR1_OA1MODE BIT(10) +#define I2C_OAR1_OA1EN BIT(15) + +/* Bit definition for I2C_OAR2 register */ +#define I2C_OAR2_OA2 GENMASK(7, 1) +#define I2C_OAR2_OA2MSK GENMASK(10, 8) +#define I2C_OAR2_OA2NOMASK 0 +#define I2C_OAR2_OA2MASK01 BIT(8) +#define I2C_OAR2_OA2MASK02 BIT(9) +#define I2C_OAR2_OA2MASK03 GENMASK(9, 8) +#define I2C_OAR2_OA2MASK04 BIT(10) +#define I2C_OAR2_OA2MASK05 (BIT(8) | BIT(10)) +#define I2C_OAR2_OA2MASK06 (BIT(9) | BIT(10)) +#define I2C_OAR2_OA2MASK07 GENMASK(10, 8) +#define I2C_OAR2_OA2EN BIT(15) + +/* Bit definition for I2C_TIMINGR register */ +#define I2C_TIMINGR_SCLL GENMASK(7, 0) +#define I2C_TIMINGR_SCLH GENMASK(15, 8) +#define I2C_TIMINGR_SDADEL GENMASK(19, 16) +#define I2C_TIMINGR_SCLDEL GENMASK(23, 20) +#define I2C_TIMINGR_PRESC GENMASK(31, 28) + +/* Bit definition for I2C_TIMEOUTR register */ +#define I2C_TIMEOUTR_TIMEOUTA GENMASK(11, 0) +#define I2C_TIMEOUTR_TIDLE BIT(12) +#define I2C_TIMEOUTR_TIMOUTEN BIT(15) +#define I2C_TIMEOUTR_TIMEOUTB GENMASK(27, 16) +#define I2C_TIMEOUTR_TEXTEN BIT(31) + +/* Bit definition for I2C_ISR register */ +#define I2C_ISR_TXE BIT(0) +#define I2C_ISR_TXIS BIT(1) +#define I2C_ISR_RXNE BIT(2) +#define I2C_ISR_ADDR BIT(3) +#define I2C_ISR_NACKF BIT(4) +#define I2C_ISR_STOPF BIT(5) +#define I2C_ISR_TC BIT(6) +#define I2C_ISR_TCR BIT(7) +#define I2C_ISR_BERR BIT(8) +#define I2C_ISR_ARLO BIT(9) +#define I2C_ISR_OVR BIT(10) +#define I2C_ISR_PECERR BIT(11) +#define I2C_ISR_TIMEOUT BIT(12) +#define I2C_ISR_ALERT BIT(13) +#define I2C_ISR_BUSY BIT(15) +#define I2C_ISR_DIR BIT(16) +#define I2C_ISR_ADDCODE GENMASK(23, 17) + +/* Bit definition for I2C_ICR register */ +#define I2C_ICR_ADDRCF BIT(3) +#define I2C_ICR_NACKCF BIT(4) +#define I2C_ICR_STOPCF BIT(5) +#define I2C_ICR_BERRCF BIT(8) +#define I2C_ICR_ARLOCF BIT(9) +#define I2C_ICR_OVRCF BIT(10) +#define I2C_ICR_PECCF BIT(11) +#define I2C_ICR_TIMOUTCF BIT(12) +#define I2C_ICR_ALERTCF BIT(13) + +struct stm32_i2c_init_s { + uint32_t timing; /* Specifies the I2C_TIMINGR_register value + * This parameter is calculated by referring + * to I2C initialization section in Reference + * manual. + */ + + uint32_t own_address1; /* Specifies the first device own address. + * This parameter can be a 7-bit or 10-bit + * address. + */ + + uint32_t addressing_mode; /* Specifies if 7-bit or 10-bit addressing + * mode is selected. + * This parameter can be a value of @ref + * I2C_ADDRESSING_MODE. + */ + + uint32_t dual_address_mode; /* Specifies if dual addressing mode is + * selected. + * This parameter can be a value of @ref + * I2C_DUAL_ADDRESSING_MODE. + */ + + uint32_t own_address2; /* Specifies the second device own address + * if dual addressing mode is selected. + * This parameter can be a 7-bit address. + */ + + uint32_t own_address2_masks; /* Specifies the acknowledge mask address + * second device own address if dual + * addressing mode is selected. + * This parameter can be a value of @ref + * I2C_OWN_ADDRESS2_MASKS. + */ + + uint32_t general_call_mode; /* Specifies if general call mode is + * selected. + * This parameter can be a value of @ref + * I2C_GENERAL_CALL_ADDRESSING_MODE. + */ + + uint32_t no_stretch_mode; /* Specifies if nostretch mode is + * selected. + * This parameter can be a value of @ref + * I2C_NOSTRETCH_MODE. + */ + +}; + +enum i2c_state_e { + I2C_STATE_RESET = 0x00U, /* Peripheral is not yet + * initialized. + */ + I2C_STATE_READY = 0x20U, /* Peripheral Initialized + * and ready for use. + */ + I2C_STATE_BUSY = 0x24U, /* An internal process is + * ongoing. + */ + I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission process + * is ongoing. + */ + I2C_STATE_BUSY_RX = 0x22U, /* Data Reception process + * is ongoing. + */ + I2C_STATE_LISTEN = 0x28U, /* Address Listen Mode is + * ongoing. + */ + I2C_STATE_BUSY_TX_LISTEN = 0x29U, /* Address Listen Mode + * and Data Transmission + * process is ongoing. + */ + I2C_STATE_BUSY_RX_LISTEN = 0x2AU, /* Address Listen Mode + * and Data Reception + * process is ongoing. + */ + I2C_STATE_ABORT = 0x60U, /* Abort user request ongoing. */ + I2C_STATE_TIMEOUT = 0xA0U, /* Timeout state. */ + I2C_STATE_ERROR = 0xE0U /* Error. */ + +}; + +enum i2c_mode_e { + I2C_MODE_NONE = 0x00U, /* No I2C communication on going. */ + I2C_MODE_MASTER = 0x10U, /* I2C communication is in Master Mode. */ + I2C_MODE_SLAVE = 0x20U, /* I2C communication is in Slave Mode. */ + I2C_MODE_MEM = 0x40U /* I2C communication is in Memory Mode. */ + +}; + +#define I2C_ERROR_NONE 0x00000000U /* No error */ +#define I2C_ERROR_BERR 0x00000001U /* BERR error */ +#define I2C_ERROR_ARLO 0x00000002U /* ARLO error */ +#define I2C_ERROR_AF 0x00000004U /* ACKF error */ +#define I2C_ERROR_OVR 0x00000008U /* OVR error */ +#define I2C_ERROR_DMA 0x00000010U /* DMA transfer error */ +#define I2C_ERROR_TIMEOUT 0x00000020U /* Timeout error */ +#define I2C_ERROR_SIZE 0x00000040U /* Size Management error */ + +struct i2c_handle_s { + uint32_t i2c_base_addr; /* Registers base address */ + + struct stm32_i2c_init_s i2c_init; /* Communication parameters */ + + uint8_t *p_buff; /* Pointer to transfer buffer */ + + uint16_t xfer_size; /* Transfer size */ + + uint16_t xfer_count; /* Transfer counter */ + + uint32_t prev_state; /* Communication previous + * state + */ + + uint8_t lock; /* Locking object */ + + enum i2c_state_e i2c_state; /* Communication state */ + + enum i2c_mode_e i2c_mode; /* Communication mode */ + + uint32_t i2c_err; /* Error code */ +}; + +#define I2C_ADDRESSINGMODE_7BIT 0x00000001U +#define I2C_ADDRESSINGMODE_10BIT 0x00000002U + +#define I2C_DUALADDRESS_DISABLE 0x00000000U +#define I2C_DUALADDRESS_ENABLE I2C_OAR2_OA2EN + +#define I2C_GENERALCALL_DISABLE 0x00000000U +#define I2C_GENERALCALL_ENABLE I2C_CR1_GCEN + +#define I2C_NOSTRETCH_DISABLE 0x00000000U +#define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH + +#define I2C_MEMADD_SIZE_8BIT 0x00000001U +#define I2C_MEMADD_SIZE_16BIT 0x00000002U + +#define I2C_RELOAD_MODE I2C_CR2_RELOAD +#define I2C_AUTOEND_MODE I2C_CR2_AUTOEND +#define I2C_SOFTEND_MODE 0x00000000U + +#define I2C_NO_STARTSTOP 0x00000000U +#define I2C_GENERATE_STOP (BIT(31) | I2C_CR2_STOP) +#define I2C_GENERATE_START_READ (BIT(31) | I2C_CR2_START | \ + I2C_CR2_RD_WRN) +#define I2C_GENERATE_START_WRITE (BIT(31) | I2C_CR2_START) + +#define I2C_FLAG_TXE I2C_ISR_TXE +#define I2C_FLAG_TXIS I2C_ISR_TXIS +#define I2C_FLAG_RXNE I2C_ISR_RXNE +#define I2C_FLAG_ADDR I2C_ISR_ADDR +#define I2C_FLAG_AF I2C_ISR_NACKF +#define I2C_FLAG_STOPF I2C_ISR_STOPF +#define I2C_FLAG_TC I2C_ISR_TC +#define I2C_FLAG_TCR I2C_ISR_TCR +#define I2C_FLAG_BERR I2C_ISR_BERR +#define I2C_FLAG_ARLO I2C_ISR_ARLO +#define I2C_FLAG_OVR I2C_ISR_OVR +#define I2C_FLAG_PECERR I2C_ISR_PECERR +#define I2C_FLAG_TIMEOUT I2C_ISR_TIMEOUT +#define I2C_FLAG_ALERT I2C_ISR_ALERT +#define I2C_FLAG_BUSY I2C_ISR_BUSY +#define I2C_FLAG_DIR I2C_ISR_DIR + +#define I2C_RESET_CR2 (I2C_CR2_SADD | I2C_CR2_HEAD10R | \ + I2C_CR2_NBYTES | I2C_CR2_RELOAD | \ + I2C_CR2_RD_WRN) + +#define I2C_ANALOGFILTER_ENABLE ((uint32_t)0x00000000U) +#define I2C_ANALOGFILTER_DISABLE I2C_CR1_ANFOFF + +int stm32_i2c_init(struct i2c_handle_s *hi2c); + +int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout); +int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint16_t mem_addr, uint16_t mem_add_size, + uint8_t *p_data, uint16_t size, uint32_t timeout); +int stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr, + uint32_t trials, uint32_t timeout); + +int stm32_i2c_config_analog_filter(struct i2c_handle_s *hi2c, + uint32_t analog_filter); + +#endif /* __STM32MP1_I2C_H */ diff --git a/include/drivers/st/stm32mp1_pmic.h b/include/drivers/st/stm32mp1_pmic.h new file mode 100644 index 0000000..5d94b40 --- /dev/null +++ b/include/drivers/st/stm32mp1_pmic.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __STM32MP1_PMIC_H__ +#define __STM32MP1_PMIC_H__ + +#include + +bool dt_check_pmic(void); +int dt_pmic_enable_boot_on_regulators(void); +void initialize_pmic_i2c(void); +void initialize_pmic(void); +int pmic_ddr_power_init(enum ddr_type ddr_type); + +#endif /* __STM32MP1_PMIC_H__ */ diff --git a/include/drivers/st/stpmu1.h b/include/drivers/st/stpmu1.h new file mode 100644 index 0000000..1b93ab2 --- /dev/null +++ b/include/drivers/st/stpmu1.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef __STPMU1_H__ +#define __STPMU1_H__ + +#include +#include + +#define TURN_ON_REG 0x1U +#define TURN_OFF_REG 0x2U +#define ICC_LDO_TURN_OFF_REG 0x3U +#define ICC_BUCK_TURN_OFF_REG 0x4U +#define RESET_STATUS_REG 0x5U +#define VERSION_STATUS_REG 0x6U +#define MAIN_CONTROL_REG 0x10U +#define PADS_PULL_REG 0x11U +#define BUCK_PULL_DOWN_REG 0x12U +#define LDO14_PULL_DOWN_REG 0x13U +#define LDO56_PULL_DOWN_REG 0x14U +#define VIN_CONTROL_REG 0x15U +#define PONKEY_TIMER_REG 0x16U +#define MASK_RANK_BUCK_REG 0x17U +#define MASK_RESET_BUCK_REG 0x18U +#define MASK_RANK_LDO_REG 0x19U +#define MASK_RESET_LDO_REG 0x1AU +#define WATCHDOG_CONTROL_REG 0x1BU +#define WATCHDOG_TIMER_REG 0x1CU +#define BUCK_ICC_TURNOFF_REG 0x1DU +#define LDO_ICC_TURNOFF_REG 0x1EU +#define BUCK_APM_CONTROL_REG 0x1FU +#define BUCK1_CONTROL_REG 0x20U +#define BUCK2_CONTROL_REG 0x21U +#define BUCK3_CONTROL_REG 0x22U +#define BUCK4_CONTROL_REG 0x23U +#define VREF_DDR_CONTROL_REG 0x24U +#define LDO1_CONTROL_REG 0x25U +#define LDO2_CONTROL_REG 0x26U +#define LDO3_CONTROL_REG 0x27U +#define LDO4_CONTROL_REG 0x28U +#define LDO5_CONTROL_REG 0x29U +#define LDO6_CONTROL_REG 0x2AU +#define BUCK1_PWRCTRL_REG 0x30U +#define BUCK2_PWRCTRL_REG 0x31U +#define BUCK3_PWRCTRL_REG 0x32U +#define BUCK4_PWRCTRL_REG 0x33U +#define VREF_DDR_PWRCTRL_REG 0x34U +#define LDO1_PWRCTRL_REG 0x35U +#define LDO2_PWRCTRL_REG 0x36U +#define LDO3_PWRCTRL_REG 0x37U +#define LDO4_PWRCTRL_REG 0x38U +#define LDO5_PWRCTRL_REG 0x39U +#define LDO6_PWRCTRL_REG 0x3AU +#define FREQUENCY_SPREADING_REG 0x3BU +#define USB_CONTROL_REG 0x40U +#define ITLATCH1_REG 0x50U +#define ITLATCH2_REG 0x51U +#define ITLATCH3_REG 0x52U +#define ITLATCH4_REG 0x53U +#define ITSETLATCH1_REG 0x60U +#define ITSETLATCH2_REG 0x61U +#define ITSETLATCH3_REG 0x62U +#define ITSETLATCH4_REG 0x63U +#define ITCLEARLATCH1_REG 0x70U +#define ITCLEARLATCH2_REG 0x71U +#define ITCLEARLATCH3_REG 0x72U +#define ITCLEARLATCH4_REG 0x73U +#define ITMASK1_REG 0x80U +#define ITMASK2_REG 0x81U +#define ITMASK3_REG 0x82U +#define ITMASK4_REG 0x83U +#define ITSETMASK1_REG 0x90U +#define ITSETMASK2_REG 0x91U +#define ITSETMASK3_REG 0x92U +#define ITSETMASK4_REG 0x93U +#define ITCLEARMASK1_REG 0xA0U +#define ITCLEARMASK2_REG 0xA1U +#define ITCLEARMASK3_REG 0xA2U +#define ITCLEARMASK4_REG 0xA3U +#define ITSOURCE1_REG 0xB0U +#define ITSOURCE2_REG 0xB1U +#define ITSOURCE3_REG 0xB2U +#define ITSOURCE4_REG 0xB3U +#define LDO_VOLTAGE_MASK 0x7CU +#define BUCK_VOLTAGE_MASK 0xFCU +#define LDO_BUCK_VOLTAGE_SHIFT 2 +#define LDO_ENABLE_MASK 0x01U +#define BUCK_ENABLE_MASK 0x01U +#define BUCK_HPLP_ENABLE_MASK 0x02U +#define LDO_HPLP_ENABLE_MASK 0x02U +#define LDO_BUCK_HPLP_SHIFT 1 +#define LDO_BUCK_RANK_MASK 0x01U +#define LDO_BUCK_RESET_MASK 0x01U +#define LDO_BUCK_PULL_DOWN_MASK 0x03U + +/* Main PMIC Control Register (MAIN_CONTROL_REG) */ +#define ICC_EVENT_ENABLED BIT(4) +#define PWRCTRL_POLARITY_HIGH BIT(3) +#define PWRCTRL_PIN_VALID BIT(2) +#define RESTART_REQUEST_ENABLED BIT(1) +#define SOFTWARE_SWITCH_OFF_ENABLED BIT(0) + +/* Main PMIC PADS Control Register (PADS_PULL_REG) */ +#define WAKEUP_DETECTOR_DISABLED BIT(4) +#define PWRCTRL_PD_ACTIVE BIT(3) +#define PWRCTRL_PU_ACTIVE BIT(2) +#define WAKEUP_PD_ACTIVE BIT(1) +#define PONKEY_PU_ACTIVE BIT(0) + +/* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */ +#define SWIN_DETECTOR_ENABLED BIT(7) +#define SWOUT_DETECTOR_ENABLED BIT(6) +#define VINLOW_HYST_MASK 0x3 +#define VINLOW_HYST_SHIFT 4 +#define VINLOW_THRESHOLD_MASK 0x7 +#define VINLOW_THRESHOLD_SHIFT 1 +#define VINLOW_ENABLED 0x01 +#define VINLOW_CTRL_REG_MASK 0xFF + +/* USB Control Register */ +#define BOOST_OVP_DISABLED BIT(7) +#define VBUS_OTG_DETECTION_DISABLED BIT(6) +#define OCP_LIMIT_HIGH BIT(3) +#define SWIN_SWOUT_ENABLED BIT(2) +#define USBSW_OTG_SWITCH_ENABLED BIT(1) + +int stpmu1_switch_off(void); +int stpmu1_register_read(uint8_t register_id, uint8_t *value); +int stpmu1_register_write(uint8_t register_id, uint8_t value); +int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask); +int stpmu1_regulator_enable(const char *name); +int stpmu1_regulator_disable(const char *name); +uint8_t stpmu1_is_regulator_enabled(const char *name); +int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts); +void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr); + +#endif /* __STPMU1_H__ */ diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c index 97abdc4..84484e1 100644 --- a/plat/st/stm32mp1/bl2_plat_setup.c +++ b/plat/st/stm32mp1/bl2_plat_setup.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,10 @@ void bl2_platform_setup(void) { + if (dt_check_pmic()) { + initialize_pmic(); + } + INFO("BL2 runs SP_MIN setup\n"); } diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk index 9c97f72..bd74d0f 100644 --- a/plat/st/stm32mp1/platform.mk +++ b/plat/st/stm32mp1/platform.mk @@ -42,6 +42,9 @@ drivers/st/clk/stm32mp1_clk.c \ drivers/st/clk/stm32mp1_clkfunc.c \ drivers/st/gpio/stm32_gpio.c \ + drivers/st/pmic/stm32_i2c.c \ + drivers/st/pmic/stm32mp1_pmic.c \ + drivers/st/pmic/stpmu1.c \ drivers/st/reset/stm32mp1_reset.c \ plat/st/stm32mp1/stm32mp1_context.c \ plat/st/stm32mp1/stm32mp1_dt.c \