summaryrefslogtreecommitdiffstats
path: root/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_i2c.c')
-rw-r--r--bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_i2c.c2004
1 files changed, 2004 insertions, 0 deletions
diff --git a/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_i2c.c b/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_i2c.c
new file mode 100644
index 0000000000..b6279a7938
--- /dev/null
+++ b/bsps/arm/altera-cyclone-v/contrib/hwlib/src/hwmgr/alt_i2c.c
@@ -0,0 +1,2004 @@
+/******************************************************************************
+ *
+ * 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 <bsp/alt_i2c.h>
+#include <bsp/alt_reset_manager.h>
+#include <stdio.h>
+
+/////
+
+// 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;
+ }
+
+ // <lcount> = <internal clock> / 2 * <speed, Hz>
+ uint32_t scl_lcnt = i2c_dev->clock_freq / (speed_in_hz << 1);
+
+ cfg->ss_scl_lcnt = cfg->fs_scl_lcnt = scl_lcnt;
+ // hcount = <lcount> + 70
+ cfg->ss_scl_hcnt = cfg->fs_scl_hcnt = scl_lcnt - ALT_I2C_DIFF_LCNT_HCNT;
+
+ // lcount = <internal clock> / 2 * <speed, Hz>
+
+ 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;
+}