rt-thread-official/bsp/nxp/imx/imx6ul/platform/include/imx_i2c.h

233 lines
8.6 KiB
C

/*
* Copyright (c) 2011-2012, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o 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.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*/
#ifndef __IMX_I2C_H__
#define __IMX_I2C_H__
#include "sdk_types.h"
//! @addtogroup diag_i2c
//! @{
////////////////////////////////////////////////////////////////////////////////
// Definitions
////////////////////////////////////////////////////////////////////////////////
//! @brief Read/write address bits
//!
//! Bit 0 of the i2c device address cycle to indicate r/w. 0 is for write, 1 is for read.
enum _i2c_rq {
I2C_WRITE = 0,
I2C_READ = 1
};
//! @brief I2C Error Codes
enum _i2c_err {
ERR_TX = -1,
ERR_RX = -2,
ERR_ARB_LOST = -3,
ERR_NO_ACK = -4,
ERR_XFER = -5,
ERR_RX_ACK = -6,
ERR_NO_ACK_ON_START = -7,
ERR_INVALID_REQUEST = -8
};
//! Default slave address used for the MX6.
enum _i2c_slave_id {
IMX6_DEFAULT_SLAVE_ID = 0x60
};
//! @brief Info required to talk to an I2C device.
//!
//! Pairs an I2C port number with a device address.
//!
//! While the device address is often fixed and known in advance by the driver,
//! some devices have configurable addresses that can be changed with pin
//! settings. Thus, the same device may have different adresses on different
//! boards depending on how these pins are tied.
//!
//! Note that the @a address member's value is @i not pre-shifted. The 7-bit
//! address is right aligned within the byte, and the top bit is always set to 0.
typedef struct i2c_device_info {
uint8_t port; //!< I2C controller instance to which the device is connected. Starts at 1.
uint8_t address; //!< I2C device address in lower 7 bits.
uint32_t freq; //!< Maximum transfer speed in bits per second.
} i2c_device_info_t;
/*!
* @brief An I2C transfer descriptor.
*
* To perform an I2C transfer, the caller first fills in an instance of this struct. Then
* i2c_xfer() is called, passing a pointer to the #imx_i2c_request_t struct.
*
* @a ctl_addr should be set to either a valid controller instance number from 1 through
* the number of I2C instances on the chip, or the base address of the controller.
*
* If @a device is set to a non-NULL value, it is a pointer to an #i2c_device_info_t struct
* to use instead of the @a ctl_addr and @a dev_addr members of this struct.
*/
typedef struct imx_i2c_request {
uint32_t ctl_addr; //!< Either the I2C controller base address or instance number starting at 1.
uint32_t dev_addr; //!< The I2C device address.
uint32_t reg_addr; //!< The register address within the target device.
uint32_t reg_addr_sz; //!< Number of bytes for the address of I2C device register.
uint8_t *buffer; //!< Buffer to hold the data.
uint32_t buffer_sz; //!< The number of bytes for read/write.
int32_t (*slave_receive) (const struct imx_i2c_request *rq); //!< Function for slave to receive data from master.
int32_t (*slave_transmit) (const struct imx_i2c_request *rq); //!< Function for slave to transmit data to master.
const i2c_device_info_t * device; //!< Optional pointer to device info struct. Overrides @a ctl_addr and @a dev_addr if set.
} imx_i2c_request_t;
////////////////////////////////////////////////////////////////////////////////
// API
////////////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus)
extern "C" {
#endif
/*!
* @brief Initialize the I2C module
*
* Mainly enable the I2C clock, module itself and the I2C clock prescaler.
*
* @param base Either the base address of I2C module or the module's instance number. (also assigned for I2Cx_CLK)
* @param baud The desired data rate in bits per second.
*
* @return 0 if successful; non-zero otherwise
*/
int i2c_init(uint32_t base, uint32_t baud);
/*!
* @brief Perform a single I2C transfer in the selected direction.
*
* This is a rather simple function that can be used for most I2C devices.
*
* Common steps for both READ and WRITE:
* - step 1: issue start signal
* - step 2: put I2C device addr on the bus (always 1 byte write. the dir always I2C_WRITE)
* - step 3: offset of the I2C device write (offset within the device. can be 1-4 bytes)
*
* For READ:
* - step 4: do repeat-start
* - step 5: send slave address again, but indicate a READ operation by setting LSB bit
* - Step 6: change to receive mode
* - Step 7: dummy read
* - Step 8: reading
*
* For WRITE:
* - Step 4: do data write
* - Step 5: generate STOP by clearing MSTA bit
*
* @param rq Pointer to #imx_i2c_request_t.
* @param dir #I2C_READ or #I2C_WRITE
*
* @return 0 on success; non-zero otherwise
*/
int i2c_xfer(const imx_i2c_request_t *rq, int dir);
/*!
* @brief Perform I2C read transfer.
*
* @param rq Pointer to #imx_i2c_request_t.
*/
int i2c_read(const imx_i2c_request_t *rq);
/*!
* @brief Perform I2C write transfer.
*
* @param rq Pointer to #imx_i2c_request_t.
*/
int i2c_write(const imx_i2c_request_t *rq);
/*!
* @brief I2C handler for the slave mode.
*
* The function is based on the flow chart for typical I2C polling routine described in the
* I2C controller chapter of the reference manual.
*
* @param rq Pointer to #imx_i2c_request_t.
*/
void i2c_slave_handler(const imx_i2c_request_t *rq);
/*!
* @brief Handle the I2C transfers in slave mode.
*
* The slave mode behaves like any device with g_addr_cycle of address + g_data_cycle of data.
* Master read =
* START - SLAVE_ID/W - ACK - MEM_ADDR - ACK - START - SLAVE_ID/R - ACK - DATAx - NACK - STOP
*
* Example for a 16-bit address access:
* - 1st IRQ - receive the slave address and Write flag from master.
* - 2nd IRQ - receive the lower byte of the requested 16-bit address.
* - 3rd IRQ - receive the higher byte of the requested 16-bit address.
* - 4th IRQ - receive the slave address and Read flag from master.
* - 5th and next IRQ - transmit the data as long as NACK and STOP is not asserted.
*
* Master write =
* START - SLAVE_ID/W - ACK - MEM_ADDR - ACK - DATAx - NACK - STOP
*
* - 1st IRQ - receive the slave address and Write flag from master.
* - 2nd IRQ - receive the lower byte of the requested 16-bit address.
* - 3rd IRQ - receive the higher byte of the requested 16-bit address.
* - 4th and next IRQ - receive the data as long STOP is not asserted.
*
* @param port Pointer to the I2C module structure.
* @param rq Pointer to #imx_i2c_request_t.
*/
void i2c_slave_xfer(imx_i2c_request_t *rq);
////////////////////////////////////////////////////////////////////////////////
// Board support
////////////////////////////////////////////////////////////////////////////////
//! @name Board support functions
//!
//! These functions are called by the driver in order to factor out board
//! specific functionality. They must be defined by the board support
//! library or the application.
//@{
//! @brief Configure IOMUX for the I2C driver.
void i2c_iomux_config(int instance);
//@}
#if defined(__cplusplus)
}
#endif
//! @}
#endif /* __IMX_I2C_H__ */
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////