/****************************************************************************** * * Copyright 2013 Altera Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************/ #include "alt_i2c.h" #include "alt_reset_manager.h" #include ///// // NOTE: To enable debugging output, delete the next line and uncomment the // line after. #define dprintf(...) // #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) ///// #define MIN(a, b) ((a) > (b) ? (b) : (a)) ///// // Timeout for reset manager #define ALT_I2C_RESET_TMO_INIT 8192 // Timeout for disable device #define ALT_I2C_MAX_T_POLL_COUNT 8192 // Timeout for waiting interrupt #define ALT_I2C_TMO_WAITER 2500000 // Min frequency during standard speed #define ALT_I2C_SS_MIN_SPEED 8000 // Max frequency during standard speed #define ALT_I2C_SS_MAX_SPEED 100000 // Min frequency during fast speed #define ALT_I2C_FS_MIN_SPEED 100000 // Max frequency during fast speed #define ALT_I2C_FS_MAX_SPEED 400000 // Default spike suppression limit during standard speed #define ALT_I2C_SS_DEFAULT_SPKLEN 11 // Default spike suppression limit during fast speed #define ALT_I2C_FS_DEFAULT_SPKLEN 4 // Diff between SCL LCNT and SCL HCNT #define ALT_I2C_DIFF_LCNT_HCNT 70 // Reserved address from 0x00 to 0x07 #define ALT_I2C_SLV_RESERVE_ADDR_S_1 0x00 #define ALT_I2C_SLV_RESERVE_ADDR_F_1 0x07 // Reserved address from 0x78 to 0x7F #define ALT_I2C_SLV_RESERVE_ADDR_S_2 0x78 #define ALT_I2C_SLV_RESERVE_ADDR_F_2 0x7F static ALT_STATUS_CODE alt_i2c_is_enabled_helper(ALT_I2C_DEV_t * i2c_dev); // // Check whether i2c space is correct. // static ALT_STATUS_CODE alt_i2c_checking(ALT_I2C_DEV_t * i2c_dev) { if ( (i2c_dev->location != (void *)ALT_I2C_I2C0) && (i2c_dev->location != (void *)ALT_I2C_I2C1) && (i2c_dev->location != (void *)ALT_I2C_I2C2) && (i2c_dev->location != (void *)ALT_I2C_I2C3)) { // Incorrect device return ALT_E_FALSE; } // Reset i2c module return ALT_E_TRUE; } static ALT_STATUS_CODE alt_i2c_rstmgr_set(ALT_I2C_DEV_t * i2c_dev) { uint32_t rst_mask = ALT_RSTMGR_PERMODRST_I2C0_SET_MSK; // Assert the appropriate I2C module reset signal via the Reset Manager Peripheral Reset register. switch ((ALT_I2C_CTLR_t)i2c_dev->location) { case ALT_I2C_I2C0: rst_mask = ALT_RSTMGR_PERMODRST_I2C0_SET_MSK; break; case ALT_I2C_I2C1: rst_mask = ALT_RSTMGR_PERMODRST_I2C1_SET_MSK; break; case ALT_I2C_I2C2: rst_mask = ALT_RSTMGR_PERMODRST_I2C2_SET_MSK; break; case ALT_I2C_I2C3: rst_mask = ALT_RSTMGR_PERMODRST_I2C3_SET_MSK; break; default: return ALT_E_BAD_ARG; } alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, rst_mask); return ALT_E_SUCCESS; } // // Reset i2c module by reset manager // static ALT_STATUS_CODE alt_i2c_rstmgr_strobe(ALT_I2C_DEV_t * i2c_dev) { uint32_t rst_mask = ALT_RSTMGR_PERMODRST_I2C0_SET_MSK; // Assert the appropriate I2C module reset signal via the Reset Manager Peripheral Reset register. switch ((ALT_I2C_CTLR_t)i2c_dev->location) { case ALT_I2C_I2C0: rst_mask = ALT_RSTMGR_PERMODRST_I2C0_SET_MSK; break; case ALT_I2C_I2C1: rst_mask = ALT_RSTMGR_PERMODRST_I2C1_SET_MSK; break; case ALT_I2C_I2C2: rst_mask = ALT_RSTMGR_PERMODRST_I2C2_SET_MSK; break; case ALT_I2C_I2C3: rst_mask = ALT_RSTMGR_PERMODRST_I2C3_SET_MSK; break; default: return ALT_E_BAD_ARG; } alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, rst_mask); volatile uint32_t timeout = ALT_I2C_RESET_TMO_INIT; // Wait while i2c modure is reseting while (--timeout) ; // Deassert the appropriate I2C module reset signal via the Reset Manager Peripheral Reset register. alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, rst_mask); return ALT_E_SUCCESS; } // // Initialize the specified I2C controller instance for use and return a device // handle referencing it. // ALT_STATUS_CODE alt_i2c_init(const ALT_I2C_CTLR_t i2c, ALT_I2C_DEV_t * i2c_dev) { // Save i2c start address to the instance i2c_dev->location = (void *)i2c; if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_clk_is_enabled(ALT_CLK_L4_SP) != ALT_E_TRUE) { return ALT_E_BAD_CLK; } ///// ALT_STATUS_CODE status = ALT_E_SUCCESS; if (status == ALT_E_SUCCESS) { status = alt_clk_freq_get(ALT_CLK_L4_SP, &i2c_dev->clock_freq); } // Reset i2c module if (status == ALT_E_SUCCESS) { status = alt_i2c_reset(i2c_dev); } return status; } // // Reset i2c module // ALT_STATUS_CODE alt_i2c_reset(ALT_I2C_DEV_t * i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } ALT_STATUS_CODE status = ALT_E_SUCCESS; bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } // Reset i2c module by reset manager alt_i2c_rstmgr_strobe(i2c_dev); // Set optimal parameters for all i2c devices on the bus ALT_I2C_MASTER_CONFIG_t cfg; cfg.addr_mode = ALT_I2C_ADDR_MODE_7_BIT; cfg.speed_mode = ALT_I2C_SPEED_STANDARD; cfg.fs_spklen = ALT_I2C_SS_DEFAULT_SPKLEN; cfg.restart_enable = ALT_E_TRUE; cfg.ss_scl_lcnt = cfg.fs_scl_lcnt = 0x2FB; cfg.ss_scl_hcnt = cfg.fs_scl_hcnt = 0x341; alt_i2c_master_config_set(i2c_dev, &cfg); // Active master mode alt_i2c_op_mode_set(i2c_dev, ALT_I2C_MODE_MASTER); // Reset the last target address cache. i2c_dev->last_target = 0xffffffff; // Clear interrupts mask and clear interrupt status. // Interrupts are unmasked by default. alt_i2c_int_disable(i2c_dev, ALT_I2C_STATUS_INT_ALL); alt_i2c_int_clear(i2c_dev, ALT_I2C_STATUS_INT_ALL); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Uninitialize the I2C controller referenced by the i2c_dev handle. // ALT_STATUS_CODE alt_i2c_uninit(ALT_I2C_DEV_t * i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } ALT_STATUS_CODE status = ALT_E_SUCCESS; // Disable i2c controller if (status == ALT_E_SUCCESS) { status = alt_i2c_disable(i2c_dev); } // Reset i2c module by reset manager if (status == ALT_E_SUCCESS) { status = alt_i2c_rstmgr_set(i2c_dev); } return status; } // // Enables the I2C controller. // ALT_STATUS_CODE alt_i2c_enable(ALT_I2C_DEV_t * i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } // Enable DMA by default. alt_write_word(ALT_I2C_DMA_CR_ADDR(i2c_dev->location), ALT_I2C_DMA_CR_TDMAE_SET_MSK | ALT_I2C_DMA_CR_RDMAE_SET_MSK); alt_setbits_word(ALT_I2C_EN_ADDR(i2c_dev->location), ALT_I2C_EN_EN_SET_MSK); return ALT_E_SUCCESS; } // // Disables the I2C controller // ALT_STATUS_CODE alt_i2c_disable(ALT_I2C_DEV_t * i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } // If i2c controller is enabled, return with sucess if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_SUCCESS; } // Else clear enable bit of i2c_enable register alt_clrbits_word(ALT_I2C_EN_ADDR(i2c_dev->location), ALT_I2C_EN_EN_SET_MSK); uint32_t timeout = ALT_I2C_MAX_T_POLL_COUNT; // Wait to complete all transfer operations or timeout while (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE) { // If controller still are active, return timeout error if (--timeout == 0) { return ALT_E_TMO; } } // Clear interrupt status alt_i2c_int_clear(i2c_dev, ALT_I2C_STATUS_INT_ALL); return ALT_E_SUCCESS; } // // Check whether i2c controller is enable // static ALT_STATUS_CODE alt_i2c_is_enabled_helper(ALT_I2C_DEV_t * i2c_dev) { if (ALT_I2C_EN_STAT_IC_EN_GET(alt_read_word(ALT_I2C_EN_STAT_ADDR(i2c_dev->location)))) { return ALT_E_TRUE; } else { return ALT_E_FALSE; } } ALT_STATUS_CODE alt_i2c_is_enabled(ALT_I2C_DEV_t * i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } return alt_i2c_is_enabled_helper(i2c_dev); } // // Get config parameters from appropriate registers for master mode. // ALT_STATUS_CODE alt_i2c_master_config_get(ALT_I2C_DEV_t *i2c_dev, ALT_I2C_MASTER_CONFIG_t* cfg) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } uint32_t cfg_register = alt_read_word(ALT_I2C_CON_ADDR(i2c_dev->location)); uint32_t tar_register = alt_read_word(ALT_I2C_TAR_ADDR(i2c_dev->location)); uint32_t spkl_register = alt_read_word(ALT_I2C_FS_SPKLEN_ADDR(i2c_dev->location)); cfg->speed_mode = (ALT_I2C_SPEED_t)ALT_I2C_CON_SPEED_GET(cfg_register); cfg->fs_spklen = ALT_I2C_FS_SPKLEN_SPKLEN_GET(spkl_register); cfg->restart_enable = ALT_I2C_CON_IC_RESTART_EN_GET(cfg_register); cfg->addr_mode = (ALT_I2C_ADDR_MODE_t)ALT_I2C_TAR_IC_10BITADDR_MST_GET(tar_register); cfg->ss_scl_lcnt = alt_read_word(ALT_I2C_SS_SCL_LCNT_ADDR(i2c_dev->location)); cfg->ss_scl_hcnt = alt_read_word(ALT_I2C_SS_SCL_HCNT_ADDR(i2c_dev->location)); cfg->fs_scl_lcnt = alt_read_word(ALT_I2C_FS_SCL_LCNT_ADDR(i2c_dev->location)); cfg->fs_scl_hcnt = alt_read_word(ALT_I2C_FS_SCL_HCNT_ADDR(i2c_dev->location)); return ALT_E_SUCCESS; } // // Set config parameters to appropriate registers for master mode. // ALT_STATUS_CODE alt_i2c_master_config_set(ALT_I2C_DEV_t *i2c_dev, const ALT_I2C_MASTER_CONFIG_t* cfg) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if ( (cfg->speed_mode != ALT_I2C_SPEED_STANDARD) && (cfg->speed_mode != ALT_I2C_SPEED_FAST)) { return ALT_E_BAD_ARG; } if ( (cfg->addr_mode != ALT_I2C_ADDR_MODE_7_BIT) && (cfg->addr_mode != ALT_I2C_ADDR_MODE_10_BIT)) { return ALT_E_ARG_RANGE; } ALT_STATUS_CODE status = ALT_E_SUCCESS; bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } // Set config parameters to appropriate registers alt_replbits_word(ALT_I2C_CON_ADDR(i2c_dev->location), ALT_I2C_CON_SPEED_SET_MSK | ALT_I2C_CON_IC_RESTART_EN_SET_MSK, ALT_I2C_CON_SPEED_SET(cfg->speed_mode) | ALT_I2C_CON_IC_RESTART_EN_SET(cfg->restart_enable)); alt_replbits_word(ALT_I2C_TAR_ADDR(i2c_dev->location), ALT_I2C_TAR_IC_10BITADDR_MST_SET_MSK, ALT_I2C_TAR_IC_10BITADDR_MST_SET(cfg->addr_mode)); alt_replbits_word(ALT_I2C_FS_SPKLEN_ADDR(i2c_dev->location), ALT_I2C_FS_SPKLEN_SPKLEN_SET_MSK, ALT_I2C_FS_SPKLEN_SPKLEN_SET(cfg->fs_spklen)); alt_replbits_word(ALT_I2C_SS_SCL_LCNT_ADDR(i2c_dev->location), ALT_I2C_SS_SCL_LCNT_IC_SS_SCL_LCNT_SET_MSK, ALT_I2C_SS_SCL_LCNT_IC_SS_SCL_LCNT_SET(cfg->ss_scl_lcnt)); alt_replbits_word(ALT_I2C_SS_SCL_HCNT_ADDR(i2c_dev->location), ALT_I2C_SS_SCL_HCNT_IC_SS_SCL_HCNT_SET_MSK, ALT_I2C_SS_SCL_HCNT_IC_SS_SCL_HCNT_SET(cfg->ss_scl_hcnt)); alt_replbits_word(ALT_I2C_FS_SCL_LCNT_ADDR(i2c_dev->location), ALT_I2C_FS_SCL_LCNT_IC_FS_SCL_LCNT_SET_MSK, ALT_I2C_FS_SCL_LCNT_IC_FS_SCL_LCNT_SET(cfg->fs_scl_lcnt)); alt_replbits_word(ALT_I2C_FS_SCL_HCNT_ADDR(i2c_dev->location), ALT_I2C_FS_SCL_HCNT_IC_FS_SCL_HCNT_SET_MSK, ALT_I2C_FS_SCL_HCNT_IC_FS_SCL_HCNT_SET(cfg->fs_scl_hcnt)); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Return bus speed by configuration of i2c controller for master mode. // ALT_STATUS_CODE alt_i2c_master_config_speed_get(ALT_I2C_DEV_t *i2c_dev, const ALT_I2C_MASTER_CONFIG_t * cfg, uint32_t * speed_in_hz) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } uint32_t scl_lcnt = (cfg->speed_mode == ALT_I2C_SPEED_STANDARD) ? cfg->ss_scl_lcnt : cfg->fs_scl_lcnt; if (scl_lcnt == 0) { return ALT_E_BAD_ARG; } *speed_in_hz = i2c_dev->clock_freq / (scl_lcnt << 1); return ALT_E_SUCCESS; } // // Fill struct with configuration of i2c controller for master mode by bus speed // ALT_STATUS_CODE alt_i2c_master_config_speed_set(ALT_I2C_DEV_t *i2c_dev, ALT_I2C_MASTER_CONFIG_t * cfg, uint32_t speed_in_hz) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } // If speed is not standard or fast return range error if ((speed_in_hz > ALT_I2C_FS_MAX_SPEED) || (speed_in_hz < ALT_I2C_SS_MIN_SPEED)) { return ALT_E_ARG_RANGE; } if (speed_in_hz > ALT_I2C_FS_MIN_SPEED) { cfg->speed_mode = ALT_I2C_SPEED_FAST; cfg->fs_spklen = ALT_I2C_FS_DEFAULT_SPKLEN; } else { cfg->speed_mode = ALT_I2C_SPEED_STANDARD; cfg->fs_spklen = ALT_I2C_SS_DEFAULT_SPKLEN; } // = / 2 * uint32_t scl_lcnt = i2c_dev->clock_freq / (speed_in_hz << 1); cfg->ss_scl_lcnt = cfg->fs_scl_lcnt = scl_lcnt; // hcount = + 70 cfg->ss_scl_hcnt = cfg->fs_scl_hcnt = scl_lcnt - ALT_I2C_DIFF_LCNT_HCNT; // lcount = / 2 * return ALT_E_SUCCESS; } // // Get config parameters from appropriate registers for slave mode. // ALT_STATUS_CODE alt_i2c_slave_config_get(ALT_I2C_DEV_t *i2c_dev, ALT_I2C_SLAVE_CONFIG_t* cfg) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } uint32_t cfg_register = alt_read_word(ALT_I2C_CON_ADDR(i2c_dev->location)); uint32_t sar_register = alt_read_word(ALT_I2C_SAR_ADDR(i2c_dev->location)); uint32_t nack_register = alt_read_word(ALT_I2C_SLV_DATA_NACK_ONLY_ADDR(i2c_dev->location)); cfg->addr_mode = (ALT_I2C_ADDR_MODE_t)ALT_I2C_CON_IC_10BITADDR_SLV_GET(cfg_register); cfg->addr = ALT_I2C_SAR_IC_SAR_GET(sar_register); cfg->nack_enable = ALT_I2C_SLV_DATA_NACK_ONLY_NACK_GET(nack_register); return ALT_E_SUCCESS; } // // Set config parameters to appropriate registers for slave mode. // ALT_STATUS_CODE alt_i2c_slave_config_set(ALT_I2C_DEV_t *i2c_dev, const ALT_I2C_SLAVE_CONFIG_t* cfg) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if ( (cfg->addr_mode != ALT_I2C_ADDR_MODE_7_BIT) && (cfg->addr_mode != ALT_I2C_ADDR_MODE_10_BIT)) { return ALT_E_BAD_ARG; } if ( (cfg->addr > ALT_I2C_SAR_IC_SAR_SET_MSK) || (cfg->addr < ALT_I2C_SLV_RESERVE_ADDR_F_1) || ((cfg->addr > ALT_I2C_SLV_RESERVE_ADDR_S_2) && (cfg->addr < ALT_I2C_SLV_RESERVE_ADDR_F_2)) ) { return ALT_E_ARG_RANGE; } ALT_STATUS_CODE status = ALT_E_SUCCESS; bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } alt_replbits_word(ALT_I2C_CON_ADDR(i2c_dev->location), ALT_I2C_CON_IC_10BITADDR_SLV_SET_MSK, ALT_I2C_CON_IC_10BITADDR_SLV_SET(cfg->addr_mode)); alt_replbits_word(ALT_I2C_SAR_ADDR(i2c_dev->location), ALT_I2C_SAR_IC_SAR_SET_MSK, ALT_I2C_SAR_IC_SAR_SET(cfg->addr)); alt_replbits_word(ALT_I2C_SLV_DATA_NACK_ONLY_ADDR(i2c_dev->location), ALT_I2C_SLV_DATA_NACK_ONLY_NACK_SET_MSK, ALT_I2C_SLV_DATA_NACK_ONLY_NACK_SET(cfg->nack_enable)); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Get hold time (use during slave mode) // ALT_STATUS_CODE alt_i2c_sda_hold_time_get(ALT_I2C_DEV_t *i2c_dev, uint16_t *hold_time) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } uint32_t sda_register = alt_read_word(ALT_I2C_SDA_HOLD_ADDR(i2c_dev->location)); *hold_time = ALT_I2C_SDA_HOLD_IC_SDA_HOLD_GET(sda_register); return ALT_E_SUCCESS; } // // Set hold time (use during slave mode) // ALT_STATUS_CODE alt_i2c_sda_hold_time_set(ALT_I2C_DEV_t *i2c_dev, const uint16_t hold_time) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } ALT_STATUS_CODE status = ALT_E_SUCCESS; bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } alt_replbits_word(ALT_I2C_SDA_HOLD_ADDR(i2c_dev->location), ALT_I2C_SDA_HOLD_IC_SDA_HOLD_SET_MSK, ALT_I2C_SDA_HOLD_IC_SDA_HOLD_SET(hold_time)); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Gets the current operational mode of the I2C controller. // ALT_STATUS_CODE alt_i2c_op_mode_get(ALT_I2C_DEV_t *i2c_dev, ALT_I2C_MODE_t* mode) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } uint32_t cfg_register = alt_read_word(ALT_I2C_CON_ADDR(i2c_dev->location)); uint32_t mst_mod_stat = ALT_I2C_CON_MST_MOD_GET(cfg_register); uint32_t slv_mod_stat = ALT_I2C_CON_IC_SLV_DIS_GET(cfg_register); // Return error if master and slave modes enable or disable at the same time if ( (mst_mod_stat == ALT_I2C_CON_MST_MOD_E_EN && slv_mod_stat == ALT_I2C_CON_IC_SLV_DIS_E_EN) || (mst_mod_stat == ALT_I2C_CON_MST_MOD_E_DIS && slv_mod_stat == ALT_I2C_CON_IC_SLV_DIS_E_DIS)) { return ALT_E_ERROR; } *mode = (ALT_I2C_MODE_t)mst_mod_stat; return ALT_E_SUCCESS; } // // Sets the operational mode of the I2C controller. // ALT_STATUS_CODE alt_i2c_op_mode_set(ALT_I2C_DEV_t *i2c_dev, const ALT_I2C_MODE_t mode) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if ( (mode != ALT_I2C_MODE_MASTER) && (mode != ALT_I2C_MODE_SLAVE)) { return ALT_E_ARG_RANGE; } ALT_STATUS_CODE status = ALT_E_SUCCESS; bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } if (mode == ALT_I2C_MODE_MASTER) { // Enable master, disable slave alt_replbits_word(ALT_I2C_CON_ADDR(i2c_dev->location), ALT_I2C_CON_IC_SLV_DIS_SET_MSK | ALT_I2C_CON_MST_MOD_SET_MSK, ALT_I2C_CON_IC_SLV_DIS_SET(ALT_I2C_CON_IC_SLV_DIS_E_DIS) | ALT_I2C_CON_MST_MOD_SET(ALT_I2C_CON_MST_MOD_E_EN)); } else if (mode == ALT_I2C_MODE_SLAVE) { // Enable slave, disable master alt_replbits_word(ALT_I2C_CON_ADDR(i2c_dev->location), ALT_I2C_CON_IC_SLV_DIS_SET_MSK | ALT_I2C_CON_MST_MOD_SET_MSK, ALT_I2C_CON_IC_SLV_DIS_SET(ALT_I2C_CON_IC_SLV_DIS_E_EN) | ALT_I2C_CON_MST_MOD_SET(ALT_I2C_CON_MST_MOD_E_DIS)); } if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Returns ALT_E_TRUE if the I2C controller is busy // ALT_STATUS_CODE alt_i2c_is_busy(ALT_I2C_DEV_t *i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if ( ALT_I2C_STAT_ACTIVITY_GET(alt_read_word(ALT_I2C_STAT_ADDR(i2c_dev->location)))) { return ALT_E_TRUE; } else { return ALT_E_FALSE; } } // // This function reads a single data byte from the receive FIFO. // ALT_STATUS_CODE alt_i2c_read(ALT_I2C_DEV_t *i2c_dev, uint8_t *value) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } *value = (uint8_t)(ALT_I2C_DATA_CMD_DAT_GET(alt_read_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location)))); return ALT_E_SUCCESS; } // // This function writes a single data byte to the transmit FIFO. // ALT_STATUS_CODE alt_i2c_write(ALT_I2C_DEV_t *i2c_dev, const uint8_t value) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_DAT_SET(value)); return ALT_E_SUCCESS; } // // This function acts in the role of a slave-receiver by receiving a single data // byte from the I2C bus in response to a write command from the master. // ALT_STATUS_CODE alt_i2c_slave_receive(ALT_I2C_DEV_t * i2c_dev, uint8_t * data) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } // alt_i2c_read(). *data = (uint8_t)(ALT_I2C_DATA_CMD_DAT_GET(alt_read_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location)))); return ALT_E_SUCCESS; } // // This function acts in the role of a slave-transmitter by transmitting a single // data byte to the I2C bus in response to a read request from the master. // ALT_STATUS_CODE alt_i2c_slave_transmit(ALT_I2C_DEV_t *i2c_dev, const uint8_t data) { // Send bulk of data with one value return alt_i2c_slave_bulk_transmit(i2c_dev, &data, 1); } // // This function acts in the role of a slave-transmitter by transmitting data in // bulk to the I2C bus in response to a series of read requests from a master. // ALT_STATUS_CODE alt_i2c_slave_bulk_transmit(ALT_I2C_DEV_t *i2c_dev, const void * data, const size_t size) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } const char * buffer = data; for (size_t i = 0; i < size; ++i) { alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_DAT_SET(*buffer) | ALT_I2C_DATA_CMD_STOP_SET(false) | ALT_I2C_DATA_CMD_RESTART_SET(false)); ++buffer; } return ALT_E_SUCCESS; } ALT_STATUS_CODE alt_i2c_master_target_get(ALT_I2C_DEV_t * i2c_dev, uint32_t * target_addr) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *target_addr = i2c_dev->last_target; return ALT_E_SUCCESS; } ALT_STATUS_CODE alt_i2c_master_target_set(ALT_I2C_DEV_t * i2c_dev, uint32_t target_addr) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } ALT_STATUS_CODE status = ALT_E_SUCCESS; // Wait until the TX FIFO flushes. This is needed because TAR can only be // updated under specific conditions. if (target_addr != i2c_dev->last_target) { uint32_t timeout = 10000; while (alt_i2c_tx_fifo_is_empty(i2c_dev) == ALT_E_FALSE) { if (--timeout == 0) { status = ALT_E_TMO; break; } } // Update target address if (status == ALT_E_SUCCESS) { alt_replbits_word(ALT_I2C_TAR_ADDR(i2c_dev->location), ALT_I2C_TAR_IC_TAR_SET_MSK, ALT_I2C_TAR_IC_TAR_SET(target_addr)); i2c_dev->last_target = target_addr; } } return status; } // // Write bulk of data or read requests to tx fifo // static ALT_STATUS_CODE alt_i2c_master_transmit_helper(ALT_I2C_DEV_t * i2c_dev, const uint8_t * buffer, size_t size, bool issue_restart, bool issue_stop) { ALT_STATUS_CODE status = ALT_E_SUCCESS; // If the rested size is 1, the restart and stop may need to be sent in the // same frame. if (size == 1) { if (status == ALT_E_SUCCESS) { status = alt_i2c_issue_write(i2c_dev, *buffer, issue_restart, issue_stop); ++buffer; --size; } } else { // First byte if (status == ALT_E_SUCCESS) { status = alt_i2c_issue_write(i2c_dev, *buffer, issue_restart, false); ++buffer; --size; } ///// // Middle byte(s) if (status == ALT_E_SUCCESS) { uint32_t timeout = size * 10000; while (size > 1) { uint32_t level = 0; status = alt_i2c_tx_fifo_level_get(i2c_dev, &level); if (status != ALT_E_SUCCESS) { break; } uint32_t space = ALT_I2C_TX_FIFO_NUM_ENTRIES - level; if (space == 0) { if (--timeout == 0) { status = ALT_E_TMO; break; } continue; } // Subtract 1 because the last byte may need to issue_stop space = MIN(space, size - 1); for (uint32_t i = 0; i < space; ++i) { alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_DAT_SET(*buffer) | ALT_I2C_DATA_CMD_STOP_SET(false) | ALT_I2C_DATA_CMD_RESTART_SET(false)); ++buffer; } size -= space; } } ///// // Last byte if (status == ALT_E_SUCCESS) { status = alt_i2c_issue_write(i2c_dev, *buffer, false, issue_stop); ++buffer; --size; } } return status; } // // This function acts in the role of a master-transmitter by issuing a write // command and transmitting data to the I2C bus. // ALT_STATUS_CODE alt_i2c_master_transmit(ALT_I2C_DEV_t *i2c_dev, const void * data, const size_t size, const bool issue_restart, const bool issue_stop) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } if (size == 0) { return ALT_E_SUCCESS; } ALT_STATUS_CODE status = ALT_E_SUCCESS; if (status == ALT_E_SUCCESS) { status = alt_i2c_master_transmit_helper(i2c_dev, data, size, issue_restart, issue_stop); } // Need reset for set i2c bus in idle state if (status == ALT_E_TMO) { alt_i2c_reset(i2c_dev); } return status; } ALT_STATUS_CODE alt_i2c_master_receive_helper(ALT_I2C_DEV_t *i2c_dev, uint8_t * buffer, size_t size, bool issue_restart, bool issue_stop) { ALT_STATUS_CODE status = ALT_E_SUCCESS; uint32_t issue_left = size; uint32_t data_left = size; uint32_t timeout = size * 10000; // Wait for space in the TX FIFO to send the first read request. // This is needed because the issue restart need to be set. if (issue_restart == true) { if (status == ALT_E_SUCCESS) { while (alt_i2c_tx_fifo_is_full(i2c_dev) == ALT_E_TRUE) { if (--timeout == 0) { status = ALT_E_TMO; break; } } } // Now send the first request. if (status == ALT_E_SUCCESS) { alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_CMD_SET(ALT_I2C_DATA_CMD_CMD_E_RD) | ALT_I2C_DATA_CMD_STOP_SET(false) | ALT_I2C_DATA_CMD_RESTART_SET(issue_restart)); --issue_left; } } // For the rest of the data ... while (data_left > 0) { if (status != ALT_E_SUCCESS) { break; } // Top up the TX FIFO with read issues // Special consideration must be made for the last read issue, as it may be necessary to "issue_stop". if (issue_left > 0) { uint32_t level = 0; status = alt_i2c_tx_fifo_level_get(i2c_dev, &level); if (status != ALT_E_SUCCESS) { break; } uint32_t space = ALT_I2C_TX_FIFO_NUM_ENTRIES - level; if (issue_left == 1) { if (space > 0) { space = 1; alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_CMD_SET(ALT_I2C_DATA_CMD_CMD_E_RD) | ALT_I2C_DATA_CMD_STOP_SET(issue_stop) | ALT_I2C_DATA_CMD_RESTART_SET(false)); } } else { // Send up to issue_left - 1, as the last issue has special considerations. space = MIN(issue_left - 1, space); for (uint32_t i = 0; i < space; ++i) { alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_CMD_SET(ALT_I2C_DATA_CMD_CMD_E_RD) | ALT_I2C_DATA_CMD_STOP_SET(false) | ALT_I2C_DATA_CMD_RESTART_SET(false)); } } issue_left -= space; } // Read out the resulting received data as they come in. if (data_left > 0) { uint32_t level = 0; status = alt_i2c_rx_fifo_level_get(i2c_dev, &level); if (status != ALT_E_SUCCESS) { break; } if (level == 0) { if (--timeout == 0) { status = ALT_E_TMO; break; } } level = MIN(data_left, level); for (uint32_t i = 0; i < level; ++i) { // alt_i2c_read(i2c_dev, &value); *buffer = (uint8_t)(ALT_I2C_DATA_CMD_DAT_GET(alt_read_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location)))); ++buffer; } data_left -= level; } } return status; } // // This function acts in the role of a master-receiver by receiving one or more // data bytes transmitted from a slave in response to read requests issued from // this master. // ALT_STATUS_CODE alt_i2c_master_receive(ALT_I2C_DEV_t *i2c_dev, void * data, const size_t size, const bool issue_restart, const bool issue_stop) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } if (size == 0) { return ALT_E_SUCCESS; } ALT_STATUS_CODE status = ALT_E_SUCCESS; // This I2C controller requires that a read issue be performed for each byte requested. // Read issue takes space in the TX FIFO, which may asynchronously handling a previous request. if (size == 1) { uint32_t timeout = 10000; // Wait for space in the TX FIFO to send the read request. if (status == ALT_E_SUCCESS) { while (alt_i2c_tx_fifo_is_full(i2c_dev) == ALT_E_TRUE) { if (--timeout == 0) { status = ALT_E_TMO; break; } } } // Issue the read request in the TX FIFO. if (status == ALT_E_SUCCESS) { alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_CMD_SET(ALT_I2C_DATA_CMD_CMD_E_RD) | ALT_I2C_DATA_CMD_STOP_SET(issue_stop) | ALT_I2C_DATA_CMD_RESTART_SET(issue_restart)); } // Wait for data to become available in the RX FIFO. if (status == ALT_E_SUCCESS) { while (alt_i2c_rx_fifo_is_empty(i2c_dev) == ALT_E_TRUE) { if (--timeout == 0) { status = ALT_E_TMO; break; } } } // Read the RX FIFO. if (status == ALT_E_SUCCESS) { uint8_t * buffer = data; *buffer = (uint8_t)(ALT_I2C_DATA_CMD_DAT_GET(alt_read_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location)))); } } else if (size <= 64) { if (status == ALT_E_SUCCESS) { status = alt_i2c_master_receive_helper(i2c_dev, data, size, issue_restart, issue_stop); } } else { uint8_t * buffer = data; size_t size_left = size; // Send the first ALT_I2C_RX_FIFO_NUM_ENTRIES items if (status == ALT_E_SUCCESS) { status = alt_i2c_master_receive_helper(i2c_dev, buffer, ALT_I2C_RX_FIFO_NUM_ENTRIES, issue_restart, false); } buffer += ALT_I2C_RX_FIFO_NUM_ENTRIES; size_left -= ALT_I2C_RX_FIFO_NUM_ENTRIES; while (size_left > 0) { if (size_left > ALT_I2C_RX_FIFO_NUM_ENTRIES) { if (status == ALT_E_SUCCESS) { status = alt_i2c_master_receive_helper(i2c_dev, buffer, ALT_I2C_RX_FIFO_NUM_ENTRIES, false, false); } buffer += ALT_I2C_RX_FIFO_NUM_ENTRIES; size_left -= ALT_I2C_RX_FIFO_NUM_ENTRIES; } else { if (status == ALT_E_SUCCESS) { status = alt_i2c_master_receive_helper(i2c_dev, buffer, size_left, false, issue_stop); } size_left = 0; } if (status != ALT_E_SUCCESS) { break; } } } // Need reset for set i2c bus in idle state if (status == ALT_E_TMO) { alt_i2c_reset(i2c_dev); } return status; } // // This function causes the I2C controller master to send data to the bus. // ALT_STATUS_CODE alt_i2c_issue_write(ALT_I2C_DEV_t *i2c_dev, const uint8_t value, const bool issue_restart, const bool issue_stop) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } // Wait until there is a FIFO spot uint32_t timeout = 10000; while (alt_i2c_tx_fifo_is_full(i2c_dev) == ALT_E_TRUE) { if (--timeout == 0) { return ALT_E_TMO; } } alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_DAT_SET(value) | ALT_I2C_DATA_CMD_STOP_SET(issue_stop) | ALT_I2C_DATA_CMD_RESTART_SET(issue_restart)); return ALT_E_SUCCESS; } // // This function causes the I2C controller master to issue a READ request on the bus. // ALT_STATUS_CODE alt_i2c_issue_read(ALT_I2C_DEV_t *i2c_dev, const bool issue_restart, const bool issue_stop) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } // Wait until there is a FIFO spot uint32_t timeout = 10000; while (alt_i2c_tx_fifo_is_full(i2c_dev) == ALT_E_TRUE) { if (--timeout == 0) { return ALT_E_TMO; } } alt_write_word(ALT_I2C_DATA_CMD_ADDR(i2c_dev->location), ALT_I2C_DATA_CMD_CMD_SET(ALT_I2C_DATA_CMD_CMD_E_RD) | ALT_I2C_DATA_CMD_STOP_SET(issue_stop) | ALT_I2C_DATA_CMD_RESTART_SET(issue_restart)); return ALT_E_SUCCESS; } // // This function acts in the role of a master-transmitter by issuing a general // call command to all devices connected to the I2C bus. // ALT_STATUS_CODE alt_i2c_master_general_call(ALT_I2C_DEV_t *i2c_dev, const void * data, const size_t size, const bool issue_restart, const bool issue_stop) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_FALSE) { return ALT_E_ERROR; } ALT_STATUS_CODE status = ALT_E_SUCCESS; if (status == ALT_E_SUCCESS) { status = alt_i2c_master_target_set(i2c_dev, 0); } // General call is a transmit in master mode (target address are not used during it) if (status == ALT_E_SUCCESS) { status = alt_i2c_master_transmit(i2c_dev, data, size, issue_restart, issue_stop); } return status; } ///// ALT_STATUS_CODE alt_i2c_general_call_ack_disable(ALT_I2C_DEV_t *i2c_dev) { ALT_STATUS_CODE status = ALT_E_SUCCESS; if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } alt_replbits_word(ALT_I2C_TAR_ADDR(i2c_dev->location), ALT_I2C_TAR_SPECIAL_SET_MSK | ALT_I2C_TAR_GC_OR_START_SET_MSK, ALT_I2C_TAR_SPECIAL_SET(ALT_I2C_TAR_SPECIAL_E_STARTBYTE) | ALT_I2C_TAR_GC_OR_START_SET(ALT_I2C_TAR_GC_OR_START_E_STARTBYTE)); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Enables the I2C controller to respond with an ACK when it receives a General // Call address. // ALT_STATUS_CODE alt_i2c_general_call_ack_enable(ALT_I2C_DEV_t *i2c_dev) { ALT_STATUS_CODE status = ALT_E_SUCCESS; if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } alt_replbits_word(ALT_I2C_TAR_ADDR(i2c_dev->location), ALT_I2C_TAR_SPECIAL_SET_MSK | ALT_I2C_TAR_GC_OR_START_SET_MSK, ALT_I2C_TAR_SPECIAL_SET(ALT_I2C_TAR_SPECIAL_E_GENCALL) | ALT_I2C_TAR_GC_OR_START_SET(ALT_I2C_TAR_GC_OR_START_E_GENCALL)); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Returns ALT_E_TRUE if the I2C controller is enabled to respond to General Call // addresses. // ALT_STATUS_CODE alt_i2c_general_call_ack_is_enabled(ALT_I2C_DEV_t *i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } uint32_t tar_register = alt_read_word(ALT_I2C_TAR_ADDR(i2c_dev->location)); if ( (ALT_I2C_TAR_SPECIAL_GET(tar_register) == ALT_I2C_TAR_SPECIAL_E_GENCALL) && (ALT_I2C_TAR_GC_OR_START_GET(tar_register) == ALT_I2C_TAR_GC_OR_START_E_GENCALL) ) { return ALT_E_TRUE; } else { return ALT_E_FALSE; } } // // Returns the current I2C controller interrupt status conditions. // ALT_STATUS_CODE alt_i2c_int_status_get(ALT_I2C_DEV_t *i2c_dev, uint32_t *status) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *status = alt_read_word(ALT_I2C_INTR_STAT_ADDR(i2c_dev->location)); return ALT_E_SUCCESS; } // // Returns the I2C controller raw interrupt status conditions irrespective of // the interrupt status condition enablement state. // ALT_STATUS_CODE alt_i2c_int_raw_status_get(ALT_I2C_DEV_t *i2c_dev, uint32_t *status) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *status = alt_read_word(ALT_I2C_RAW_INTR_STAT_ADDR(i2c_dev->location)); return ALT_E_SUCCESS; } // // Clears the specified I2C controller interrupt status conditions identified // in the mask. // ALT_STATUS_CODE alt_i2c_int_clear(ALT_I2C_DEV_t *i2c_dev, const uint32_t mask) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (mask == ALT_I2C_STATUS_INT_ALL) { alt_read_word(ALT_I2C_CLR_INTR_ADDR(i2c_dev->location)); return ALT_E_SUCCESS; } // For different status clear different register if (mask & ALT_I2C_STATUS_RX_UNDER) { alt_read_word(ALT_I2C_CLR_RX_UNDER_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_RX_OVER) { alt_read_word(ALT_I2C_CLR_RX_OVER_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_TX_OVER) { alt_read_word(ALT_I2C_CLR_TX_OVER_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_RD_REQ) { alt_read_word(ALT_I2C_CLR_RD_REQ_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_TX_ABORT) { alt_read_word(ALT_I2C_CLR_TX_ABRT_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_RX_DONE) { alt_read_word(ALT_I2C_CLR_RX_DONE_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_ACTIVITY) { alt_read_word(ALT_I2C_CLR_ACTIVITY_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_STOP_DET) { alt_read_word(ALT_I2C_CLR_STOP_DET_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_START_DET) { alt_read_word(ALT_I2C_CLR_START_DET_ADDR(i2c_dev->location)); } if (mask & ALT_I2C_STATUS_INT_CALL) { alt_read_word(ALT_I2C_CLR_GEN_CALL_ADDR(i2c_dev->location)); } return ALT_E_SUCCESS; } // // Disable the specified I2C controller interrupt status conditions identified in // the mask. // ALT_STATUS_CODE alt_i2c_int_disable(ALT_I2C_DEV_t *i2c_dev, const uint32_t mask) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } alt_clrbits_word(ALT_I2C_INTR_MSK_ADDR(i2c_dev->location), mask); return ALT_E_SUCCESS; } // // Enable the specified I2C controller interrupt status conditions identified in // the mask. // ALT_STATUS_CODE alt_i2c_int_enable(ALT_I2C_DEV_t *i2c_dev, const uint32_t mask) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } alt_setbits_word(ALT_I2C_INTR_MSK_ADDR(i2c_dev->location), mask); return ALT_E_SUCCESS; } ///// // // Gets the cause of I2C transmission abort. // ALT_STATUS_CODE alt_i2c_tx_abort_cause_get(ALT_I2C_DEV_t *i2c_dev, ALT_I2C_TX_ABORT_CAUSE_t *cause) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *cause = (ALT_I2C_TX_ABORT_CAUSE_t)alt_read_word(ALT_I2C_TX_ABRT_SRC_ADDR(i2c_dev->location)); return ALT_E_SUCCESS; } ///// // // Returns ALT_E_TRUE when the receive FIFO is empty. // ALT_STATUS_CODE alt_i2c_rx_fifo_is_empty(ALT_I2C_DEV_t *i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (ALT_I2C_STAT_RFNE_GET(alt_read_word(ALT_I2C_STAT_ADDR(i2c_dev->location))) == ALT_I2C_STAT_RFNE_E_EMPTY) { return ALT_E_TRUE; } else { return ALT_E_FALSE; } } // // Returns ALT_E_TRUE when the receive FIFO is completely full. // ALT_STATUS_CODE alt_i2c_rx_fifo_is_full(ALT_I2C_DEV_t *i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (ALT_I2C_STAT_RFF_GET(alt_read_word(ALT_I2C_STAT_ADDR(i2c_dev->location))) == ALT_I2C_STAT_RFF_E_FULL) { return ALT_E_TRUE; } else { return ALT_E_FALSE; } } // // Returns the number of valid entries in the receive FIFO. // ALT_STATUS_CODE alt_i2c_rx_fifo_level_get(ALT_I2C_DEV_t *i2c_dev, uint32_t *num_entries) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *num_entries = ALT_I2C_RXFLR_RXFLR_GET(alt_read_word(ALT_I2C_RXFLR_ADDR(i2c_dev->location))); return ALT_E_SUCCESS; } // // Gets the current receive FIFO threshold level value. // ALT_STATUS_CODE alt_i2c_rx_fifo_threshold_get(ALT_I2C_DEV_t *i2c_dev, uint8_t *threshold) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *threshold = ALT_I2C_RX_TL_RX_TL_GET(alt_read_word(ALT_I2C_RX_TL_ADDR(i2c_dev->location))); return ALT_E_SUCCESS; } // // Sets the current receive FIFO threshold level value. // ALT_STATUS_CODE alt_i2c_rx_fifo_threshold_set(ALT_I2C_DEV_t *i2c_dev, const uint8_t threshold) { ALT_STATUS_CODE status = ALT_E_SUCCESS; if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } alt_replbits_word(ALT_I2C_RX_TL_ADDR(i2c_dev->location), ALT_I2C_RX_TL_RX_TL_SET_MSK, ALT_I2C_RX_TL_RX_TL_SET(threshold)); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } // // Returns ALT_E_TRUE when the transmit FIFO is empty. // ALT_STATUS_CODE alt_i2c_tx_fifo_is_empty(ALT_I2C_DEV_t *i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (ALT_I2C_STAT_TFE_GET(alt_read_word(ALT_I2C_STAT_ADDR(i2c_dev->location))) == ALT_I2C_STAT_TFE_E_EMPTY) { return ALT_E_TRUE; } else { return ALT_E_FALSE; } } // // Returns ALT_E_TRUE when the transmit FIFO is completely full. // ALT_STATUS_CODE alt_i2c_tx_fifo_is_full(ALT_I2C_DEV_t *i2c_dev) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (ALT_I2C_STAT_TFNF_GET(alt_read_word(ALT_I2C_STAT_ADDR(i2c_dev->location))) == ALT_I2C_STAT_TFNF_E_FULL) { return ALT_E_TRUE; } else { return ALT_E_FALSE; } } // // Returns the number of valid entries in the transmit FIFO. // ALT_STATUS_CODE alt_i2c_tx_fifo_level_get(ALT_I2C_DEV_t *i2c_dev, uint32_t *num_entries) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *num_entries = ALT_I2C_TXFLR_TXFLR_GET(alt_read_word(ALT_I2C_TXFLR_ADDR(i2c_dev->location))); return ALT_E_SUCCESS; } // // Sets the current transmit FIFO threshold level value. // ALT_STATUS_CODE alt_i2c_tx_fifo_threshold_get(ALT_I2C_DEV_t *i2c_dev, uint8_t *threshold) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *threshold = ALT_I2C_TX_TL_TX_TL_GET(alt_read_word(ALT_I2C_TX_TL_ADDR(i2c_dev->location))); return ALT_E_SUCCESS; } // // Sets the current transmit FIFO threshold level value. // ALT_STATUS_CODE alt_i2c_tx_fifo_threshold_set(ALT_I2C_DEV_t *i2c_dev, const uint8_t threshold) { ALT_STATUS_CODE status = ALT_E_SUCCESS; if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } bool already_enabled = (alt_i2c_is_enabled_helper(i2c_dev) == ALT_E_TRUE); if (already_enabled) { // Temporarily disable controller status = alt_i2c_disable(i2c_dev); if (status != ALT_E_SUCCESS) { return status; } } alt_replbits_word(ALT_I2C_TX_TL_ADDR(i2c_dev->location), ALT_I2C_TX_TL_TX_TL_SET_MSK, ALT_I2C_TX_TL_TX_TL_SET(threshold)); if (already_enabled) { // Re-enable controller status = alt_i2c_enable(i2c_dev); } return status; } ///// ALT_STATUS_CODE alt_i2c_rx_dma_threshold_get(ALT_I2C_DEV_t * i2c_dev, uint8_t * threshold) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *threshold = ALT_I2C_DMA_RDLR_DMARDL_GET(alt_read_word(ALT_I2C_DMA_RDLR_ADDR(i2c_dev->location))); return ALT_E_SUCCESS; } ALT_STATUS_CODE alt_i2c_rx_dma_threshold_set(ALT_I2C_DEV_t * i2c_dev, uint8_t threshold) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (threshold > ALT_I2C_DMA_RDLR_DMARDL_SET_MSK) { return ALT_E_ARG_RANGE; } alt_write_word(ALT_I2C_DMA_RDLR_ADDR(i2c_dev->location), threshold); return ALT_E_SUCCESS; } ALT_STATUS_CODE alt_i2c_tx_dma_threshold_get(ALT_I2C_DEV_t * i2c_dev, uint8_t * threshold) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } *threshold = ALT_I2C_DMA_TDLR_DMATDL_GET(alt_read_word(ALT_I2C_DMA_TDLR_ADDR(i2c_dev->location))); return ALT_E_SUCCESS; } ALT_STATUS_CODE alt_i2c_tx_dma_threshold_set(ALT_I2C_DEV_t * i2c_dev, uint8_t threshold) { if (alt_i2c_checking(i2c_dev) == ALT_E_FALSE) { return ALT_E_BAD_ARG; } if (threshold > ALT_I2C_DMA_TDLR_DMATDL_SET_MSK) { return ALT_E_ARG_RANGE; } alt_write_word(ALT_I2C_DMA_TDLR_ADDR(i2c_dev->location), threshold); return ALT_E_SUCCESS; }