mirror of
https://github.com/apache/nuttx.git
synced 2026-08-13 16:35:21 +00:00
arch/arm/rtl8721dx: add shared Ameba I2C driver
Add a shared NuttX I2C master lower-half for the Realtek Ameba I2C controllers (I2C0/I2C1) in arch/arm/src/common/ameba, driven through the SDK fwlib in polling mode. Per-chip wiring (controller count, register bases, clock masks, crossbar pad-mux codes and the fwlib I2C_InitTypeDef layout) lives in arch/arm/src/rtl8721dx/ameba_i2c_chip.h so a port to the other Ameba chips only supplies a same-named header. Each controller registers as /dev/i2cN from pke8721daf bring-up through the stock I2C character driver; a dedicated `i2c` defconfig drives the i2ctool for validation. Assisted-by: Claude <noreply@anthropic.com> Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
This commit is contained in:
parent
9b02dead5d
commit
dfc55c9bbe
14 changed files with 1011 additions and 1 deletions
|
|
@ -55,4 +55,18 @@ config AMEBA_UART_TXBUFSIZE
|
|||
|
||||
endif # AMEBA_UART
|
||||
|
||||
config AMEBA_I2C
|
||||
bool "I2C"
|
||||
default n
|
||||
select I2C
|
||||
select I2C_DRIVER
|
||||
---help---
|
||||
Expose the Ameba I2C controllers (I2C0/I2C1) as NuttX I2C master
|
||||
buses at /dev/i2cN. The board selects which controller is used and
|
||||
its SCL/SDA pads in its bring-up code.
|
||||
|
||||
The driver (arch/arm/src/common/ameba/ameba_i2c.c) sits on the SDK
|
||||
fwlib register layer and drives the DesignWare I2C block in polling
|
||||
mode.
|
||||
|
||||
endmenu # Ameba Peripheral Support
|
||||
|
|
|
|||
600
arch/arm/src/common/ameba/ameba_i2c.c
Normal file
600
arch/arm/src/common/ameba/ameba_i2c.c
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/common/ameba/ameba_i2c.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
****************************************************************************/
|
||||
|
||||
/* NuttX I2C master lower half for the Realtek Ameba I2C controllers (I2C0
|
||||
* and I2C1). Each controller is registered from board bring-up and appears
|
||||
* as /dev/i2cN through the stock I2C character driver (i2c_register()).
|
||||
*
|
||||
* The controller is a Synopsys DesignWare I2C block programmed through the
|
||||
* SDK fwlib I2C API in polling mode (no interrupts): I2C_Init() programs the
|
||||
* speed/target, and I2C_MasterWrite()/Read()/RepeatRead() drive the FIFO and
|
||||
* block until the transfer completes or the poll times out.
|
||||
*
|
||||
* Unlike the UART fwlib, which runs from on-chip ROM and resolves the secure
|
||||
* register alias itself via TrustZone_IsSecure(), the I2C fwlib routines are
|
||||
* compiled from ram_common/ameba_i2c.c (see AMEBA_FWLIB_SRCS) and use the
|
||||
* register pointer they are handed without any secure conversion. NuttX
|
||||
* runs on the KM4 core in the SECURE state, yet the I2C block only responds
|
||||
* on its NON-secure alias (see the note at AMEBA_I2C_BASES in
|
||||
* ameba_i2c_chip.h), so this driver hands the fwlib those non-secure bases.
|
||||
*
|
||||
* The chip-specific wiring (controller count, register bases, clock masks,
|
||||
* pad-mux codes and the fwlib I2C_InitTypeDef layout) lives in the per-chip
|
||||
* ameba_i2c_chip.h. To keep the vendor headers out of the NuttX include
|
||||
* world, the few fwlib symbols and that struct layout used here are declared
|
||||
* locally rather than pulled in from <ameba_i2c.h>.
|
||||
*/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
#include "ameba_i2c.h"
|
||||
#include "ameba_i2c_chip.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The register bases, peripheral-clock masks, crossbar pad-mux codes,
|
||||
* controller count (AMEBA_NI2C) and I2C_InitTypeDef layout
|
||||
* (AMEBA_I2C_HAS_DMA_FIELDS) all come from the per-chip ameba_i2c_chip.h.
|
||||
* Everything below is common to every current Ameba chip.
|
||||
*/
|
||||
|
||||
#define AMEBA_GPIO_PUPD_UP 0x2 /* GPIO_PuPd_UP */
|
||||
|
||||
/* fwlib I2C_InitTypeDef field values (I2C_ADDR_*, I2C_*_MODE, ameba_i2c.h).
|
||||
* These are identical on every Ameba chip audited, so they stay here rather
|
||||
* than in the per-chip header.
|
||||
*/
|
||||
|
||||
#define AMEBA_I2C_ADDR_7BIT 0x0 /* I2C_ADDR_7BIT */
|
||||
#define AMEBA_I2C_ADDR_10BIT 0x1 /* I2C_ADDR_10BIT */
|
||||
|
||||
#define AMEBA_I2C_SS_MODE 0x1 /* I2C_SS_MODE (<= 100 kHz) */
|
||||
#define AMEBA_I2C_FS_MODE 0x2 /* I2C_FS_MODE (<= 400 kHz) */
|
||||
#define AMEBA_I2C_HS_MODE 0x3 /* I2C_HS_MODE (I2C1 only) */
|
||||
|
||||
#define AMEBA_I2C_MASTER_MODE 0x1 /* I2C_MASTER_MODE */
|
||||
|
||||
/* IC_RAW_INTR_STAT.TX_ABRT and the matching IC_CLR_TX_ABRT selector for
|
||||
* I2C_ClearINT(). A transmit abort latches whenever an address or data
|
||||
* byte goes unacknowledged (among other causes); the fwlib master helpers
|
||||
* can miss it and still return the full byte count, so this driver checks
|
||||
* it after each transfer to surface a NAK. It sits at bit 6 of both
|
||||
* registers on every Ameba chip audited (amebadplus/smart/lite/green2/
|
||||
* RTL8720F), so it stays here rather than in the per-chip header.
|
||||
*/
|
||||
|
||||
#define AMEBA_I2C_TX_ABRT (1u << 6) /* IC_RAW_INTR_STAT TX_ABRT */
|
||||
#define AMEBA_I2C_R_TX_ABRT (1u << 6) /* I2C_ClearINT() TX_ABRT sel. */
|
||||
|
||||
/* IC_STATUS.TFNF (transmit FIFO not full) and the bounded spin used to wait
|
||||
* for a free FIFO slot while pushing the leading bytes of a chained write
|
||||
* (an I2C_M_NOSTOP segment). TFNF sits at bit 1 on every Ameba chip.
|
||||
*/
|
||||
|
||||
#define AMEBA_I2C_TFNF (1u << 1) /* IC_STATUS TFNF */
|
||||
#define AMEBA_I2C_FIFO_TIMEOUT 100000 /* ~loop guard, ample for 16 FIFO */
|
||||
|
||||
/* Second/third argument to fwlib "state" style APIs. */
|
||||
|
||||
#define AMEBA_DISABLE 0x0
|
||||
#define AMEBA_ENABLE 0x1
|
||||
|
||||
/* Default bus frequency used until the first transfer requests one. */
|
||||
|
||||
#define AMEBA_I2C_DEFAULT_FREQ I2C_SPEED_STANDARD
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Layout-compatible mirror of the fwlib I2C_InitTypeDef (all u32, same
|
||||
* order); passed by address to I2C_StructInit()/I2C_Init(). The leading
|
||||
* I2CIdx field is present on every Ameba chip audited (amebadplus/
|
||||
* amebasmart/amebalite/amebagreen2/RTL8720F), so it stays unconditional. A
|
||||
* single per-chip layout switch keeps this struct byte-for-byte identical to
|
||||
* the fwlib one: AMEBA_I2C_HAS_DMA_FIELDS gates the three DMA request-level
|
||||
* fields between I2CFilter and I2CAckAddr1, which only some chips carry.
|
||||
* See ameba_i2c_chip.h for the per-chip value.
|
||||
*/
|
||||
|
||||
struct ameba_i2c_init_s
|
||||
{
|
||||
uint32_t idx; /* I2CIdx */
|
||||
uint32_t master; /* I2CMaster */
|
||||
uint32_t addrmod; /* I2CAddrMod */
|
||||
uint32_t spdmod; /* I2CSpdMod */
|
||||
uint32_t rxtl; /* I2CRXTL */
|
||||
uint32_t txtl; /* I2CTXTL */
|
||||
uint32_t mstrestr; /* I2CMstReSTR */
|
||||
uint32_t mstgc; /* I2CMstGC */
|
||||
uint32_t mststartb; /* I2CMstStartB */
|
||||
uint32_t slvnoack; /* I2CSlvNoAck */
|
||||
uint32_t slvackgc; /* I2CSlvAckGC */
|
||||
uint32_t ackaddr; /* I2CAckAddr */
|
||||
uint32_t slvsetup; /* I2CSlvSetup */
|
||||
uint32_t sdahd; /* I2CSdaHd */
|
||||
uint32_t clk; /* I2CClk (kHz) */
|
||||
uint32_t ipclk; /* I2CIPClk (Hz) */
|
||||
uint32_t filter; /* I2CFilter */
|
||||
#ifdef AMEBA_I2C_HAS_DMA_FIELDS
|
||||
uint32_t txdmarqlv; /* I2CTxDMARqLv */
|
||||
uint32_t rxdmarqlv; /* I2CRxDMARqLv */
|
||||
uint32_t dmamod; /* I2CDMAMod */
|
||||
#endif
|
||||
uint32_t ackaddr1; /* I2CAckAddr1 */
|
||||
};
|
||||
|
||||
struct ameba_i2c_dev_s
|
||||
{
|
||||
struct i2c_master_s dev; /* I2C master lower half (must be first) */
|
||||
uintptr_t base; /* Non-secure I2C register base address */
|
||||
uint32_t periph; /* APBPeriph function mask (RCC arg 1) */
|
||||
uint32_t clk; /* APBPeriph clock mask (RCC arg 2) */
|
||||
uint32_t frequency; /* Currently programmed bus frequency (Hz) */
|
||||
uint16_t address; /* Currently programmed target address */
|
||||
uint8_t addrmod; /* Currently programmed AMEBA_I2C_ADDR_*BIT */
|
||||
uint8_t sclpin; /* SCL pad (AMEBA_PA()/AMEBA_PB() encoding) */
|
||||
uint8_t sdapin; /* SDA pad (AMEBA_PA()/AMEBA_PB() encoding) */
|
||||
uint8_t sclfid; /* Pin mux function code for the SCL pad */
|
||||
uint8_t sdafid; /* Pin mux function code for the SDA pad */
|
||||
mutex_t lock; /* Serializes bus access */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* SDK fwlib I2C/pin/clock API. The pin/clock helpers resolve to the on-chip
|
||||
* ROM symbol table; the I2C helpers are compiled into libameba_fwlib.a from
|
||||
* ram_common/ameba_i2c.c (see AMEBA_FWLIB_SRCS).
|
||||
*/
|
||||
|
||||
extern void RCC_PeriphClockCmd(uint32_t periph, uint32_t clock,
|
||||
uint8_t newstate);
|
||||
extern void Pinmux_Config(uint8_t pin, uint32_t func);
|
||||
extern void PAD_PullCtrl(uint8_t pin, uint8_t pull);
|
||||
extern void I2C_StructInit(struct ameba_i2c_init_s *init);
|
||||
extern void I2C_Init(void *i2cx, struct ameba_i2c_init_s *init);
|
||||
extern void I2C_Cmd(void *i2cx, uint8_t newstate);
|
||||
extern uint32_t I2C_MasterWrite(void *i2cx, uint8_t *buf, uint32_t len);
|
||||
extern uint32_t I2C_MasterRead(void *i2cx, uint8_t *buf, uint32_t len);
|
||||
extern uint32_t I2C_MasterRepeatRead(void *i2cx, uint8_t *wbuf,
|
||||
uint32_t wlen, uint8_t *rbuf,
|
||||
uint32_t rlen);
|
||||
extern uint32_t I2C_GetRawINT(void *i2cx);
|
||||
extern uint32_t I2C_ClearINT(void *i2cx, uint32_t intrbit);
|
||||
extern uint8_t I2C_CheckFlagState(void *i2cx, uint32_t flag);
|
||||
extern void I2C_MasterSend(void *i2cx, uint8_t *buf, uint8_t cmd,
|
||||
uint8_t stop, uint8_t restart);
|
||||
|
||||
/* I2C master lower-half operations. */
|
||||
|
||||
static int ameba_i2c_transfer(struct i2c_master_s *dev,
|
||||
struct i2c_msg_s *msgs, int count);
|
||||
static int ameba_i2c_setup(struct i2c_master_s *dev);
|
||||
static int ameba_i2c_shutdown(struct i2c_master_s *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct i2c_ops_s g_ameba_i2c_ops =
|
||||
{
|
||||
.transfer = ameba_i2c_transfer,
|
||||
.setup = ameba_i2c_setup,
|
||||
.shutdown = ameba_i2c_shutdown,
|
||||
};
|
||||
|
||||
/* Per-controller register base, peripheral function/clock masks and crossbar
|
||||
* pad-mux codes, indexed by controller number and supplied by the per-chip
|
||||
* ameba_i2c_chip.h. g_i2c_periph feeds the "function" arg and g_i2c_clk
|
||||
* the "clock" argument of RCC_PeriphClockCmd() (equal on this chip, distinct
|
||||
* on others).
|
||||
*/
|
||||
|
||||
static const uintptr_t g_i2c_base[AMEBA_NI2C] = AMEBA_I2C_BASES;
|
||||
static const uint32_t g_i2c_periph[AMEBA_NI2C] = AMEBA_I2C_APBPERIPH;
|
||||
static const uint32_t g_i2c_clk[AMEBA_NI2C] = AMEBA_I2C_APBPERIPH_CLK;
|
||||
static const uint8_t g_i2c_sclfid[AMEBA_NI2C] = AMEBA_I2C_SCLFID;
|
||||
static const uint8_t g_i2c_sdafid[AMEBA_NI2C] = AMEBA_I2C_SDAFID;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_reconfigure
|
||||
*
|
||||
* Description:
|
||||
* (Re)program the controller for a given target address, addressing mode
|
||||
* and bus frequency, and enable it. This is a comparatively heavy DW-IP
|
||||
* reconfiguration (the block must be disabled to change IC_TAR/speed), so
|
||||
* it runs only when one of those parameters changes between transfers.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_i2c_reconfigure(struct ameba_i2c_dev_s *priv,
|
||||
uint16_t address, uint8_t addrmod,
|
||||
uint32_t frequency)
|
||||
{
|
||||
struct ameba_i2c_init_s init;
|
||||
void *i2cx = (void *)priv->base;
|
||||
|
||||
memset(&init, 0, sizeof(init));
|
||||
I2C_StructInit(&init);
|
||||
|
||||
init.master = AMEBA_I2C_MASTER_MODE;
|
||||
init.addrmod = addrmod;
|
||||
init.ackaddr = address;
|
||||
|
||||
/* Enable RESTART so a combined write-then-read (I2C_MasterRepeatRead())
|
||||
* emits a true repeated START; the DW IP ignores the RESTART command bit
|
||||
* unless IC_CON.IC_RESTART_EN is set.
|
||||
*/
|
||||
|
||||
init.mstrestr = AMEBA_ENABLE;
|
||||
|
||||
if (frequency <= I2C_SPEED_STANDARD)
|
||||
{
|
||||
init.spdmod = AMEBA_I2C_SS_MODE;
|
||||
}
|
||||
else if (frequency <= I2C_SPEED_FAST)
|
||||
{
|
||||
init.spdmod = AMEBA_I2C_FS_MODE;
|
||||
}
|
||||
else
|
||||
{
|
||||
init.spdmod = AMEBA_I2C_HS_MODE;
|
||||
}
|
||||
|
||||
init.clk = frequency / 1000; /* fwlib expects the bus clock in kHz */
|
||||
|
||||
I2C_Cmd(i2cx, AMEBA_DISABLE);
|
||||
I2C_Init(i2cx, &init);
|
||||
I2C_Cmd(i2cx, AMEBA_ENABLE);
|
||||
|
||||
priv->address = address;
|
||||
priv->addrmod = addrmod;
|
||||
priv->frequency = frequency;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_aborted
|
||||
*
|
||||
* Description:
|
||||
* Return true if the controller latched a transmit abort during the last
|
||||
* transfer. The fwlib master helpers poll IC_STATUS.TFE, which the DW IP
|
||||
* also sets when it flushes the TX FIFO on an abort, so they can return
|
||||
* the full byte count even though the address (or a data byte) was never
|
||||
* acknowledged. Checking IC_RAW_INTR_STAT.TX_ABRT directly is the only
|
||||
* reliable way to detect that NAK. The abort is cleared here (reading
|
||||
* IC_CLR_TX_ABRT) so the block is left in a clean state.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool ameba_i2c_aborted(struct ameba_i2c_dev_s *priv)
|
||||
{
|
||||
void *i2cx = (void *)priv->base;
|
||||
|
||||
if ((I2C_GetRawINT(i2cx) & AMEBA_I2C_TX_ABRT) != 0)
|
||||
{
|
||||
I2C_ClearINT(i2cx, AMEBA_I2C_R_TX_ABRT);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_writeprefix
|
||||
*
|
||||
* Description:
|
||||
* Push the bytes of a non-terminating write segment (one flagged
|
||||
* I2C_M_NOSTOP) into the TX FIFO without asserting STOP. Because the DW
|
||||
* IP only issues a STOP when a byte carries the STOP bit, leaving it clear
|
||||
* keeps the current transaction open so the following segment continues
|
||||
* without a repeated START -- this is how I2C_M_NOSTOP/I2C_M_NOSTART are
|
||||
* honoured for chained writes such as the "register address + data" pair
|
||||
* emitted by "i2c set". The terminating segment is handled by the tested
|
||||
* I2C_MasterWrite(), which supplies the STOP and the final TFE wait.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ameba_i2c_writeprefix(struct ameba_i2c_dev_s *priv,
|
||||
const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
void *i2cx = (void *)priv->base;
|
||||
uint32_t i;
|
||||
uint32_t to;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
uint8_t byte = buf[i];
|
||||
|
||||
/* Wait for a free TX FIFO slot before pushing the next byte. */
|
||||
|
||||
for (to = AMEBA_I2C_FIFO_TIMEOUT;
|
||||
to > 0 && I2C_CheckFlagState(i2cx, AMEBA_I2C_TFNF) == 0; to--);
|
||||
|
||||
if (to == 0)
|
||||
{
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Write, no STOP, no RESTART: leave the transaction open. */
|
||||
|
||||
I2C_MasterSend(i2cx, &byte, 0, 0, 0);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_transfer
|
||||
*
|
||||
* Description:
|
||||
* Run a sequence of I2C messages on the bus. A write message immediately
|
||||
* followed by a read message to the same target is fused into a single
|
||||
* combined transaction with a repeated START. A write flagged
|
||||
* I2C_M_NOSTOP is chained to the following write segment(s) without an
|
||||
* intervening STOP (e.g. register address + data from "i2c set"). Every
|
||||
* other message is a standalone START..STOP write or read.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ameba_i2c_transfer(struct i2c_master_s *dev,
|
||||
struct i2c_msg_s *msgs, int count)
|
||||
{
|
||||
struct ameba_i2c_dev_s *priv = (struct ameba_i2c_dev_s *)dev;
|
||||
void *i2cx = (void *)priv->base;
|
||||
int ret = OK;
|
||||
int i;
|
||||
|
||||
if (msgs == NULL || count < 1)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&priv->lock);
|
||||
|
||||
for (i = 0; i < count; )
|
||||
{
|
||||
struct i2c_msg_s *msg = &msgs[i];
|
||||
uint8_t addrmod = (msg->flags & I2C_M_TEN) ?
|
||||
AMEBA_I2C_ADDR_10BIT : AMEBA_I2C_ADDR_7BIT;
|
||||
uint32_t freq = (msg->frequency != 0) ? msg->frequency :
|
||||
AMEBA_I2C_DEFAULT_FREQ;
|
||||
uint32_t done;
|
||||
|
||||
/* Reprogram the controller only when the target, addressing mode or
|
||||
* bus frequency differs from the running configuration.
|
||||
*/
|
||||
|
||||
if (msg->addr != priv->address || addrmod != priv->addrmod ||
|
||||
freq != priv->frequency)
|
||||
{
|
||||
ameba_i2c_reconfigure(priv, msg->addr, addrmod, freq);
|
||||
}
|
||||
|
||||
if ((msg->flags & I2C_M_READ) == 0 && (i + 1) < count &&
|
||||
(msgs[i + 1].flags & I2C_M_READ) != 0 &&
|
||||
msgs[i + 1].addr == msg->addr)
|
||||
{
|
||||
/* Write followed by read to the same target: one transaction with
|
||||
* a repeated START between the two phases.
|
||||
*/
|
||||
|
||||
struct i2c_msg_s *rd = &msgs[i + 1];
|
||||
|
||||
done = I2C_MasterRepeatRead(i2cx, msg->buffer, msg->length,
|
||||
rd->buffer, rd->length);
|
||||
if (ameba_i2c_aborted(priv))
|
||||
{
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (done != (uint32_t)rd->length)
|
||||
{
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
i += 2;
|
||||
}
|
||||
else if ((msg->flags & I2C_M_READ) != 0)
|
||||
{
|
||||
done = I2C_MasterRead(i2cx, msg->buffer, msg->length);
|
||||
|
||||
if (ameba_i2c_aborted(priv))
|
||||
{
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (done != (uint32_t)msg->length)
|
||||
{
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
else if ((msg->flags & I2C_M_NOSTOP) != 0)
|
||||
{
|
||||
/* Leading segment of a chained write (e.g. the register address
|
||||
* before the data in "i2c set"): push its bytes but keep the
|
||||
* transaction open so the next segment continues without a STOP.
|
||||
*/
|
||||
|
||||
ret = ameba_i2c_writeprefix(priv, msg->buffer, msg->length);
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
done = I2C_MasterWrite(i2cx, msg->buffer, msg->length);
|
||||
if (ameba_i2c_aborted(priv))
|
||||
{
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (done != (uint32_t)msg->length)
|
||||
{
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* A failed transfer can leave the DW IP with a latched TX abort; force a
|
||||
* full reconfiguration before the next transfer to clear it.
|
||||
*/
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
priv->frequency = 0;
|
||||
priv->address = 0xffff;
|
||||
}
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_setup
|
||||
*
|
||||
* Description:
|
||||
* Called by the I2C character driver on the first open. Gate the
|
||||
* peripheral clock and route the SCL/SDA pads to this controller; the
|
||||
* speed/target are programmed lazily on the first transfer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ameba_i2c_setup(struct i2c_master_s *dev)
|
||||
{
|
||||
struct ameba_i2c_dev_s *priv = (struct ameba_i2c_dev_s *)dev;
|
||||
|
||||
RCC_PeriphClockCmd(priv->periph, priv->clk, AMEBA_ENABLE);
|
||||
|
||||
Pinmux_Config(priv->sclpin, priv->sclfid);
|
||||
Pinmux_Config(priv->sdapin, priv->sdafid);
|
||||
PAD_PullCtrl(priv->sclpin, AMEBA_GPIO_PUPD_UP);
|
||||
PAD_PullCtrl(priv->sdapin, AMEBA_GPIO_PUPD_UP);
|
||||
|
||||
/* Force the first transfer to program the controller. */
|
||||
|
||||
priv->frequency = 0;
|
||||
priv->address = 0xffff;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_shutdown
|
||||
*
|
||||
* Description:
|
||||
* Called by the I2C character driver on the last close. Disable the
|
||||
* controller and gate its peripheral clock off.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int ameba_i2c_shutdown(struct i2c_master_s *dev)
|
||||
{
|
||||
struct ameba_i2c_dev_s *priv = (struct ameba_i2c_dev_s *)dev;
|
||||
|
||||
I2C_Cmd((void *)priv->base, AMEBA_DISABLE);
|
||||
RCC_PeriphClockCmd(priv->periph, priv->clk, AMEBA_DISABLE);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_register
|
||||
*
|
||||
* Description:
|
||||
* See ameba_i2c.h.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ameba_i2c_register(int bus, uint8_t sclpin, uint8_t sdapin)
|
||||
{
|
||||
struct ameba_i2c_dev_s *priv;
|
||||
int ret;
|
||||
|
||||
if (bus < 0 || bus >= AMEBA_NI2C)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct ameba_i2c_dev_s));
|
||||
if (priv == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->dev.ops = &g_ameba_i2c_ops;
|
||||
priv->base = g_i2c_base[bus];
|
||||
priv->periph = g_i2c_periph[bus];
|
||||
priv->clk = g_i2c_clk[bus];
|
||||
priv->sclpin = sclpin;
|
||||
priv->sdapin = sdapin;
|
||||
priv->sclfid = g_i2c_sclfid[bus];
|
||||
priv->sdafid = g_i2c_sdafid[bus];
|
||||
priv->address = 0xffff;
|
||||
nxmutex_init(&priv->lock);
|
||||
|
||||
ret = i2c_register(&priv->dev, bus);
|
||||
if (ret < 0)
|
||||
{
|
||||
_err("ERROR: i2c_register(/dev/i2c%d) failed: %d\n", bus, ret);
|
||||
nxmutex_destroy(&priv->lock);
|
||||
kmm_free(priv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
84
arch/arm/src/common/ameba/ameba_i2c.h
Normal file
84
arch/arm/src/common/ameba/ameba_i2c.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/common/ameba/ameba_i2c.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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_COMMON_AMEBA_AMEBA_I2C_H
|
||||
#define __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_I2C_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The Ameba I2C controllers exposed to NuttX as I2C master buses. The SCL
|
||||
* and SDA pads are given with the same AMEBA_PA()/AMEBA_PB() PinName code
|
||||
* used by the GPIO driver (see ameba_gpio.h); any pad can be routed to an
|
||||
* I2C bus through the pin mux.
|
||||
*/
|
||||
|
||||
#define AMEBA_I2C0 0
|
||||
#define AMEBA_I2C1 1
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_i2c_register
|
||||
*
|
||||
* Description:
|
||||
* Configure one Ameba I2C controller as a master bus and register it with
|
||||
* the NuttX I2C character driver at /dev/i2cN, where N is the bus number.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bus - The controller index, AMEBA_I2C0 or AMEBA_I2C1. Also used as
|
||||
* the /dev/i2cN minor number.
|
||||
* sclpin - The SCL pad, encoded with AMEBA_PA()/AMEBA_PB().
|
||||
* sdapin - The SDA pad, encoded with AMEBA_PA()/AMEBA_PB().
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ameba_i2c_register(int bus, uint8_t sclpin, uint8_t sdapin);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_I2C_H */
|
||||
|
|
@ -48,6 +48,10 @@ if(CONFIG_AMEBA_UART)
|
|||
list(APPEND SRCS ${AMEBA_COMMON}/ameba_uart.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_AMEBA_I2C)
|
||||
list(APPEND SRCS ${AMEBA_COMMON}/ameba_i2c.c)
|
||||
endif()
|
||||
|
||||
target_include_directories(arch PRIVATE ${AMEBA_COMMON})
|
||||
target_sources(arch PRIVATE ${SRCS})
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ ifeq ($(CONFIG_AMEBA_UART),y)
|
|||
CHIP_CSRCS += ameba_uart.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_AMEBA_I2C),y)
|
||||
CHIP_CSRCS += ameba_i2c.c
|
||||
endif
|
||||
|
||||
############################################################################
|
||||
# Realtek RTL8721Dx SDK integration
|
||||
#
|
||||
|
|
|
|||
|
|
@ -137,6 +137,15 @@ ifeq ($(CONFIG_AMEBA_UART),y)
|
|||
AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_uart.c
|
||||
endif
|
||||
|
||||
# I2C register layer. Unlike UART, the fwlib I2C API is NOT in ROM: the I2C
|
||||
# driver (arch/.../common/ameba/ameba_i2c.c) calls I2C_Init/StructInit/Cmd and
|
||||
# I2C_MasterWrite/Read/RepeatRead, all of which are compiled from this RAM
|
||||
# source and must be linked in (--gc-sections drops the unused DMA/interrupt
|
||||
# helpers).
|
||||
ifeq ($(CONFIG_AMEBA_I2C),y)
|
||||
AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_i2c.c
|
||||
endif
|
||||
|
||||
# -Wno-int-conversion: the vendored SDK passes NULL to irq_register()'s u32
|
||||
# "Data" (interrupt context) argument in many places -- an intentional
|
||||
# NULL-as-context idiom. Silence -Wint-conversion for the SDK fwlib sources
|
||||
|
|
|
|||
103
arch/arm/src/rtl8721dx/ameba_i2c_chip.h
Normal file
103
arch/arm/src/rtl8721dx/ameba_i2c_chip.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rtl8721dx/ameba_i2c_chip.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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_RTL8721DX_AMEBA_I2C_CHIP_H
|
||||
#define __ARCH_ARM_SRC_RTL8721DX_AMEBA_I2C_CHIP_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Per-chip I2C wiring for RTL8721DX (amebadplus). The shared driver
|
||||
* (arch/arm/src/common/ameba/ameba_i2c.c) includes this header to learn how
|
||||
* many I2C controllers the chip exposes and, for each, its register base,
|
||||
* peripheral-clock masks and crossbar pad-mux codes. It also learns the
|
||||
* chip's I2C_InitTypeDef layout through AMEBA_I2C_HAS_DMA_FIELDS.
|
||||
*
|
||||
* Contract for the other Ameba chips (amebalite / amebasmart / amebagreen2 /
|
||||
* RTL8720F): supply a same-named header on the chip include path with the
|
||||
* macros below. What differs per chip, from the fwlib audit:
|
||||
*
|
||||
* 1. Controller count and bases: 2 controllers on amebadplus / amebalite /
|
||||
* amebagreen2 / RTL8720F, 3 on amebasmart (its I2C0 lives in the LP
|
||||
* domain). The bases below are the NON-secure peripheral aliases; see
|
||||
* the note in ameba_i2c.c on why the secure alias must not be used.
|
||||
*
|
||||
* 2. APBPeriph "function" and "clock" masks are two separate lists because
|
||||
* RCC_PeriphClockCmd() takes them as distinct arguments. They are
|
||||
* equal on every current chip, but amebasmart encodes the bits
|
||||
* differently (bit25/26/27, group bit30=0) versus (bit30|bit10/11)
|
||||
* here, so each chip must supply its own values.
|
||||
*
|
||||
* 3. Pad mux: amebadplus / amebalite / amebagreen2 / RTL8720F use a
|
||||
* crossbar with a distinct function code per SCL/SDA signal (supplied
|
||||
* as two lists). amebasmart instead has a single generic
|
||||
* PINMUX_FUNCTION_I2C code (7) shared by every I2C pad; that chip fills
|
||||
* both the SCL and SDA lists with 7 and the driver needs no change.
|
||||
*
|
||||
* 4. I2C_InitTypeDef layout: amebadplus / amebagreen2 / RTL8720F carry
|
||||
* three DMA request-level fields (I2CTxDMARqLv / I2CRxDMARqLv /
|
||||
* I2CDMAMod) between I2CFilter and I2CAckAddr1 (21 u32 fields);
|
||||
* amebalite and amebasmart omit them (18 fields). Define
|
||||
* AMEBA_I2C_HAS_DMA_FIELDS to 1 when present so the driver's mirror
|
||||
* struct stays byte-for-byte identical to the fwlib struct that
|
||||
* I2C_StructInit()/I2C_Init() use.
|
||||
*/
|
||||
|
||||
#define AMEBA_NI2C 2
|
||||
|
||||
/* NON-secure I2C register bases (I2C0_REG_BASE / I2C1_REG_BASE). */
|
||||
|
||||
#define AMEBA_I2C_BASES { 0x41108000ul, 0x4110a000ul }
|
||||
|
||||
/* APBPeriph_I2Cx (function) and APBPeriph_I2Cx_CLOCK masks. Equal on this
|
||||
* chip; kept as two lists so chips where they differ can supply both.
|
||||
*/
|
||||
|
||||
#define AMEBA_I2C_APBPERIPH \
|
||||
{ (((uint32_t)1 << 30) | ((uint32_t)1 << 10)), \
|
||||
(((uint32_t)1 << 30) | ((uint32_t)1 << 11)) }
|
||||
|
||||
#define AMEBA_I2C_APBPERIPH_CLK \
|
||||
{ (((uint32_t)1 << 30) | ((uint32_t)1 << 10)), \
|
||||
(((uint32_t)1 << 30) | ((uint32_t)1 << 11)) }
|
||||
|
||||
/* Crossbar pad-mux function codes (PINMUX_FUNCTION_I2Cx_SCL/SDA), indexed by
|
||||
* controller. On a chip with one generic I2C code, set both to that code.
|
||||
*/
|
||||
|
||||
#define AMEBA_I2C_SCLFID { 48, 50 } /* I2C0_SCL, I2C1_SCL */
|
||||
#define AMEBA_I2C_SDAFID { 49, 51 } /* I2C0_SDA, I2C1_SDA */
|
||||
|
||||
/* The amebadplus I2C_InitTypeDef carries the DMA request-level fields. */
|
||||
|
||||
#define AMEBA_I2C_HAS_DMA_FIELDS 1
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_RTL8721DX_AMEBA_I2C_CHIP_H */
|
||||
51
boards/arm/rtl8721dx/pke8721daf/configs/i2c/defconfig
Normal file
51
boards/arm/rtl8721dx/pke8721daf/configs/i2c/defconfig
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# This file is autogenerated: PLEASE DO NOT EDIT IT.
|
||||
#
|
||||
# You can use "make menuconfig" to make any modifications to the installed .config file.
|
||||
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
|
||||
# modifications.
|
||||
#
|
||||
# CONFIG_DEBUG_WARN is not set
|
||||
CONFIG_AMEBA_I2C=y
|
||||
CONFIG_ARCH="arm"
|
||||
CONFIG_ARCH_BOARD="pke8721daf"
|
||||
CONFIG_ARCH_BOARD_PKE8721DAF=y
|
||||
CONFIG_ARCH_CHIP="rtl8721dx"
|
||||
CONFIG_ARCH_CHIP_RTL8721DX=y
|
||||
CONFIG_ARCH_INTERRUPTSTACK=2048
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_ARMV8M_SYSTICK=y
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_DEBUG_ASSERTIONS=y
|
||||
CONFIG_DEBUG_FEATURES=y
|
||||
CONFIG_DEBUG_FULLOPT=y
|
||||
CONFIG_DEBUG_SYMBOLS=y
|
||||
CONFIG_DEFAULT_TASK_STACKSIZE=4096
|
||||
CONFIG_EXAMPLES_HELLO=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_FS_TMPFS=y
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_INIT_ENTRYPOINT="nsh_main"
|
||||
CONFIG_LIBC_MEMFD_ERROR=y
|
||||
CONFIG_MM_DEFAULT_ALIGNMENT=32
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_FILEIOSIZE=512
|
||||
CONFIG_NSH_READLINE=y
|
||||
CONFIG_PREALLOC_TIMERS=4
|
||||
CONFIG_RAM_SIZE=294912
|
||||
CONFIG_RAM_START=0x20020000
|
||||
CONFIG_RR_INTERVAL=200
|
||||
CONFIG_RTL8721DX_FLASH_FS=y
|
||||
CONFIG_SCHED_HPWORK=y
|
||||
CONFIG_SCHED_HPWORKPRIORITY=192
|
||||
CONFIG_SCHED_LPWORK=y
|
||||
CONFIG_STACK_COLORATION=y
|
||||
CONFIG_START_DAY=16
|
||||
CONFIG_START_MONTH=6
|
||||
CONFIG_START_YEAR=2026
|
||||
CONFIG_SYSTEM_I2CTOOL=y
|
||||
CONFIG_SYSTEM_NSH=y
|
||||
CONFIG_SYSTEM_NSH_STACKSIZE=2500
|
||||
CONFIG_TIMER=y
|
||||
CONFIG_TIMER_ARCH=y
|
||||
CONFIG_USEC_PER_TICK=1000
|
||||
|
|
@ -30,9 +30,15 @@ if(CONFIG_AMEBA_UART)
|
|||
list(APPEND SRCS rtl8721dx_uart.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_AMEBA_I2C)
|
||||
list(APPEND SRCS rtl8721dx_i2c.c)
|
||||
endif()
|
||||
|
||||
target_sources(board PRIVATE ${SRCS})
|
||||
|
||||
if(CONFIG_AMEBA_GPIO OR CONFIG_AMEBA_UART)
|
||||
if(CONFIG_AMEBA_GPIO
|
||||
OR CONFIG_AMEBA_UART
|
||||
OR CONFIG_AMEBA_I2C)
|
||||
# The board pin/UART tables pull in the shared driver's public headers from
|
||||
# arch/arm/src/common/ameba/, not on the default board include path.
|
||||
target_include_directories(board
|
||||
|
|
|
|||
|
|
@ -42,4 +42,13 @@ CSRCS += rtl8721dx_uart.c
|
|||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_AMEBA_I2C),y)
|
||||
CSRCS += rtl8721dx_i2c.c
|
||||
|
||||
# The board I2C table pulls in the shared driver's public header from
|
||||
# arch/arm/src/common/ameba/, which is not on the default board include path.
|
||||
|
||||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
|
||||
endif
|
||||
|
||||
include $(TOPDIR)/boards/Board.mk
|
||||
|
|
|
|||
|
|
@ -128,6 +128,16 @@ int rtl8721dx_bringup(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMEBA_I2C
|
||||
/* Register the board's I2C master buses at /dev/i2cN. */
|
||||
|
||||
ret = rtl8721dx_i2c_initialize();
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: rtl8721dx_i2c_initialize failed: %d\n", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Install the inter-core HW IPC-semaphore RTOS hooks LAST -- after all the
|
||||
* flash / WHC bring-up above, and just before this (board_late_initialize)
|
||||
* path returns and nx_start() hands off to the init task.
|
||||
|
|
|
|||
102
boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_i2c.c
Normal file
102
boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_i2c.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/****************************************************************************
|
||||
* boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_i2c.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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/param.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "ameba_gpio.h"
|
||||
#include "ameba_i2c.h"
|
||||
#include "rtl8721dx_pke8721daf.h"
|
||||
|
||||
#ifdef CONFIG_AMEBA_I2C
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* One entry per I2C bus exposed to NuttX at /dev/i2cN. The SCL/SDA pads are
|
||||
* examples used by the `i2c` config (system/i2c i2ctool) -- any pad can be
|
||||
* routed to an I2C controller through the pin mux, so adjust them to match
|
||||
* your board's wiring.
|
||||
*/
|
||||
|
||||
struct rtl8721dx_i2c_s
|
||||
{
|
||||
int bus; /* Controller index (AMEBA_I2C0/AMEBA_I2C1) */
|
||||
uint8_t sclpin; /* SCL pad (AMEBA_PA()/AMEBA_PB() encoding) */
|
||||
uint8_t sdapin; /* SDA pad (AMEBA_PA()/AMEBA_PB() encoding) */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct rtl8721dx_i2c_s g_i2c_buses[] =
|
||||
{
|
||||
{
|
||||
AMEBA_I2C0, AMEBA_PB(20), AMEBA_PB(21)
|
||||
},
|
||||
{
|
||||
AMEBA_I2C1, AMEBA_PB(18), AMEBA_PB(19)
|
||||
},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rtl8721dx_i2c_initialize
|
||||
*
|
||||
* Description:
|
||||
* Register the board's I2C master buses at /dev/i2cN.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rtl8721dx_i2c_initialize(void)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)nitems(g_i2c_buses); i++)
|
||||
{
|
||||
ret = ameba_i2c_register(g_i2c_buses[i].bus, g_i2c_buses[i].sclpin,
|
||||
g_i2c_buses[i].sdapin);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR,
|
||||
"ERROR: ameba_i2c_register(/dev/i2c%d) failed: %d\n",
|
||||
g_i2c_buses[i].bus, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_AMEBA_I2C */
|
||||
|
|
@ -95,6 +95,19 @@ int rtl8721dx_gpio_initialize(void);
|
|||
int rtl8721dx_uart_initialize(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMEBA_I2C
|
||||
/****************************************************************************
|
||||
* Name: rtl8721dx_i2c_initialize
|
||||
*
|
||||
* Description:
|
||||
* Register the board's I2C master buses at /dev/i2cN
|
||||
* (boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_i2c.c).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rtl8721dx_i2c_initialize(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTL8721DX_FLASH_FS
|
||||
/****************************************************************************
|
||||
* Name: ameba_flash_fs_initialize
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ static const char *g_white_prefix[] =
|
|||
"FLASH_",
|
||||
"GPIO_",
|
||||
"Get_OSC131_", /* Get_OSC131_STATE — Ameba SDK RTC accessor */
|
||||
"I2C_", /* I2C_Init, I2C_MasterWrite, I2C_InitTypeDef, etc. */
|
||||
"IPC_",
|
||||
"LOGUART_",
|
||||
"OSC2M_",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue