arm/rp2040: Add RP2040 I2C device support
This commit is contained in:
parent
60b18467f3
commit
9d0b3594f6
@ -72,3 +72,27 @@ config RP2040_UART1_2STOP
|
||||
0=1 stop bit, 1=Two stop bits. Default: 1 stop bit
|
||||
|
||||
endif
|
||||
|
||||
config RP2040_I2C
|
||||
bool "I2C"
|
||||
select I2C
|
||||
|
||||
if RP2040_I2C
|
||||
|
||||
config RP2040_I2C0
|
||||
bool "I2C0"
|
||||
|
||||
config RP2040_I2C1
|
||||
bool "I2C1"
|
||||
|
||||
config RP2040_I2C_DRIVER
|
||||
bool "I2C character driver"
|
||||
default n
|
||||
select I2C_DRIVER
|
||||
---help---
|
||||
Build in support for a character driver at /dev/i2c[N] that may be
|
||||
used to perform I2C bus transfers from applications. The intent of
|
||||
this driver is to support I2C testing. It is not suitable for use
|
||||
in any real driver application.
|
||||
|
||||
endif
|
||||
|
@ -67,6 +67,10 @@ CHIP_CSRCS += rp2040_cpuidlestack.c
|
||||
CHIP_CSRCS += rp2040_testset.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP2040_I2C),y)
|
||||
CHIP_CSRCS += rp2040_i2c.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP2040_FLASH_BOOT),y)
|
||||
ifneq ($(PICO_SDK_PATH),)
|
||||
include chip/boot2/Make.defs
|
||||
|
322
arch/arm/src/rp2040/hardware/rp2040_i2c.h
Normal file
322
arch/arm/src/rp2040/hardware/rp2040_i2c.h
Normal file
@ -0,0 +1,322 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/hardware/rp2040_i2c.h
|
||||
*
|
||||
* Generated from rp2040.svd originally provided by
|
||||
* Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* 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. Neither the name of the copyright holder 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 __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_I2C_H
|
||||
#define __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_I2C_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include "hardware/rp2040_memorymap.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define RP2040_I2C_IC_CON_OFFSET 0x000000 /* I2C Control Register */
|
||||
#define RP2040_I2C_IC_TAR_OFFSET 0x000004 /* I2C Target Address Register */
|
||||
#define RP2040_I2C_IC_SAR_OFFSET 0x000008 /* I2C Slave Address Register */
|
||||
#define RP2040_I2C_IC_DATA_CMD_OFFSET 0x000010 /* I2C Rx/Tx Data Buffer and Command Register */
|
||||
#define RP2040_I2C_IC_SS_SCL_HCNT_OFFSET 0x000014 /* Standard Speed I2C Clock SCL High Count Register */
|
||||
#define RP2040_I2C_IC_SS_SCL_LCNT_OFFSET 0x000018 /* Standard Speed I2C Clock SCL Low Count Register */
|
||||
#define RP2040_I2C_IC_FS_SCL_HCNT_OFFSET 0x00001c /* Fast Mode or Fast Mode Plus I2C Clock SCL High Count Register */
|
||||
#define RP2040_I2C_IC_FS_SCL_LCNT_OFFSET 0x000020 /* Fast Mode or Fast Mode Plus I2C Clock SCL Low Count Register */
|
||||
#define RP2040_I2C_IC_INTR_STAT_OFFSET 0x00002c /* I2C Interrupt Status Register */
|
||||
#define RP2040_I2C_IC_INTR_MASK_OFFSET 0x000030 /* I2C Interrupt Mask Register */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_OFFSET 0x000034 /* I2C Raw Interrupt Status Register */
|
||||
#define RP2040_I2C_IC_RX_TL_OFFSET 0x000038 /* I2C Receive FIFO Threshold Register */
|
||||
#define RP2040_I2C_IC_TX_TL_OFFSET 0x00003c /* I2C Transmit FIFO Threshold Register */
|
||||
#define RP2040_I2C_IC_CLR_INTR_OFFSET 0x000040 /* Clear Combined and Individual Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_RX_UNDER_OFFSET 0x000044 /* Clear RX_UNDER Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_RX_OVER_OFFSET 0x000048 /* Clear RX_OVER Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_TX_OVER_OFFSET 0x00004c /* Clear TX_OVER Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_RD_REQ_OFFSET 0x000050 /* Clear RD_REQ Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_TX_ABRT_OFFSET 0x000054 /* Clear TX_ABRT Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_RX_DONE_OFFSET 0x000058 /* Clear RX_DONE Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_ACTIVITY_OFFSET 0x00005c /* Clear ACTIVITY Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_STOP_DET_OFFSET 0x000060 /* Clear STOP_DET Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_START_DET_OFFSET 0x000064 /* Clear START_DET Interrupt Register */
|
||||
#define RP2040_I2C_IC_CLR_GEN_CALL_OFFSET 0x000068 /* Clear GEN_CALL Interrupt Register */
|
||||
#define RP2040_I2C_IC_ENABLE_OFFSET 0x00006c /* I2C Enable Register */
|
||||
#define RP2040_I2C_IC_STATUS_OFFSET 0x000070 /* I2C Status Register */
|
||||
#define RP2040_I2C_IC_TXFLR_OFFSET 0x000074 /* I2C Transmit FIFO Level Register */
|
||||
#define RP2040_I2C_IC_RXFLR_OFFSET 0x000078 /* I2C Receive FIFO Level Register */
|
||||
#define RP2040_I2C_IC_SDA_HOLD_OFFSET 0x00007c /* I2C SDA Hold Time Length Register */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_OFFSET 0x000080 /* I2C Transmit Abort Source Register */
|
||||
#define RP2040_I2C_IC_SLV_DATA_NACK_ONLY_OFFSET 0x000084 /* Generate Slave Data NACK Register */
|
||||
#define RP2040_I2C_IC_DMA_CR_OFFSET 0x000088 /* DMA Control Register */
|
||||
#define RP2040_I2C_IC_DMA_TDLR_OFFSET 0x00008c /* DMA Transmit Data Level Register */
|
||||
#define RP2040_I2C_IC_DMA_RDLR_OFFSET 0x000090 /* I2C Receive Data Level Register */
|
||||
#define RP2040_I2C_IC_SDA_SETUP_OFFSET 0x000094 /* I2C SDA Setup Register */
|
||||
#define RP2040_I2C_IC_ACK_GENERAL_CALL_OFFSET 0x000098 /* I2C ACK General Call Register */
|
||||
#define RP2040_I2C_IC_ENABLE_STATUS_OFFSET 0x00009c /* I2C Enable Status Register */
|
||||
#define RP2040_I2C_IC_FS_SPKLEN_OFFSET 0x0000a0 /* I2C SS, FS or FM+ spike suppression limit */
|
||||
#define RP2040_I2C_IC_CLR_RESTART_DET_OFFSET 0x0000a8 /* Clear RESTART_DET Interrupt Register */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_OFFSET 0x0000f4 /* Component Parameter Register 1 */
|
||||
#define RP2040_I2C_IC_COMP_VERSION_OFFSET 0x0000f8 /* I2C Component Version Register */
|
||||
#define RP2040_I2C_IC_COMP_TYPE_OFFSET 0x0000fc /* I2C Component Type Register */
|
||||
|
||||
/* Register definitions *****************************************************/
|
||||
|
||||
#define RP2040_I2C_IC_CON(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CON_OFFSET)
|
||||
#define RP2040_I2C_IC_TAR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_TAR_OFFSET)
|
||||
#define RP2040_I2C_IC_SAR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_SAR_OFFSET)
|
||||
#define RP2040_I2C_IC_DATA_CMD(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_DATA_CMD_OFFSET)
|
||||
#define RP2040_I2C_IC_SS_SCL_HCNT(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_SS_SCL_HCNT_OFFSET)
|
||||
#define RP2040_I2C_IC_SS_SCL_LCNT(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_SS_SCL_LCNT_OFFSET)
|
||||
#define RP2040_I2C_IC_FS_SCL_HCNT(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_FS_SCL_HCNT_OFFSET)
|
||||
#define RP2040_I2C_IC_FS_SCL_LCNT(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_FS_SCL_LCNT_OFFSET)
|
||||
#define RP2040_I2C_IC_INTR_STAT(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_INTR_STAT_OFFSET)
|
||||
#define RP2040_I2C_IC_INTR_MASK(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_INTR_MASK_OFFSET)
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_RAW_INTR_STAT_OFFSET)
|
||||
#define RP2040_I2C_IC_RX_TL(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_RX_TL_OFFSET)
|
||||
#define RP2040_I2C_IC_TX_TL(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_TX_TL_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_INTR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_INTR_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_RX_UNDER(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_RX_UNDER_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_RX_OVER(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_RX_OVER_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_TX_OVER(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_TX_OVER_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_RD_REQ(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_RD_REQ_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_TX_ABRT(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_TX_ABRT_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_RX_DONE(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_RX_DONE_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_ACTIVITY(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_ACTIVITY_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_STOP_DET(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_STOP_DET_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_START_DET(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_START_DET_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_GEN_CALL(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_GEN_CALL_OFFSET)
|
||||
#define RP2040_I2C_IC_ENABLE(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_ENABLE_OFFSET)
|
||||
#define RP2040_I2C_IC_STATUS(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_STATUS_OFFSET)
|
||||
#define RP2040_I2C_IC_TXFLR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_TXFLR_OFFSET)
|
||||
#define RP2040_I2C_IC_RXFLR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_RXFLR_OFFSET)
|
||||
#define RP2040_I2C_IC_SDA_HOLD(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_SDA_HOLD_OFFSET)
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_TX_ABRT_SOURCE_OFFSET)
|
||||
#define RP2040_I2C_IC_SLV_DATA_NACK_ONLY(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_SLV_DATA_NACK_ONLY_OFFSET)
|
||||
#define RP2040_I2C_IC_DMA_CR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_DMA_CR_OFFSET)
|
||||
#define RP2040_I2C_IC_DMA_TDLR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_DMA_TDLR_OFFSET)
|
||||
#define RP2040_I2C_IC_DMA_RDLR(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_DMA_RDLR_OFFSET)
|
||||
#define RP2040_I2C_IC_SDA_SETUP(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_SDA_SETUP_OFFSET)
|
||||
#define RP2040_I2C_IC_ACK_GENERAL_CALL(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_ACK_GENERAL_CALL_OFFSET)
|
||||
#define RP2040_I2C_IC_ENABLE_STATUS(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_ENABLE_STATUS_OFFSET)
|
||||
#define RP2040_I2C_IC_FS_SPKLEN(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_FS_SPKLEN_OFFSET)
|
||||
#define RP2040_I2C_IC_CLR_RESTART_DET(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_CLR_RESTART_DET_OFFSET)
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_COMP_PARAM_1_OFFSET)
|
||||
#define RP2040_I2C_IC_COMP_VERSION(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_COMP_VERSION_OFFSET)
|
||||
#define RP2040_I2C_IC_COMP_TYPE(n) (RP2040_I2C_BASE(n) + RP2040_I2C_IC_COMP_TYPE_OFFSET)
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
#define RP2040_I2C_IC_CON_STOP_DET_IF_MASTER_ACTIVE (1 << 10) /* Master issues the STOP_DET interrupt irrespective of whether master is active or not */
|
||||
#define RP2040_I2C_IC_CON_RX_FIFO_FULL_HLD_CTRL (1 << 9) /* Hold bus when RX_FIFO is full */
|
||||
#define RP2040_I2C_IC_CON_TX_EMPTY_CTRL (1 << 8) /* Controlled generation of TX_EMPTY interrupt */
|
||||
#define RP2040_I2C_IC_CON_STOP_DET_IFADDRESSED (1 << 7) /* slave issues STOP_DET intr only if addressed */
|
||||
#define RP2040_I2C_IC_CON_IC_SLAVE_DISABLE (1 << 6) /* Slave mode is disabled */
|
||||
#define RP2040_I2C_IC_CON_IC_RESTART_EN (1 << 5) /* Master restart enabled */
|
||||
#define RP2040_I2C_IC_CON_IC_10BITADDR_MASTER (1 << 4) /* Master 10Bit addressing mode */
|
||||
#define RP2040_I2C_IC_CON_IC_10BITADDR_SLAVE (1 << 3) /* Slave 10Bit addressing */
|
||||
#define RP2040_I2C_IC_CON_SPEED_SHIFT (1) /* These bits control at which speed the DW_apb_i2c operates */
|
||||
#define RP2040_I2C_IC_CON_SPEED_MASK (0x03 << RP2040_I2C_IC_CON_SPEED_SHIFT)
|
||||
#define RP2040_I2C_IC_CON_SPEED_STANDARD (0x1 << RP2040_I2C_IC_CON_SPEED_SHIFT)
|
||||
#define RP2040_I2C_IC_CON_SPEED_FAST (0x2 << RP2040_I2C_IC_CON_SPEED_SHIFT)
|
||||
#define RP2040_I2C_IC_CON_SPEED_HIGH (0x3 << RP2040_I2C_IC_CON_SPEED_SHIFT)
|
||||
#define RP2040_I2C_IC_CON_MASTER_MODE (1 << 0) /* Master mode is enabled */
|
||||
|
||||
#define RP2040_I2C_IC_TAR_SPECIAL (1 << 11) /* Enables programming of GENERAL_CALL or START_BYTE transmission */
|
||||
#define RP2040_I2C_IC_TAR_GC_OR_START (1 << 10) /* START byte transmission */
|
||||
#define RP2040_I2C_IC_TAR_MASK (0x3ff) /* This is the target address for any master transaction. */
|
||||
|
||||
#define RP2040_I2C_IC_SAR_MASK (0x3ff) /* The IC_SAR holds the slave address when the I2C is operating as a slave. */
|
||||
|
||||
#define RP2040_I2C_IC_DATA_CMD_FIRST_DATA_BYTE (1 << 11) /* Non sequential data byte received */
|
||||
#define RP2040_I2C_IC_DATA_CMD_RESTART (1 << 10) /* Issue RESTART before this command */
|
||||
#define RP2040_I2C_IC_DATA_CMD_STOP (1 << 9) /* Issue STOP after this command */
|
||||
#define RP2040_I2C_IC_DATA_CMD_CMD (1 << 8) /* Master Read Command */
|
||||
#define RP2040_I2C_IC_DATA_CMD_DAT_MASK (0xff) /* This register contains the data to be transmitted or received on the I2C bus. */
|
||||
|
||||
#define RP2040_I2C_IC_SS_SCL_HCNT_MASK (0xffff) /* This register must be set before any I2C bus transaction can take place to ensure proper I/O timing. */
|
||||
|
||||
#define RP2040_I2C_IC_SS_SCL_LCNT_MASK (0xffff) /* This register must be set before any I2C bus transaction can take place to ensure proper I/O timing. */
|
||||
|
||||
#define RP2040_I2C_IC_FS_SCL_HCNT_MASK (0xffff) /* This register must be set before any I2C bus transaction can take place to ensure proper I/O timing. */
|
||||
|
||||
#define RP2040_I2C_IC_FS_SCL_LCNT_MASK (0xffff) /* This register must be set before any I2C bus transaction can take place to ensure proper I/O timing. */
|
||||
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_MASTER_ON_HOLD (1 << 13) /* R_MASTER_ON_HOLD interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_RESTART_DET (1 << 12) /* R_RESTART_DET interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_GEN_CALL (1 << 11) /* R_GEN_CALL interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_START_DET (1 << 10) /* R_START_DET interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_STOP_DET (1 << 9) /* R_STOP_DET interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_ACTIVITY (1 << 8) /* R_ACTIVITY interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_RX_DONE (1 << 7) /* R_RX_DONE interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_TX_ABRT (1 << 6) /* R_TX_ABRT interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_RD_REQ (1 << 5) /* R_RD_REQ interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_TX_EMPTY (1 << 4) /* R_TX_EMPTY interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_TX_OVER (1 << 3) /* R_TX_OVER interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_RX_FULL (1 << 2) /* R_RX_FULL interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_RX_OVER (1 << 1) /* R_RX_OVER interrupt is active */
|
||||
#define RP2040_I2C_IC_INTR_STAT_R_RX_UNDER (1 << 0) /* RX_UNDER interrupt is active */
|
||||
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_MASTER_ON_HOLD_READ_ONLY (1 << 13) /* MASTER_ON_HOLD interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_RESTART_DET (1 << 12) /* RESTART_DET interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_GEN_CALL (1 << 11) /* GEN_CALL interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_START_DET (1 << 10) /* START_DET interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_STOP_DET (1 << 9) /* STOP_DET interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_ACTIVITY (1 << 8) /* ACTIVITY interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_RX_DONE (1 << 7) /* RX_DONE interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_TX_ABRT (1 << 6) /* TX_ABORT interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_RD_REQ (1 << 5) /* RD_REQ interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_TX_EMPTY (1 << 4) /* TX_EMPTY interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_TX_OVER (1 << 3) /* TX_OVER interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_RX_FULL (1 << 2) /* RX_FULL interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_RX_OVER (1 << 1) /* RX_OVER interrupt is unmasked */
|
||||
#define RP2040_I2C_IC_INTR_MASK_M_RX_UNDER (1 << 0) /* RX_UNDER interrupt is unmasked */
|
||||
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_MASTER_ON_HOLD (1 << 13) /* MASTER_ON_HOLD interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_RESTART_DET (1 << 12) /* RESTART_DET interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_GEN_CALL (1 << 11) /* GEN_CALL interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_START_DET (1 << 10) /* START_DET interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_STOP_DET (1 << 9) /* STOP_DET interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_ACTIVITY (1 << 8) /* RAW_INTR_ACTIVITY interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_RX_DONE (1 << 7) /* RX_DONE interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_TX_ABRT (1 << 6) /* TX_ABRT interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_RD_REQ (1 << 5) /* RD_REQ interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_TX_EMPTY (1 << 4) /* TX_EMPTY interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_TX_OVER (1 << 3) /* TX_OVER interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_RX_FULL (1 << 2) /* RX_FULL interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_RX_OVER (1 << 1) /* RX_OVER interrupt is active */
|
||||
#define RP2040_I2C_IC_RAW_INTR_STAT_RX_UNDER (1 << 0) /* RX_UNDER interrupt is active */
|
||||
|
||||
#define RP2040_I2C_IC_RX_TL_RX_TL_MASK (0xff) /* Receive FIFO Threshold Level. */
|
||||
|
||||
#define RP2040_I2C_IC_TX_TL_TX_TL_MASK (0xff) /* Transmit FIFO Threshold Level. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_INTR_CLR_INTR (1 << 0) /* Read this register to clear the combined interrupt, all individual interrupts, and the IC_TX_ABRT_SOURCE register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_RX_UNDER_CLR_RX_UNDER (1 << 0) /* Read this register to clear the RX_UNDER interrupt (bit 0) of the IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_RX_OVER_CLR_RX_OVER (1 << 0) /* Read this register to clear the RX_OVER interrupt (bit 1) of the IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_TX_OVER_CLR_TX_OVER (1 << 0) /* Read this register to clear the TX_OVER interrupt (bit 3) of the IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_RD_REQ_CLR_RD_REQ (1 << 0) /* Read this register to clear the RD_REQ interrupt (bit 5) of the IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_TX_ABRT_CLR_TX_ABRT (1 << 0) /* Read this register to clear the TX_ABRT interrupt (bit 6) of the IC_RAW_INTR_STAT register, and the IC_TX_ABRT_SOURCE register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_RX_DONE_CLR_RX_DONE (1 << 0) /* Read this register to clear the RX_DONE interrupt (bit 7) of the IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_ACTIVITY_CLR_ACTIVITY (1 << 0) /* Reading this register clears the ACTIVITY interrupt if the I2C is not active anymore. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_STOP_DET_CLR_STOP_DET (1 << 0) /* Read this register to clear the STOP_DET interrupt (bit 9) of the IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_START_DET_CLR_START_DET (1 << 0) /* Read this register to clear the START_DET interrupt (bit 10) of the IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_GEN_CALL_CLR_GEN_CALL (1 << 0) /* Read this register to clear the GEN_CALL interrupt (bit 11) of IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_ENABLE_TX_CMD_BLOCK (1 << 2) /* Tx Command execution blocked */
|
||||
#define RP2040_I2C_IC_ENABLE_ABORT (1 << 1) /* ABORT operation in progress */
|
||||
#define RP2040_I2C_IC_ENABLE_ENABLE (1 << 0) /* I2C is enabled */
|
||||
|
||||
#define RP2040_I2C_IC_STATUS_SLV_ACTIVITY (1 << 6) /* Slave not idle */
|
||||
#define RP2040_I2C_IC_STATUS_MST_ACTIVITY (1 << 5) /* Master not idle */
|
||||
#define RP2040_I2C_IC_STATUS_RFF (1 << 4) /* Rx FIFO is full */
|
||||
#define RP2040_I2C_IC_STATUS_RFNE (1 << 3) /* Rx FIFO not empty */
|
||||
#define RP2040_I2C_IC_STATUS_TFE (1 << 2) /* Tx FIFO is empty */
|
||||
#define RP2040_I2C_IC_STATUS_TFNF (1 << 1) /* Tx FIFO not full */
|
||||
#define RP2040_I2C_IC_STATUS_ACTIVITY (1 << 0) /* I2C is active */
|
||||
|
||||
#define RP2040_I2C_IC_TXFLR_TXFLR_MASK (0x1f) /* Transmit FIFO Level. */
|
||||
|
||||
#define RP2040_I2C_IC_RXFLR_RXFLR_MASK (0x1f) /* Receive FIFO Level. */
|
||||
|
||||
#define RP2040_I2C_IC_SDA_HOLD_IC_SDA_RX_HOLD_SHIFT (16) /* Sets the required SDA hold time in units of ic_clk period, when DW_apb_i2c acts as a receiver. */
|
||||
#define RP2040_I2C_IC_SDA_HOLD_IC_SDA_RX_HOLD_MASK (0xff << RP2040_I2C_IC_SDA_HOLD_IC_SDA_RX_HOLD_SHIFT)
|
||||
#define RP2040_I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD_MASK (0xffff) /* Sets the required SDA hold time in units of ic_clk period, when DW_apb_i2c acts as a transmitter. */
|
||||
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_TX_FLUSH_CNT_SHIFT (23) /* This field indicates the number of Tx FIFO Data Commands which are flushed due to TX_ABRT interrupt. */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_TX_FLUSH_CNT_MASK (0x1ff << RP2040_I2C_IC_TX_ABRT_SOURCE_TX_FLUSH_CNT_SHIFT)
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_USER_ABRT (1 << 16) /* Transfer abort detected by master */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_SLVRD_INTX (1 << 15) /* Slave trying to transmit to remote master in read mode */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_SLV_ARBLOST (1 << 14) /* Slave lost arbitration to remote master */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_SLVFLUSH_TXFIFO (1 << 13) /* Slave flushes existing data in TX-FIFO upon getting read command */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ARB_LOST (1 << 12) /* Master or Slave-Transmitter lost arbitration */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_MASTER_DIS (1 << 11) /* User initiating master operation when MASTER disabled */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_10B_RD_NORSTRT (1 << 10) /* Master trying to read in 10Bit addressing mode when RESTART disabled */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_SBYTE_NORSTRT (1 << 9) /* User trying to send START byte when RESTART disabled */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_HS_NORSTRT (1 << 8) /* User trying to switch Master to HS mode when RESTART disabled */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_SBYTE_ACKDET (1 << 7) /* ACK detected for START byte */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_HS_ACKDET (1 << 6) /* HS Master code ACKed in HS Mode */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_GCALL_READ (1 << 5) /* GCALL is followed by read from bus */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_GCALL_NOACK (1 << 4) /* GCALL not ACKed by any slave */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK (1 << 3) /* Transmitted data not ACKed by addressed slave */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK (1 << 2) /* Byte 2 of 10Bit Address not ACKed by any slave */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK (1 << 1) /* Byte 1 of 10Bit Address not ACKed by any slave */
|
||||
#define RP2040_I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK (1 << 0) /* This abort is generated because of NOACK for 7-bit address */
|
||||
|
||||
#define RP2040_I2C_IC_SLV_DATA_NACK_ONLY_NACK (1 << 0) /* Slave receiver generates NACK upon data reception only */
|
||||
|
||||
#define RP2040_I2C_IC_DMA_CR_TDMAE (1 << 1) /* Transmit FIFO DMA channel enabled */
|
||||
#define RP2040_I2C_IC_DMA_CR_RDMAE (1 << 0) /* Receive FIFO DMA channel enabled */
|
||||
|
||||
#define RP2040_I2C_IC_DMA_TDLR_DMATDL_MASK (0x0f) /* Transmit Data Level. */
|
||||
|
||||
#define RP2040_I2C_IC_DMA_RDLR_DMARDL_MASK (0x0f) /* Receive Data Level. */
|
||||
|
||||
#define RP2040_I2C_IC_SDA_SETUP_SDA_SETUP_MASK (0xff) /* SDA Setup. */
|
||||
|
||||
#define RP2040_I2C_IC_ACK_GENERAL_CALL_ACK_GEN_CALL (1 << 0) /* Generate ACK for a General Call */
|
||||
|
||||
#define RP2040_I2C_IC_ENABLE_STATUS_SLV_RX_DATA_LOST (1 << 2) /* Slave RX Data is lost */
|
||||
#define RP2040_I2C_IC_ENABLE_STATUS_SLV_DISABLED_WHILE_BUSY (1 << 1) /* Slave is disabled when it is active */
|
||||
#define RP2040_I2C_IC_ENABLE_STATUS_IC_EN (1 << 0) /* I2C enabled */
|
||||
|
||||
#define RP2040_I2C_IC_FS_SPKLEN_MASK (0xff) /* This register must be set before any I2C bus transaction can take place to ensure stable operation. */
|
||||
|
||||
#define RP2040_I2C_IC_CLR_RESTART_DET_CLR_RESTART_DET (1 << 0) /* Read this register to clear the RESTART_DET interrupt (bit 12) of IC_RAW_INTR_STAT register. */
|
||||
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_TX_BUFFER_DEPTH_SHIFT (16) /* TX Buffer Depth = 16 */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_TX_BUFFER_DEPTH_MASK (0xff << RP2040_I2C_IC_COMP_PARAM_1_TX_BUFFER_DEPTH_SHIFT)
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_RX_BUFFER_DEPTH_SHIFT (8) /* RX Buffer Depth = 16 */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_RX_BUFFER_DEPTH_MASK (0xff << RP2040_I2C_IC_COMP_PARAM_1_RX_BUFFER_DEPTH_SHIFT)
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_ADD_ENCODED_PARAMS (1 << 7) /* Encoded parameters not visible */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_HAS_DMA (1 << 6) /* DMA handshaking signals are enabled */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_INTR_IO (1 << 5) /* COMBINED Interrupt outputs */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_HC_COUNT_VALUES (1 << 4) /* Programmable count values for each mode. */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_MAX_SPEED_MODE_SHIFT (2) /* MAX SPEED MODE = FAST MODE */
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_MAX_SPEED_MODE_MASK (0x03 << RP2040_I2C_IC_COMP_PARAM_1_MAX_SPEED_MODE_SHIFT)
|
||||
#define RP2040_I2C_IC_COMP_PARAM_1_APB_DATA_WIDTH_MASK (0x03) /* APB data bus width is 32 bits */
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_I2C_H */
|
@ -72,10 +72,13 @@
|
||||
#define RP2040_BUSCTRL_BASE 0x40030000 /* Register block for busfabric control signals and performance counters */
|
||||
#define RP2040_UART0_BASE 0x40034000
|
||||
#define RP2040_UART1_BASE 0x40038000
|
||||
#define RP2040_UART_BASE(n) (0x40034000 + (n) * 0x4000)
|
||||
#define RP2040_SPI0_BASE 0x4003c000
|
||||
#define RP2040_SPI1_BASE 0x40040000
|
||||
#define RP2040_SPI_BASE(n) (0x4003c000 + (n) * 0x4000)
|
||||
#define RP2040_I2C0_BASE 0x40044000 /* DW_apb_i2c address block */
|
||||
#define RP2040_I2C1_BASE 0x40048000 /* DW_apb_i2c address block */
|
||||
#define RP2040_I2C_BASE(n) (0x40044000 + (n) * 0x4000)
|
||||
#define RP2040_ADC_BASE 0x4004c000 /* Control and data interface to SAR ADC */
|
||||
#define RP2040_PWM_BASE 0x40050000 /* Simple PWM */
|
||||
#define RP2040_TIMER_BASE 0x40054000 /* Controls time and alarms time is a 64 bit value indicating the time in usec since power-on timeh is the top 32 bits of time & timel is the bottom 32 bits to change time write to timelw before timehw to read time read from timelr before timehr An alarm is set by setting alarm_enable and writing to the corresponding alarm register When an alarm is pending, the corresponding alarm_running signal will be high An alarm can be cancelled before it has finished by clearing the alarm_enable When an alarm fires, the corresponding alarm_irq is set and alarm_running is cleared To clear the interrupt write a 1 to the corresponding alarm_irq */
|
||||
@ -88,6 +91,7 @@
|
||||
#define RP2040_USBCTRL_REGS_BASE 0x50110000 /* USB FS/LS controller device registers */
|
||||
#define RP2040_PIO0_BASE 0x50200000 /* Programmable IO block */
|
||||
#define RP2040_PIO1_BASE 0x50300000 /* Programmable IO block */
|
||||
#define RP2040_PIO_BASE(n) (0x50200000 + (n) * 0x100000)
|
||||
#define RP2040_SIO_BASE 0xd0000000 /* Single-cycle IO block Provides core-local and inter-core hardware for the two processors, with single-cycle access. */
|
||||
#define RP2040_PPB_BASE 0xe0000000
|
||||
|
||||
|
833
arch/arm/src/rp2040/rp2040_i2c.c
Normal file
833
arch/arm/src/rp2040/rp2040_i2c.c
Normal file
@ -0,0 +1,833 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/rp2040_i2c.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "arm_arch.h"
|
||||
#include "arm_internal.h"
|
||||
|
||||
#include "rp2040_i2c.h"
|
||||
#include "hardware/rp2040_i2c.h"
|
||||
|
||||
#ifdef CONFIG_RP2040_I2C
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define I2C_TIMEOUT (20*1000/CONFIG_USEC_PER_TICK) /* 20 mS */
|
||||
|
||||
#define I2C_DEFAULT_FREQUENCY 400000
|
||||
#define I2C_FIFO_MAX_SIZE 32
|
||||
|
||||
#define I2C_INTR_ENABLE ((RP2040_I2C_IC_INTR_STAT_R_STOP_DET) | \
|
||||
(RP2040_I2C_IC_INTR_STAT_R_TX_ABRT) | \
|
||||
(RP2040_I2C_IC_INTR_STAT_R_TX_OVER) | \
|
||||
(RP2040_I2C_IC_INTR_STAT_R_RX_OVER) | \
|
||||
(RP2040_I2C_IC_INTR_STAT_R_RX_UNDER))
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
struct rp2040_i2cdev_s
|
||||
{
|
||||
struct i2c_master_s dev; /* Generic I2C device */
|
||||
unsigned int base; /* Base address of registers */
|
||||
uint16_t irqid; /* IRQ for this device */
|
||||
int8_t port; /* Port number */
|
||||
uint32_t base_freq; /* branch frequency */
|
||||
|
||||
sem_t mutex; /* Only one thread can access at a time */
|
||||
sem_t wait; /* Place to wait for transfer completion */
|
||||
struct wdog_s timeout; /* watchdog to timeout when bus hung */
|
||||
uint32_t frequency; /* Current I2C frequency */
|
||||
ssize_t reg_buff_offset;
|
||||
ssize_t rw_size;
|
||||
|
||||
struct i2c_msg_s *msgs;
|
||||
|
||||
int error; /* Error status of each transfers */
|
||||
int refs; /* Reference count */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_RP2040_I2C0
|
||||
static struct rp2040_i2cdev_s g_i2c0dev =
|
||||
{
|
||||
.port = 0,
|
||||
.base = RP2040_I2C0_BASE,
|
||||
.irqid = RP2040_I2C0_IRQ,
|
||||
.refs = 0,
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_RP2040_I2C1
|
||||
static struct rp2040_i2cdev_s g_i2c1dev =
|
||||
{
|
||||
.port = 1,
|
||||
.base = RP2040_I2C1_BASE,
|
||||
.irqid = RP2040_I2C1_IRQ,
|
||||
.refs = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static inline int i2c_takesem(FAR sem_t *sem);
|
||||
static inline int i2c_givesem(FAR sem_t *sem);
|
||||
|
||||
static inline uint32_t i2c_reg_read(struct rp2040_i2cdev_s *priv,
|
||||
uint32_t offset);
|
||||
static inline void i2c_reg_write(struct rp2040_i2cdev_s *priv,
|
||||
uint32_t offset,
|
||||
uint32_t val);
|
||||
static inline void i2c_reg_rmw(struct rp2040_i2cdev_s *dev,
|
||||
uint32_t offset,
|
||||
uint32_t val, uint32_t mask);
|
||||
|
||||
static int rp2040_i2c_disable(struct rp2040_i2cdev_s *priv);
|
||||
static void rp2040_i2c_enable(struct rp2040_i2cdev_s *priv);
|
||||
|
||||
static int rp2040_i2c_interrupt(int irq, FAR void *context, FAR void *arg);
|
||||
static void rp2040_i2c_timeout(wdparm_t arg);
|
||||
static void rp2040_i2c_setfrequency(struct rp2040_i2cdev_s *priv,
|
||||
uint32_t frequency);
|
||||
static int rp2040_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
FAR struct i2c_msg_s *msgs, int count);
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
static int rp2040_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: i2c_takesem
|
||||
****************************************************************************/
|
||||
|
||||
static inline int i2c_takesem(FAR sem_t *sem)
|
||||
{
|
||||
return nxsem_wait_uninterruptible(sem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: i2c_givesem
|
||||
****************************************************************************/
|
||||
|
||||
static inline int i2c_givesem(FAR sem_t *sem)
|
||||
{
|
||||
return nxsem_post(sem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* I2C device operations
|
||||
****************************************************************************/
|
||||
|
||||
struct i2c_ops_s rp2040_i2c_ops =
|
||||
{
|
||||
.transfer = rp2040_i2c_transfer,
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
.reset = rp2040_i2c_reset,
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_setfrequency
|
||||
*
|
||||
* Description:
|
||||
* Set the frequency for the next transfer
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void rp2040_i2c_setfrequency(struct rp2040_i2cdev_s *priv,
|
||||
uint32_t frequency)
|
||||
{
|
||||
int32_t lcnt;
|
||||
int32_t hcnt;
|
||||
uint64_t lcnt64;
|
||||
uint64_t hcnt64;
|
||||
uint64_t speed;
|
||||
uint64_t t_low;
|
||||
uint64_t t_high;
|
||||
uint32_t base = BOARD_PERI_FREQ;
|
||||
uint32_t spklen;
|
||||
|
||||
ASSERT(base);
|
||||
|
||||
if ((priv->frequency == frequency) && (priv->base_freq == base))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
priv->frequency = frequency;
|
||||
priv->base_freq = base;
|
||||
|
||||
base /= 1000;
|
||||
|
||||
if (frequency <= 100000)
|
||||
{
|
||||
t_low = 4700000;
|
||||
t_high = 4000000;
|
||||
}
|
||||
else if (frequency <= 400000)
|
||||
{
|
||||
t_low = 1300000;
|
||||
t_high = 600000;
|
||||
}
|
||||
else
|
||||
{
|
||||
t_low = 500000;
|
||||
t_high = 260000;
|
||||
}
|
||||
|
||||
if (frequency > 100000)
|
||||
{
|
||||
if (base < 20032)
|
||||
{
|
||||
spklen = 1;
|
||||
}
|
||||
else if (base < 40064)
|
||||
{
|
||||
spklen = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
spklen = 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spklen = 1;
|
||||
}
|
||||
|
||||
lcnt64 = (t_low + 6500ull / 20000ull) * base;
|
||||
lcnt = ((lcnt64 + 999999999ull) / 1000000000ull) - 1; /* ceil */
|
||||
lcnt = lcnt < 8 ? 8 : lcnt;
|
||||
|
||||
hcnt64 = (t_high - 6500ull) * base;
|
||||
hcnt = ((hcnt64 + 999999999ull) / 1000000000ull) - 6 - spklen; /* ceil */
|
||||
hcnt = hcnt < 6 ? 6 : hcnt;
|
||||
|
||||
speed =
|
||||
1000000000000000000ull /
|
||||
(((lcnt + 1) * 1000000000000ull +
|
||||
(hcnt + 6 + spklen) * 1000000000000ull) / base +
|
||||
20000ull / 1000ull * 1000000ull);
|
||||
|
||||
if (speed > (frequency * 1000ull))
|
||||
{
|
||||
uint64_t adj;
|
||||
adj = ((1000000000000000000ull / (frequency * 1000ull)) -
|
||||
(1000000000000000000ull / speed)) *
|
||||
base;
|
||||
hcnt += (adj + 999999999999ull) / 1000000000000ull;
|
||||
}
|
||||
|
||||
/* use FS register in SS and FS mode */
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_FS_SCL_HCNT_OFFSET, hcnt);
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_FS_SCL_LCNT_OFFSET, lcnt);
|
||||
i2c_reg_rmw(priv, RP2040_I2C_IC_CON_OFFSET,
|
||||
RP2040_I2C_IC_CON_SPEED_FAST,
|
||||
RP2040_I2C_IC_CON_SPEED_MASK);
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_FS_SPKLEN_OFFSET, spklen);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_timeout
|
||||
*
|
||||
* Description:
|
||||
* Watchdog timer for timeout of I2C operation
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void rp2040_i2c_timeout(wdparm_t arg)
|
||||
{
|
||||
struct rp2040_i2cdev_s *priv = (struct rp2040_i2cdev_s *)arg;
|
||||
irqstate_t flags = enter_critical_section();
|
||||
|
||||
priv->error = -ENODEV;
|
||||
i2c_givesem(&priv->wait);
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_drainrxfifo
|
||||
*
|
||||
* Description:
|
||||
* Receive I2C data
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void rp2040_i2c_drainrxfifo(struct rp2040_i2cdev_s *priv)
|
||||
{
|
||||
struct i2c_msg_s *msg = priv->msgs;
|
||||
uint32_t status;
|
||||
uint32_t dat;
|
||||
ssize_t i;
|
||||
|
||||
DEBUGASSERT(msg != NULL);
|
||||
|
||||
status = i2c_reg_read(priv, RP2040_I2C_IC_STATUS_OFFSET);
|
||||
|
||||
for (i = 0; i < priv->rw_size && status & RP2040_I2C_IC_STATUS_RFNE; i++)
|
||||
{
|
||||
dat = i2c_reg_read(priv, RP2040_I2C_IC_DATA_CMD_OFFSET);
|
||||
msg->buffer[priv->reg_buff_offset + i] = dat & 0xff;
|
||||
status = i2c_reg_read(priv, RP2040_I2C_IC_STATUS_OFFSET);
|
||||
}
|
||||
|
||||
priv->reg_buff_offset += priv->rw_size;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_interrupt
|
||||
*
|
||||
* Description:
|
||||
* The I2C Interrupt Handler
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int rp2040_i2c_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
FAR struct rp2040_i2cdev_s *priv = (FAR struct rp2040_i2cdev_s *)arg;
|
||||
uint32_t state;
|
||||
int ret;
|
||||
|
||||
state = i2c_reg_read(priv, RP2040_I2C_IC_INTR_STAT_OFFSET);
|
||||
|
||||
if (state & RP2040_I2C_IC_INTR_STAT_R_TX_ABRT)
|
||||
{
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_TX_ABRT_OFFSET);
|
||||
priv->error = -ENODEV;
|
||||
}
|
||||
|
||||
if (state & RP2040_I2C_IC_INTR_STAT_R_TX_OVER)
|
||||
{
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_TX_OVER_OFFSET);
|
||||
priv->error = -EIO;
|
||||
}
|
||||
|
||||
if (state & RP2040_I2C_IC_INTR_STAT_R_RX_OVER)
|
||||
{
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_RX_OVER_OFFSET);
|
||||
priv->error = -EIO;
|
||||
}
|
||||
|
||||
if (state & RP2040_I2C_IC_INTR_STAT_R_RX_UNDER)
|
||||
{
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_RX_UNDER_OFFSET);
|
||||
priv->error = -EIO;
|
||||
}
|
||||
|
||||
if (state & RP2040_I2C_IC_INTR_STAT_R_TX_EMPTY)
|
||||
{
|
||||
/* TX_EMPTY is automatically cleared by hardware
|
||||
* when the buffer level goes above the threshold.
|
||||
*/
|
||||
|
||||
i2c_reg_rmw(priv, RP2040_I2C_IC_INTR_MASK_OFFSET,
|
||||
0, RP2040_I2C_IC_INTR_MASK_M_TX_EMPTY);
|
||||
}
|
||||
|
||||
if (state & RP2040_I2C_IC_INTR_STAT_R_RX_FULL)
|
||||
{
|
||||
/* RX_FULL is automatically cleared by hardware
|
||||
* when the buffer level goes below the threshold.
|
||||
*/
|
||||
|
||||
i2c_reg_rmw(priv, RP2040_I2C_IC_INTR_MASK_OFFSET,
|
||||
0, RP2040_I2C_IC_INTR_MASK_M_RX_FULL);
|
||||
rp2040_i2c_drainrxfifo(priv);
|
||||
}
|
||||
|
||||
if (state & RP2040_I2C_IC_INTR_STAT_R_STOP_DET)
|
||||
{
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_STOP_DET_OFFSET);
|
||||
}
|
||||
|
||||
if ((priv->error) || (state & RP2040_I2C_IC_INTR_STAT_R_TX_EMPTY) ||
|
||||
(state & RP2040_I2C_IC_INTR_STAT_R_RX_FULL))
|
||||
{
|
||||
/* Failure of wd_cancel() means that the timer expired.
|
||||
* In this case, nxsem_post() has already been called.
|
||||
* Therefore, call nxsem_post() only when wd_cancel() succeeds.
|
||||
*/
|
||||
|
||||
ret = wd_cancel(&priv->timeout);
|
||||
if (ret == OK)
|
||||
{
|
||||
i2c_givesem(&priv->wait);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_receive
|
||||
*
|
||||
* Description:
|
||||
* Receive data from I2C bus.
|
||||
* Prohibit all interrupt because the STOP condition might happen
|
||||
* if the interrupt occurs when the writing request.
|
||||
* Actual receiving data is in RX_FULL interrupt handler.
|
||||
*
|
||||
* TODO : The argument "last" is not used.
|
||||
****************************************************************************/
|
||||
|
||||
static int rp2040_i2c_receive(struct rp2040_i2cdev_s *priv, int last)
|
||||
{
|
||||
struct i2c_msg_s *msg = priv->msgs;
|
||||
int i;
|
||||
int en;
|
||||
ssize_t msg_length;
|
||||
irqstate_t flags;
|
||||
|
||||
priv->reg_buff_offset = 0;
|
||||
|
||||
DEBUGASSERT(msg != NULL);
|
||||
|
||||
for (msg_length = msg->length; msg_length > 0; msg_length -= priv->rw_size)
|
||||
{
|
||||
if (msg_length <= I2C_FIFO_MAX_SIZE)
|
||||
{
|
||||
priv->rw_size = msg_length;
|
||||
en = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->rw_size = I2C_FIFO_MAX_SIZE;
|
||||
en = 0;
|
||||
}
|
||||
|
||||
/* update threshold value of the receive buffer */
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_RX_TL_OFFSET, priv->rw_size - 1);
|
||||
|
||||
for (i = 0; i < priv->rw_size - 1; i++)
|
||||
{
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_DATA_CMD_OFFSET,
|
||||
RP2040_I2C_IC_DATA_CMD_CMD);
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
wd_start(&priv->timeout, I2C_TIMEOUT,
|
||||
rp2040_i2c_timeout, (wdparm_t)priv);
|
||||
|
||||
/* Set stop flag for indicate the last data */
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_DATA_CMD_OFFSET,
|
||||
RP2040_I2C_IC_DATA_CMD_CMD |
|
||||
(en ? RP2040_I2C_IC_DATA_CMD_STOP : 0));
|
||||
|
||||
i2c_reg_rmw(priv, RP2040_I2C_IC_INTR_MASK_OFFSET,
|
||||
RP2040_I2C_IC_INTR_STAT_R_RX_FULL,
|
||||
RP2040_I2C_IC_INTR_STAT_R_RX_FULL);
|
||||
leave_critical_section(flags);
|
||||
i2c_takesem(&priv->wait);
|
||||
|
||||
if (priv->error != OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_send
|
||||
*
|
||||
* Description:
|
||||
* Send data to I2C bus.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int rp2040_i2c_send(struct rp2040_i2cdev_s *priv, int last)
|
||||
{
|
||||
struct i2c_msg_s *msg = priv->msgs;
|
||||
ssize_t i;
|
||||
irqstate_t flags;
|
||||
|
||||
DEBUGASSERT(msg != NULL);
|
||||
|
||||
for (i = 0; i < msg->length - 1; i++)
|
||||
{
|
||||
while (!(i2c_reg_read(priv, RP2040_I2C_IC_STATUS_OFFSET)
|
||||
& RP2040_I2C_IC_STATUS_TFNF))
|
||||
;
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_DATA_CMD_OFFSET,
|
||||
(uint32_t)msg->buffer[i]);
|
||||
}
|
||||
|
||||
while (!(i2c_reg_read(priv, RP2040_I2C_IC_STATUS_OFFSET)
|
||||
& RP2040_I2C_IC_STATUS_TFNF))
|
||||
;
|
||||
|
||||
flags = enter_critical_section();
|
||||
wd_start(&priv->timeout, I2C_TIMEOUT,
|
||||
rp2040_i2c_timeout, (wdparm_t)priv);
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_DATA_CMD_OFFSET,
|
||||
(uint32_t)msg->buffer[i] |
|
||||
(last ? RP2040_I2C_IC_DATA_CMD_STOP : 0));
|
||||
|
||||
/* Enable TX_EMPTY interrupt for determine transfer done. */
|
||||
|
||||
i2c_reg_rmw(priv, RP2040_I2C_IC_INTR_MASK_OFFSET,
|
||||
RP2040_I2C_IC_INTR_STAT_R_TX_EMPTY,
|
||||
RP2040_I2C_IC_INTR_STAT_R_TX_EMPTY);
|
||||
leave_critical_section(flags);
|
||||
|
||||
i2c_takesem(&priv->wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_transfer
|
||||
*
|
||||
* Description:
|
||||
* Perform a sequence of I2C transfers
|
||||
*
|
||||
* TODO: Multiple i2c_msg_s read operations with the same address are not
|
||||
* currently guaranteed.
|
||||
****************************************************************************/
|
||||
|
||||
static int rp2040_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
FAR struct i2c_msg_s *msgs, int count)
|
||||
{
|
||||
struct rp2040_i2cdev_s *priv = (struct rp2040_i2cdev_s *)dev;
|
||||
int i;
|
||||
int ret = 0;
|
||||
int semval = 0;
|
||||
int addr = -1;
|
||||
static int wostop = 0;
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
|
||||
/* Get exclusive access to the I2C bus */
|
||||
|
||||
i2c_takesem(&priv->mutex);
|
||||
|
||||
/* Check wait semaphore value. If the value is not 0, the transfer can not
|
||||
* be performed normally.
|
||||
*/
|
||||
|
||||
ret = nxsem_get_value(&priv->wait, &semval);
|
||||
DEBUGASSERT(ret == OK && semval == 0);
|
||||
|
||||
for (i = 0; i < count; i++, msgs++)
|
||||
{
|
||||
/* Pass msg descriptor via device context */
|
||||
|
||||
priv->msgs = msgs;
|
||||
priv->error = OK;
|
||||
|
||||
if ((addr != msgs->addr) && !wostop)
|
||||
{
|
||||
rp2040_i2c_disable(priv);
|
||||
|
||||
rp2040_i2c_setfrequency(priv, msgs->frequency);
|
||||
|
||||
i2c_reg_rmw(priv, RP2040_I2C_IC_CON_OFFSET,
|
||||
RP2040_I2C_IC_CON_IC_RESTART_EN,
|
||||
RP2040_I2C_IC_CON_IC_RESTART_EN);
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_TAR_OFFSET, msgs->addr & 0x7f);
|
||||
|
||||
rp2040_i2c_enable(priv);
|
||||
addr = msgs->addr;
|
||||
}
|
||||
|
||||
if (msgs->flags & I2C_M_NOSTOP)
|
||||
{
|
||||
/* Don't send stop condition even if the last data */
|
||||
|
||||
wostop = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
wostop = 0;
|
||||
}
|
||||
|
||||
if (msgs->flags & I2C_M_READ)
|
||||
{
|
||||
ret = rp2040_i2c_receive(priv, (wostop) ? 0 : (i + 1 == count));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = rp2040_i2c_send(priv, (wostop) ? 0 : (i + 1 == count));
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (priv->error != OK)
|
||||
{
|
||||
ret = priv->error;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear msg descriptor for prevent illegal access in interrupt */
|
||||
|
||||
priv->msgs = NULL;
|
||||
}
|
||||
|
||||
if (!wostop)
|
||||
{
|
||||
rp2040_i2c_disable(priv);
|
||||
}
|
||||
|
||||
i2c_givesem(&priv->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2c_reset
|
||||
*
|
||||
* Description:
|
||||
* Perform an I2C bus reset in an attempt to break loose stuck I2C devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
static int rp2040_i2c_reset(FAR struct i2c_master_s *dev)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_I2C_RESET */
|
||||
|
||||
static inline uint32_t i2c_reg_read(struct rp2040_i2cdev_s *priv,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(priv->base + offset);
|
||||
}
|
||||
|
||||
static inline void i2c_reg_write(struct rp2040_i2cdev_s *priv,
|
||||
uint32_t offset, uint32_t val)
|
||||
{
|
||||
putreg32(val, priv->base + offset);
|
||||
}
|
||||
|
||||
static inline void i2c_reg_rmw(struct rp2040_i2cdev_s *priv, uint32_t offset,
|
||||
uint32_t val, uint32_t mask)
|
||||
{
|
||||
modbits_reg32(val, mask, priv->base + offset);
|
||||
}
|
||||
|
||||
static int rp2040_i2c_disable(struct rp2040_i2cdev_s *priv)
|
||||
{
|
||||
int retry = 25000;
|
||||
uint32_t stat;
|
||||
|
||||
/* disable all interrupt */
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_INTR_MASK_OFFSET, 0x0);
|
||||
|
||||
/* clear all interrupt status */
|
||||
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_INTR_OFFSET);
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_ENABLE_OFFSET, 0);
|
||||
|
||||
do
|
||||
{
|
||||
stat = i2c_reg_read(priv, RP2040_I2C_IC_ENABLE_STATUS_OFFSET);
|
||||
}
|
||||
while (--retry && (stat & RP2040_I2C_IC_ENABLE_STATUS_IC_EN));
|
||||
|
||||
if (!retry)
|
||||
{
|
||||
i2cerr("i2c wait timeout.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* clear all interrupt status again */
|
||||
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_INTR_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rp2040_i2c_enable(struct rp2040_i2cdev_s *priv)
|
||||
{
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_INTR_MASK_OFFSET, I2C_INTR_ENABLE);
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_ENABLE_OFFSET, 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2cbus_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialise an I2C device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct i2c_master_s *rp2040_i2cbus_initialize(int port)
|
||||
{
|
||||
struct rp2040_i2cdev_s *priv;
|
||||
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
#ifdef CONFIG_RP2040_I2C0
|
||||
if (port == 0)
|
||||
{
|
||||
priv = &g_i2c0dev;
|
||||
priv->dev.ops = &rp2040_i2c_ops;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef CONFIG_RP2040_I2C1
|
||||
if (port == 1)
|
||||
{
|
||||
priv = &g_i2c1dev;
|
||||
priv->dev.ops = &rp2040_i2c_ops;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
leave_critical_section(flags);
|
||||
i2cerr("I2C Only support 0,1\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
priv->refs++;
|
||||
|
||||
/* Test if already initialized or not */
|
||||
|
||||
if (1 < priv->refs)
|
||||
{
|
||||
leave_critical_section(flags);
|
||||
return &priv->dev;
|
||||
}
|
||||
|
||||
priv->port = port;
|
||||
priv->frequency = 0;
|
||||
|
||||
priv->base_freq = BOARD_PERI_FREQ;
|
||||
|
||||
rp2040_i2c_disable(priv);
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_INTR_MASK_OFFSET, 0x00);
|
||||
i2c_reg_read(priv, RP2040_I2C_IC_CLR_INTR_OFFSET);
|
||||
|
||||
/* set threshold level of the Rx/Tx FIFO */
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_RX_TL_OFFSET, 0xff);
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_TX_TL_OFFSET, 0);
|
||||
|
||||
/* set hold time for margin */
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_SDA_HOLD_OFFSET, 1);
|
||||
|
||||
i2c_reg_write(priv, RP2040_I2C_IC_CON_OFFSET,
|
||||
(RP2040_I2C_IC_CON_IC_SLAVE_DISABLE |
|
||||
RP2040_I2C_IC_CON_MASTER_MODE |
|
||||
RP2040_I2C_IC_CON_TX_EMPTY_CTRL));
|
||||
rp2040_i2c_setfrequency(priv, I2C_DEFAULT_FREQUENCY);
|
||||
|
||||
leave_critical_section(flags);
|
||||
|
||||
nxsem_init(&priv->mutex, 0, 1);
|
||||
nxsem_init(&priv->wait, 0, 0);
|
||||
nxsem_set_protocol(&priv->wait, SEM_PRIO_NONE);
|
||||
|
||||
/* Attach Interrupt Handler */
|
||||
|
||||
irq_attach(priv->irqid, rp2040_i2c_interrupt, priv);
|
||||
|
||||
/* Enable Interrupt Handler */
|
||||
|
||||
up_enable_irq(priv->irqid);
|
||||
|
||||
return &priv->dev;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2cbus_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* Uninitialise an I2C device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rp2040_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
|
||||
{
|
||||
struct rp2040_i2cdev_s *priv = (struct rp2040_i2cdev_s *)dev;
|
||||
|
||||
/* Decrement reference count and check for underflow */
|
||||
|
||||
if (priv->refs == 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
if (--priv->refs)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
rp2040_i2c_disable(priv);
|
||||
|
||||
up_disable_irq(priv->irqid);
|
||||
irq_detach(priv->irqid);
|
||||
|
||||
wd_cancel(&priv->timeout);
|
||||
nxsem_destroy(&priv->mutex);
|
||||
nxsem_destroy(&priv->wait);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RP2040_I2C */
|
87
arch/arm/src/rp2040/rp2040_i2c.h
Normal file
87
arch/arm/src/rp2040/rp2040_i2c.h
Normal file
@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/rp2040_i2c.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_RP2040_RP2040_I2C_H
|
||||
#define __ARCH_ARM_SRC_RP2040_RP2040_I2C_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
#include "hardware/rp2040_i2c.h"
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2cbus_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the selected I2C port. And return a unique instance of struct
|
||||
* struct i2c_master_s. This function may be called to obtain multiple
|
||||
* instances of the interface, each of which may be set up with a
|
||||
* different frequency and slave address.
|
||||
*
|
||||
* Input Parameter:
|
||||
* Port number (for hardware that has multiple I2C interfaces)
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid I2C device structure reference on success; a NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct i2c_master_s *rp2040_i2cbus_initialize(int port);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_i2cbus_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* De-initialize the selected I2C port, and power down the device.
|
||||
*
|
||||
* Input Parameter:
|
||||
* Device structure as returned by the rp2040_i2cbus_initialize()
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, ERROR when internal reference count mismatch or dev
|
||||
* points to invalid hardware device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rp2040_i2cbus_uninitialize(FAR struct i2c_master_s *dev);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_RP2040_I2C_H */
|
Loading…
Reference in New Issue
Block a user