mirror of
https://github.com/apache/nuttx.git
synced 2026-08-30 13:43:09 +00:00
arch/arm/rtl8721dx: add shared Ameba SPI driver
Add a shared NuttX SPI master lower-half for the Realtek Ameba SPI controllers (SPI0/SPI1) in arch/arm/src/common/ameba, driven through the SDK fwlib in polling mode with full-duplex exchange and a software chip select. Per-chip wiring (controller count, register bases, clock masks, crossbar pad-mux codes and the fwlib SSI_InitTypeDef layout) lives in arch/arm/src/rtl8721dx/ameba_spi_chip.h so a port to the other Ameba chips only supplies a same-named header. Each controller registers as /dev/spiN from pke8721daf bring-up through the stock SPI character driver; a dedicated `spi` defconfig drives the spitool for validation. Assisted-by: Claude <noreply@anthropic.com> Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
This commit is contained in:
parent
e5a0c4ae88
commit
7dbf782e5b
15 changed files with 1100 additions and 1 deletions
|
|
@ -39,6 +39,8 @@ Supported in this NuttX port:
|
|||
directly on the SDK fwlib register layer
|
||||
* I2C master buses exposed as ``/dev/i2cN`` character devices, driven directly
|
||||
on the SDK fwlib register layer
|
||||
* SPI master buses exposed as ``/dev/spiN`` character devices, driven directly
|
||||
on the SDK fwlib register layer
|
||||
|
||||
Buttons and LEDs
|
||||
================
|
||||
|
|
@ -116,6 +118,22 @@ external pull-ups on SCL/SDA. Probe a bus with the tool::
|
|||
|
||||
nsh> i2c dev -b 0 0x03 0x77 # scan /dev/i2c0 for devices
|
||||
|
||||
spi
|
||||
---
|
||||
|
||||
Minimal NSH with the SPI master driver and the ``spi`` tool
|
||||
(``system/spi``) enabled (no Wi-Fi). The board registers two buses from its
|
||||
table (see ``boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_spi.c``): SPI0 at
|
||||
``/dev/spi0`` with CLK/MOSI/MISO/CS on PA14/PA15/PA16/PA17 and SPI1 at
|
||||
``/dev/spi1`` with CLK/MOSI/MISO on PB18/PB19/PB20 and a software chip-select
|
||||
on PB21. Edit that table -- controller, CLK/MOSI/MISO pads and CS pad -- to
|
||||
match a board's wiring; the pads use the same ``AMEBA_PA()`` / ``AMEBA_PB()``
|
||||
encoding as the GPIO table and are muxed to the SPI function through the SDK
|
||||
ROM, while the chip-select is driven as a plain GPIO. Exercise a bus with the
|
||||
tool::
|
||||
|
||||
nsh> spi exch -b 1 -x 4 deadbeef # full-duplex transfer on /dev/spi1
|
||||
|
||||
Wi-Fi
|
||||
=====
|
||||
|
||||
|
|
|
|||
|
|
@ -69,4 +69,20 @@ config AMEBA_I2C
|
|||
fwlib register layer and drives the DesignWare I2C block in polling
|
||||
mode.
|
||||
|
||||
config AMEBA_SPI
|
||||
bool "SPI"
|
||||
default n
|
||||
select SPI
|
||||
select SPI_DRIVER
|
||||
select SPI_EXCHANGE
|
||||
---help---
|
||||
Expose the Ameba SPI controllers (SPI0/SPI1) as NuttX SPI master
|
||||
buses at /dev/spiN. The board selects which controller is used and
|
||||
its CLK/MOSI/MISO/CS pads in its bring-up code; the chip select is
|
||||
driven as a plain GPIO (software CS).
|
||||
|
||||
The driver (arch/arm/src/common/ameba/ameba_spi.c) sits on the SDK
|
||||
fwlib register layer and drives the DesignWare SSI block in polling
|
||||
mode.
|
||||
|
||||
endmenu # Ameba Peripheral Support
|
||||
|
|
|
|||
648
arch/arm/src/common/ameba/ameba_spi.c
Normal file
648
arch/arm/src/common/ameba/ameba_spi.c
Normal file
|
|
@ -0,0 +1,648 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/common/ameba/ameba_spi.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 SPI master lower half for the Realtek Ameba SPI controllers (SPI0
|
||||
* and SPI1). Each controller is registered from board bring-up and appears
|
||||
* as /dev/spiN through the stock SPI character driver (spi_register()).
|
||||
*
|
||||
* The controller is a Synopsys DesignWare SSI block programmed through the
|
||||
* SDK fwlib SSI API in polling mode (no interrupts): SSI_Init() programs the
|
||||
* role/mode/clock, and each word is moved by spinning on SSI_Writeable() /
|
||||
* SSI_Readable() around SSI_WriteData() / SSI_ReadData(). The block runs in
|
||||
* transmit-and-receive mode so every word written yields one word read,
|
||||
* which is exactly the full-duplex exchange NuttX expects.
|
||||
*
|
||||
* The SSI fwlib routines resolve to the on-chip ROM symbol table (they are
|
||||
* _LONG_CALL_ entries), like the UART fwlib and unlike the I2C fwlib. The
|
||||
* SSI baud divider is derived from the peripheral clock ip_clk =
|
||||
* PLL_ClkGet() / (HPERI divider + 1), read once at registration.
|
||||
*
|
||||
* The chip select is driven as a plain GPIO (software CS) rather than the
|
||||
* SSI hardware CS: select() toggles the CS pad through GPIO_WriteBit(), so
|
||||
* any pad can serve as CS and the CS timing is not tied to the FIFO state.
|
||||
*
|
||||
* The chip-specific wiring (controller count, register bases, clock masks
|
||||
* and pad-mux codes) lives in the per-chip ameba_spi_chip.h. To keep the
|
||||
* vendor headers out of the NuttX include world, the few fwlib symbols and
|
||||
* the SSI_InitTypeDef layout used here are declared locally rather than
|
||||
* pulled in from <ameba_spi.h>.
|
||||
*/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/spi/spi.h>
|
||||
#include <nuttx/spi/spi_transfer.h>
|
||||
|
||||
#include "ameba_spi.h"
|
||||
#include "ameba_spi_chip.h"
|
||||
#include "ameba_gpio_chip.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The register bases, peripheral-clock masks, crossbar pad-mux codes and
|
||||
* controller count (AMEBA_NSPI) come from the per-chip ameba_spi_chip.h.
|
||||
* Everything below is common to every current Ameba chip.
|
||||
*/
|
||||
|
||||
/* fwlib SSI_InitTypeDef field values (SSI_MASTER, TMOD/FRF, SCPOL/SCPH).
|
||||
* These are identical on every Ameba chip audited.
|
||||
*/
|
||||
|
||||
#define AMEBA_SSI_MASTER 0x1 /* SSI_MASTER (SPI_Role) */
|
||||
#define AMEBA_SSI_TMOD_TR 0x0 /* Transmit & receive (SPI_TransferMode) */
|
||||
#define AMEBA_SSI_FRF_SPI 0x0 /* FRF_MOTOROLA_SPI (SPI_DataFrameFormat) */
|
||||
|
||||
#define AMEBA_SSI_SCPOL_LOW 0x0 /* SCPOL_INACTIVE_IS_LOW (CPOL=0) */
|
||||
#define AMEBA_SSI_SCPOL_HIGH 0x1 /* SCPOL_INACTIVE_IS_HIGH (CPOL=1) */
|
||||
#define AMEBA_SSI_SCPH_MIDDLE 0x0 /* SCPH_TOGGLES_IN_MIDDLE (CPHA=0) */
|
||||
#define AMEBA_SSI_SCPH_START 0x1 /* SCPH_TOGGLES_AT_START (CPHA=1) */
|
||||
|
||||
/* GPIO field values for the software chip select (see ameba_gpio.c). */
|
||||
|
||||
#define AMEBA_GPIO_MODE_OUT 0x1 /* GPIO_Mode_OUT */
|
||||
#define AMEBA_GPIO_PUPD_NONE 0x0 /* GPIO_PuPd_NOPULL */
|
||||
|
||||
/* Second/third argument to fwlib "state" style APIs. */
|
||||
|
||||
#define AMEBA_DISABLE 0x0
|
||||
#define AMEBA_ENABLE 0x1
|
||||
|
||||
/* Bus defaults used until the upper half programs its own. */
|
||||
|
||||
#define AMEBA_SPI_DEFAULT_FREQ 1000000
|
||||
#define AMEBA_SPI_DEFAULT_BITS 8
|
||||
|
||||
/* Bounded spin guarding each FIFO wait so a wedged bus cannot hang. */
|
||||
|
||||
#define AMEBA_SPI_TIMEOUT 1000000
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Layout-compatible mirror of the fwlib SSI_InitTypeDef (all u32, same
|
||||
* order); passed by address to SSI_StructInit()/SSI_Init().
|
||||
*/
|
||||
|
||||
struct ameba_ssi_init_s
|
||||
{
|
||||
uint32_t dmarxlvl; /* SPI_DmaRxDataLevel */
|
||||
uint32_t dmatxlvl; /* SPI_DmaTxDataLevel */
|
||||
uint32_t rxthlvl; /* SPI_RxThresholdLevel */
|
||||
uint32_t txthlvl; /* SPI_TxThresholdLevel */
|
||||
uint32_t ssenable; /* SPI_SlaveSelectEnable */
|
||||
uint32_t divider; /* SPI_ClockDivider */
|
||||
uint32_t framenum; /* SPI_DataFrameNumber */
|
||||
uint32_t frameformat; /* SPI_DataFrameFormat */
|
||||
uint32_t framesize; /* SPI_DataFrameSize */
|
||||
uint32_t intmask; /* SPI_InterruptMask */
|
||||
uint32_t role; /* SPI_Role */
|
||||
uint32_t sclkphase; /* SPI_SclkPhase */
|
||||
uint32_t sclkpolarity; /* SPI_SclkPolarity */
|
||||
uint32_t transfermode; /* SPI_TransferMode */
|
||||
};
|
||||
|
||||
/* Layout-compatible mirror of the fwlib GPIO_InitTypeDef (see ameba_gpio.c),
|
||||
* used to configure the software chip-select pad as an output.
|
||||
*/
|
||||
|
||||
struct ameba_gpio_init_s
|
||||
{
|
||||
uint32_t mode; /* GPIO_Mode */
|
||||
uint32_t pupd; /* GPIO_PuPd */
|
||||
uint32_t ittrigger; /* GPIO_ITTrigger */
|
||||
uint32_t itpolarity; /* GPIO_ITPolarity */
|
||||
uint32_t itdebounce; /* GPIO_ITDebounce */
|
||||
uint32_t pin; /* GPIO_Pin */
|
||||
};
|
||||
|
||||
struct ameba_spi_dev_s
|
||||
{
|
||||
struct spi_dev_s dev; /* SPI master lower half (must be first) */
|
||||
uintptr_t base; /* Non-secure SPI register base address */
|
||||
uint32_t periph; /* APBPeriph function mask (RCC arg 1) */
|
||||
uint32_t clk; /* APBPeriph clock mask (RCC arg 2) */
|
||||
uint32_t ipclk; /* SSI peripheral clock ip_clk (Hz) */
|
||||
uint32_t frequency; /* Requested bus frequency (Hz) */
|
||||
uint32_t actual; /* Achieved bus frequency (Hz) */
|
||||
uint32_t divider; /* SSI clock divider for that frequency */
|
||||
uint8_t mode; /* Currently programmed enum spi_mode_e */
|
||||
uint8_t nbits; /* Currently programmed bits per word */
|
||||
bool dirty; /* SSI needs an SSI_Init() before use */
|
||||
uint8_t clkpin; /* SCLK pad (AMEBA_PA()/AMEBA_PB()) */
|
||||
uint8_t mosipin; /* MOSI pad */
|
||||
uint8_t misopin; /* MISO pad */
|
||||
uint8_t cspin; /* Chip-select pad (GPIO output) */
|
||||
uint8_t clkfid; /* Pin mux code for the SCLK pad */
|
||||
uint8_t mosifid; /* Pin mux code for the MOSI pad */
|
||||
uint8_t misofid; /* Pin mux code for the MISO pad */
|
||||
mutex_t lock; /* Serializes bus access */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* SDK fwlib SSI/GPIO/pin/clock API, all resolved from the on-chip ROM. */
|
||||
|
||||
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 GPIO_Init(struct ameba_gpio_init_s *init);
|
||||
extern void GPIO_WriteBit(uint32_t pin, uint32_t state);
|
||||
extern void SSI_SetRole(void *spidev, uint32_t role);
|
||||
extern void SSI_StructInit(struct ameba_ssi_init_s *init);
|
||||
extern void SSI_Init(void *spidev, struct ameba_ssi_init_s *init);
|
||||
extern void SSI_Cmd(void *spidev, uint32_t newstate);
|
||||
extern uint32_t SSI_Writeable(void *spidev);
|
||||
extern uint32_t SSI_Readable(void *spidev);
|
||||
extern void SSI_WriteData(void *spidev, uint32_t value);
|
||||
extern uint32_t SSI_ReadData(void *spidev);
|
||||
|
||||
/* SPI master lower-half operations. */
|
||||
|
||||
static int ameba_spi_lock(struct spi_dev_s *dev, bool lock);
|
||||
static void ameba_spi_select(struct spi_dev_s *dev, uint32_t devid,
|
||||
bool selected);
|
||||
static uint32_t ameba_spi_setfrequency(struct spi_dev_s *dev,
|
||||
uint32_t frequency);
|
||||
static void ameba_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode);
|
||||
static void ameba_spi_setbits(struct spi_dev_s *dev, int nbits);
|
||||
static uint8_t ameba_spi_status(struct spi_dev_s *dev, uint32_t devid);
|
||||
static uint32_t ameba_spi_send(struct spi_dev_s *dev, uint32_t wd);
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
static void ameba_spi_exchange(struct spi_dev_s *dev,
|
||||
const void *txbuffer, void *rxbuffer,
|
||||
size_t nwords);
|
||||
#else
|
||||
static void ameba_spi_sndblock(struct spi_dev_s *dev, const void *buffer,
|
||||
size_t nwords);
|
||||
static void ameba_spi_recvblock(struct spi_dev_s *dev, void *buffer,
|
||||
size_t nwords);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct spi_ops_s g_ameba_spi_ops =
|
||||
{
|
||||
.lock = ameba_spi_lock,
|
||||
.select = ameba_spi_select,
|
||||
.setfrequency = ameba_spi_setfrequency,
|
||||
.setmode = ameba_spi_setmode,
|
||||
.setbits = ameba_spi_setbits,
|
||||
.status = ameba_spi_status,
|
||||
.send = ameba_spi_send,
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
.exchange = ameba_spi_exchange,
|
||||
#else
|
||||
.sndblock = ameba_spi_sndblock,
|
||||
.recvblock = ameba_spi_recvblock,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Per-controller register base, peripheral function/clock masks and crossbar
|
||||
* pad-mux codes, indexed by controller number and supplied by the per-chip
|
||||
* ameba_spi_chip.h.
|
||||
*/
|
||||
|
||||
static const uintptr_t g_spi_base[AMEBA_NSPI] = AMEBA_SPI_BASES;
|
||||
static const uint32_t g_spi_periph[AMEBA_NSPI] = AMEBA_SPI_APBPERIPH;
|
||||
static const uint32_t g_spi_clk[AMEBA_NSPI] = AMEBA_SPI_APBPERIPH_CLK;
|
||||
static const uint8_t g_spi_clkfid[AMEBA_NSPI] = AMEBA_SPI_CLKFID;
|
||||
static const uint8_t g_spi_mosifid[AMEBA_NSPI] = AMEBA_SPI_MOSIFID;
|
||||
static const uint8_t g_spi_misofid[AMEBA_NSPI] = AMEBA_SPI_MISOFID;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_ipclk
|
||||
*
|
||||
* Description:
|
||||
* Return the SSI peripheral clock ip_clk = PLL_ClkGet() / (HPERI + 1),
|
||||
* the frequency the baud divider divides down to produce SCLK.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t ameba_spi_ipclk(void)
|
||||
{
|
||||
/* The register address and HPERI field position are chip-specific and are
|
||||
* expressed by AMEBA_SPI_IPCLK() in the per-chip ameba_spi_chip.h.
|
||||
*/
|
||||
|
||||
return AMEBA_SPI_IPCLK();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_configure
|
||||
*
|
||||
* Description:
|
||||
* (Re)program the SSI block for the currently requested frequency, mode
|
||||
* and word length, and enable it. The DesignWare SSI can only be
|
||||
* configured while disabled, so this runs lazily on the first word after
|
||||
* any of those parameters changes (priv->dirty).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_configure(struct ameba_spi_dev_s *priv)
|
||||
{
|
||||
struct ameba_ssi_init_s init;
|
||||
void *spidev = (void *)priv->base;
|
||||
|
||||
if (!priv->dirty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&init, 0, sizeof(init));
|
||||
SSI_StructInit(&init);
|
||||
|
||||
init.role = AMEBA_SSI_MASTER;
|
||||
init.transfermode = AMEBA_SSI_TMOD_TR;
|
||||
init.frameformat = AMEBA_SSI_FRF_SPI;
|
||||
init.ssenable = 0; /* Software CS: do not drive the SSI CS line */
|
||||
init.intmask = 0; /* Polling: no SSI interrupts */
|
||||
init.divider = priv->divider;
|
||||
init.framesize = priv->nbits - 1;
|
||||
|
||||
/* enum spi_mode_e encodes CPOL in bit1 and CPHA in bit0. */
|
||||
|
||||
init.sclkpolarity = (priv->mode & 0x2) ? AMEBA_SSI_SCPOL_HIGH :
|
||||
AMEBA_SSI_SCPOL_LOW;
|
||||
init.sclkphase = (priv->mode & 0x1) ? AMEBA_SSI_SCPH_START :
|
||||
AMEBA_SSI_SCPH_MIDDLE;
|
||||
|
||||
SSI_Cmd(spidev, AMEBA_DISABLE);
|
||||
SSI_Init(spidev, &init);
|
||||
SSI_Cmd(spidev, AMEBA_ENABLE);
|
||||
|
||||
priv->dirty = false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_transfer
|
||||
*
|
||||
* Description:
|
||||
* Move nwords words full-duplex in polling mode. Every word written to
|
||||
* the TX FIFO produces one word in the RX FIFO (transmit-and-receive
|
||||
* mode); a NULL txbuffer sends 0xffff and a NULL rxbuffer discards the
|
||||
* received words.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_transfer(struct ameba_spi_dev_s *priv,
|
||||
const void *txbuffer, void *rxbuffer,
|
||||
size_t nwords)
|
||||
{
|
||||
void *spidev = (void *)priv->base;
|
||||
bool wide = priv->nbits > 8;
|
||||
size_t i;
|
||||
uint32_t to;
|
||||
|
||||
ameba_spi_configure(priv);
|
||||
|
||||
for (i = 0; i < nwords; i++)
|
||||
{
|
||||
uint32_t word = 0xffff;
|
||||
uint32_t rxword;
|
||||
|
||||
if (txbuffer != NULL)
|
||||
{
|
||||
word = wide ? ((const uint16_t *)txbuffer)[i] :
|
||||
((const uint8_t *)txbuffer)[i];
|
||||
}
|
||||
|
||||
for (to = AMEBA_SPI_TIMEOUT;
|
||||
to > 0 && SSI_Writeable(spidev) == 0; to--);
|
||||
|
||||
SSI_WriteData(spidev, word);
|
||||
|
||||
for (to = AMEBA_SPI_TIMEOUT;
|
||||
to > 0 && SSI_Readable(spidev) == 0; to--);
|
||||
|
||||
rxword = SSI_ReadData(spidev);
|
||||
|
||||
if (rxbuffer != NULL)
|
||||
{
|
||||
if (wide)
|
||||
{
|
||||
((uint16_t *)rxbuffer)[i] = (uint16_t)rxword;
|
||||
}
|
||||
else
|
||||
{
|
||||
((uint8_t *)rxbuffer)[i] = (uint8_t)rxword;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_lock
|
||||
****************************************************************************/
|
||||
|
||||
static int ameba_spi_lock(struct spi_dev_s *dev, bool lock)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
|
||||
return lock ? nxmutex_lock(&priv->lock) : nxmutex_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_select
|
||||
*
|
||||
* Description:
|
||||
* Assert (selected) or de-assert the active-low chip-select GPIO. A
|
||||
* single CS pad is driven per bus, so the devid is not used.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_select(struct spi_dev_s *dev, uint32_t devid,
|
||||
bool selected)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
|
||||
GPIO_WriteBit(priv->cspin, selected ? AMEBA_DISABLE : AMEBA_ENABLE);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_setfrequency
|
||||
*
|
||||
* Description:
|
||||
* Choose the largest even SSI divider whose SCLK does not exceed the
|
||||
* requested frequency (SCLK = ip_clk / divider, even, 2..65534), and
|
||||
* return the frequency actually achieved.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t ameba_spi_setfrequency(struct spi_dev_s *dev,
|
||||
uint32_t frequency)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
uint32_t divider;
|
||||
|
||||
if (frequency == 0)
|
||||
{
|
||||
return priv->actual;
|
||||
}
|
||||
|
||||
if (frequency == priv->frequency)
|
||||
{
|
||||
return priv->actual;
|
||||
}
|
||||
|
||||
/* Round the divider down to an even value, then bump it up until SCLK no
|
||||
* longer exceeds the request; clamp to the 16-bit even range.
|
||||
*/
|
||||
|
||||
divider = (priv->ipclk / frequency / 2) * 2;
|
||||
if (divider < 2)
|
||||
{
|
||||
divider = 2;
|
||||
}
|
||||
|
||||
if ((priv->ipclk / divider) > frequency)
|
||||
{
|
||||
divider += 2;
|
||||
}
|
||||
|
||||
if (divider > 0xfffe)
|
||||
{
|
||||
divider = 0xfffe;
|
||||
}
|
||||
|
||||
priv->divider = divider;
|
||||
priv->frequency = frequency;
|
||||
priv->actual = priv->ipclk / divider;
|
||||
priv->dirty = true;
|
||||
|
||||
spiinfo("frequency=%" PRIu32 " actual=%" PRIu32 " div=%" PRIu32 "\n",
|
||||
frequency, priv->actual, divider);
|
||||
return priv->actual;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_setmode
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
|
||||
if ((uint8_t)mode != priv->mode)
|
||||
{
|
||||
priv->mode = (uint8_t)mode;
|
||||
priv->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_setbits
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_setbits(struct spi_dev_s *dev, int nbits)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
|
||||
if (nbits >= 4 && nbits <= 16 && (uint8_t)nbits != priv->nbits)
|
||||
{
|
||||
priv->nbits = (uint8_t)nbits;
|
||||
priv->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_status
|
||||
****************************************************************************/
|
||||
|
||||
static uint8_t ameba_spi_status(struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
UNUSED(dev);
|
||||
UNUSED(devid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_send
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t ameba_spi_send(struct spi_dev_s *dev, uint32_t wd)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
uint16_t rxword = 0;
|
||||
uint16_t txword = (uint16_t)wd;
|
||||
|
||||
ameba_spi_transfer(priv, &txword, &rxword, 1);
|
||||
return rxword;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_exchange
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_exchange(struct spi_dev_s *dev,
|
||||
const void *txbuffer, void *rxbuffer,
|
||||
size_t nwords)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
|
||||
ameba_spi_transfer(priv, txbuffer, rxbuffer, nwords);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_sndblock
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_sndblock(struct spi_dev_s *dev, const void *buffer,
|
||||
size_t nwords)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
|
||||
ameba_spi_transfer(priv, buffer, NULL, nwords);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_recvblock
|
||||
****************************************************************************/
|
||||
|
||||
static void ameba_spi_recvblock(struct spi_dev_s *dev, void *buffer,
|
||||
size_t nwords)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv = (struct ameba_spi_dev_s *)dev;
|
||||
|
||||
ameba_spi_transfer(priv, NULL, buffer, nwords);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SPI_EXCHANGE */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_register
|
||||
*
|
||||
* Description:
|
||||
* See ameba_spi.h.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct spi_dev_s *ameba_spi_register(int bus, uint8_t clkpin,
|
||||
uint8_t mosipin, uint8_t misopin,
|
||||
uint8_t cspin)
|
||||
{
|
||||
struct ameba_spi_dev_s *priv;
|
||||
struct ameba_gpio_init_s gpio;
|
||||
int ret;
|
||||
|
||||
if (bus < 0 || bus >= AMEBA_NSPI)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
priv = kmm_zalloc(sizeof(struct ameba_spi_dev_s));
|
||||
if (priv == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
priv->dev.ops = &g_ameba_spi_ops;
|
||||
priv->base = g_spi_base[bus];
|
||||
priv->periph = g_spi_periph[bus];
|
||||
priv->clk = g_spi_clk[bus];
|
||||
priv->clkpin = clkpin;
|
||||
priv->mosipin = mosipin;
|
||||
priv->misopin = misopin;
|
||||
priv->cspin = cspin;
|
||||
priv->clkfid = g_spi_clkfid[bus];
|
||||
priv->mosifid = g_spi_mosifid[bus];
|
||||
priv->misofid = g_spi_misofid[bus];
|
||||
priv->mode = SPIDEV_MODE0;
|
||||
priv->nbits = AMEBA_SPI_DEFAULT_BITS;
|
||||
priv->frequency = 0;
|
||||
priv->dirty = true;
|
||||
nxmutex_init(&priv->lock);
|
||||
|
||||
/* Gate the SSI peripheral clock and route the CLK/MOSI/MISO pads. */
|
||||
|
||||
RCC_PeriphClockCmd(priv->periph, priv->clk, AMEBA_ENABLE);
|
||||
|
||||
/* The controller powers up as an SPI slave (the LSYS SPIx_MST bit is clear
|
||||
* out of reset), and in slave mode the master-only baud-rate and slave-
|
||||
* enable registers are write-ignored so the block never drives SCLK.
|
||||
* Switch it to master before any SSI_Init() so that configuration sticks.
|
||||
*/
|
||||
|
||||
SSI_SetRole((void *)priv->base, AMEBA_SSI_MASTER);
|
||||
|
||||
Pinmux_Config(priv->clkpin, priv->clkfid);
|
||||
Pinmux_Config(priv->mosipin, priv->mosifid);
|
||||
Pinmux_Config(priv->misopin, priv->misofid);
|
||||
|
||||
/* Configure the chip-select pad as a GPIO output, de-asserted (high). */
|
||||
|
||||
RCC_PeriphClockCmd(AMEBA_APBPERIPH_GPIO, AMEBA_APBPERIPH_GPIO,
|
||||
AMEBA_ENABLE);
|
||||
memset(&gpio, 0, sizeof(gpio));
|
||||
gpio.mode = AMEBA_GPIO_MODE_OUT;
|
||||
gpio.pupd = AMEBA_GPIO_PUPD_NONE;
|
||||
gpio.pin = priv->cspin;
|
||||
GPIO_Init(&gpio);
|
||||
GPIO_WriteBit(priv->cspin, AMEBA_ENABLE);
|
||||
|
||||
/* Latch the peripheral clock and prime the default bus frequency. */
|
||||
|
||||
priv->ipclk = ameba_spi_ipclk();
|
||||
ameba_spi_setfrequency(&priv->dev, AMEBA_SPI_DEFAULT_FREQ);
|
||||
|
||||
ret = spi_register(&priv->dev, bus);
|
||||
if (ret < 0)
|
||||
{
|
||||
_err("ERROR: spi_register(/dev/spi%d) failed: %d\n", bus, ret);
|
||||
nxmutex_destroy(&priv->lock);
|
||||
kmm_free(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &priv->dev;
|
||||
}
|
||||
92
arch/arm/src/common/ameba/ameba_spi.h
Normal file
92
arch/arm/src/common/ameba/ameba_spi.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/common/ameba/ameba_spi.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_SPI_H
|
||||
#define __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_SPI_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nuttx/spi/spi.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* The Ameba SPI (DesignWare SSI) controllers exposed to NuttX as SPI master
|
||||
* buses. The CLK/MOSI/MISO/CS 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 SPI bus through the pin mux, and the chip select
|
||||
* is driven as a plain GPIO (software CS) so any pad may serve as CS.
|
||||
*/
|
||||
|
||||
#define AMEBA_SPI0 0
|
||||
#define AMEBA_SPI1 1
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ameba_spi_register
|
||||
*
|
||||
* Description:
|
||||
* Configure one Ameba SPI (DesignWare SSI) controller as a master bus,
|
||||
* registering it with the NuttX SPI character driver at /dev/spiN, where N
|
||||
* is the bus number. The chip select is driven as a GPIO (software CS).
|
||||
*
|
||||
* Input Parameters:
|
||||
* bus - The controller index, AMEBA_SPI0 or AMEBA_SPI1. Also used as
|
||||
* the /dev/spiN minor number.
|
||||
* clkpin - The SCLK pad, encoded with AMEBA_PA()/AMEBA_PB().
|
||||
* mosipin - The MOSI pad, encoded with AMEBA_PA()/AMEBA_PB().
|
||||
* misopin - The MISO pad, encoded with AMEBA_PA()/AMEBA_PB().
|
||||
* cspin - The chip-select pad, driven as an active-low GPIO output.
|
||||
*
|
||||
* Returned Value:
|
||||
* The SPI master lower half on success; NULL on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct spi_dev_s *ameba_spi_register(int bus, uint8_t clkpin,
|
||||
uint8_t mosipin, uint8_t misopin,
|
||||
uint8_t cspin);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_SPI_H */
|
||||
|
|
@ -52,6 +52,10 @@ if(CONFIG_AMEBA_I2C)
|
|||
list(APPEND SRCS ${AMEBA_COMMON}/ameba_i2c.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_AMEBA_SPI)
|
||||
list(APPEND SRCS ${AMEBA_COMMON}/ameba_spi.c)
|
||||
endif()
|
||||
|
||||
target_include_directories(arch PRIVATE ${AMEBA_COMMON})
|
||||
target_sources(arch PRIVATE ${SRCS})
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ ifeq ($(CONFIG_AMEBA_I2C),y)
|
|||
CHIP_CSRCS += ameba_i2c.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_AMEBA_SPI),y)
|
||||
CHIP_CSRCS += ameba_spi.c
|
||||
endif
|
||||
|
||||
############################################################################
|
||||
# Realtek RTL8721Dx SDK integration
|
||||
#
|
||||
|
|
|
|||
|
|
@ -146,6 +146,15 @@ ifeq ($(CONFIG_AMEBA_I2C),y)
|
|||
AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_i2c.c
|
||||
endif
|
||||
|
||||
# SPI (DesignWare SSI) register layer. Like I2C, the fwlib SSI API is NOT in
|
||||
# ROM: the SPI driver (arch/.../common/ameba/ameba_spi.c) calls SSI_Init/
|
||||
# StructInit/Cmd and SSI_Writeable/Readable/WriteData/ReadData, all compiled
|
||||
# from this RAM source and linked in (--gc-sections drops the unused DMA/
|
||||
# interrupt helpers).
|
||||
ifeq ($(CONFIG_AMEBA_SPI),y)
|
||||
AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_spi.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
|
||||
|
|
|
|||
113
arch/arm/src/rtl8721dx/ameba_spi_chip.h
Normal file
113
arch/arm/src/rtl8721dx/ameba_spi_chip.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/rtl8721dx/ameba_spi_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_SPI_CHIP_H
|
||||
#define __ARCH_ARM_SRC_RTL8721DX_AMEBA_SPI_CHIP_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Per-chip SPI wiring for RTL8721DX (amebadplus). The shared driver
|
||||
* (arch/arm/src/common/ameba/ameba_spi.c) includes this header to learn how
|
||||
* many SPI (DesignWare SSI) controllers the chip exposes and, for each, its
|
||||
* register base, peripheral-clock masks and crossbar pad-mux codes.
|
||||
*
|
||||
* 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: amebadplus exposes two high-speed SSI
|
||||
* masters, SPI0 and SPI1, in the PERI_HCLK domain. The bases below are
|
||||
* the NON-secure peripheral aliases (0x4012xxxx); the secure aliases
|
||||
* (0x5012xxxx) must not be used from the non-secure world.
|
||||
*
|
||||
* 2. APBPeriph "function" and "clock" masks are two separate lists because
|
||||
* RCC_PeriphClockCmd() takes them as distinct arguments. They are
|
||||
* equal on this chip. NOTE the group selector bit30 is 0 here (unlike
|
||||
* the Ameba UART/I2C blocks where bit30 is 1), so each chip must supply
|
||||
* its own values.
|
||||
*
|
||||
* 3. Pad mux: SPI0 (master) shares one generic PINMUX_FUNCTION_SPI code
|
||||
* (8) on all four signals, whereas SPI1 uses per-signal codes
|
||||
* (CLK/MOSI/MISO/CS). The codes are therefore supplied as one list per
|
||||
* signal, indexed by controller. The chip-select entries are only used
|
||||
* when hardware CS is selected; this driver drives CS as a plain GPIO
|
||||
* (software CS), so the CS pad-mux code is informational.
|
||||
*/
|
||||
|
||||
#define AMEBA_NSPI 2
|
||||
|
||||
/* NON-secure SPI register bases (SPI0_REG_BASE / SPI1_REG_BASE). */
|
||||
|
||||
#define AMEBA_SPI_BASES { 0x40124000ul, 0x40125000ul }
|
||||
|
||||
/* APBPeriph_SPIx (function) and APBPeriph_SPIx_CLOCK masks. Equal on this
|
||||
* chip; kept as two lists so chips where they differ can supply both. The
|
||||
* group selector (bit30) is 0 for the SPI block on amebadplus.
|
||||
*/
|
||||
|
||||
#define AMEBA_SPI_APBPERIPH \
|
||||
{ (((uint32_t)0 << 30) | ((uint32_t)1 << 14)), \
|
||||
(((uint32_t)0 << 30) | ((uint32_t)1 << 15)) }
|
||||
|
||||
#define AMEBA_SPI_APBPERIPH_CLK \
|
||||
{ (((uint32_t)0 << 30) | ((uint32_t)1 << 14)), \
|
||||
(((uint32_t)0 << 30) | ((uint32_t)1 << 15)) }
|
||||
|
||||
/* Crossbar pad-mux function codes, one list per signal, indexed by
|
||||
* controller. SPI0 uses the generic PINMUX_FUNCTION_SPI (8) on every
|
||||
* signal; SPI1 uses its per-signal codes CLK=29 / MISO=30 / MOSI=31 / CS=32.
|
||||
*/
|
||||
|
||||
#define AMEBA_SPI_CLKFID { 8, 29 } /* SPI0 generic, SPI1_CLK */
|
||||
#define AMEBA_SPI_MOSIFID { 8, 31 } /* SPI0 generic, SPI1_MOSI */
|
||||
#define AMEBA_SPI_MISOFID { 8, 30 } /* SPI0 generic, SPI1_MISO */
|
||||
#define AMEBA_SPI_CSFID { 8, 32 } /* SPI0 generic, SPI1_CS */
|
||||
|
||||
/* SSI peripheral clock: ip_clk = PLL_ClkGet() / (HPERI divider + 1), the
|
||||
* frequency the SPI baud divider divides down to make SCLK. On amebadplus
|
||||
* the HPERI divider field is bits[10:8] of REG_LSYS_CKD_GRP0 in the system-
|
||||
* control block (non-secure alias 0x41008000 + 0x0220). BOTH the register
|
||||
* address and the field position are chip-specific -- e.g. on amebalite that
|
||||
* same bit field is not HPERI -- so the whole computation lives here rather
|
||||
* than in the shared driver. PLL_ClkGet() is the amebadplus fwlib PLL query;
|
||||
* each chip header declares the clock-source query its AMEBA_SPI_IPCLK()
|
||||
* uses (the shared driver includes this header before the macro expands).
|
||||
*/
|
||||
|
||||
extern uint32_t PLL_ClkGet(void);
|
||||
|
||||
#define AMEBA_SPI_CKD_GRP0 0x41008220ul
|
||||
#define AMEBA_SPI_IPCLK() \
|
||||
(PLL_ClkGet() / \
|
||||
((((*(volatile uint32_t *)AMEBA_SPI_CKD_GRP0) >> 8) & 0x7) + 1))
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_RTL8721DX_AMEBA_SPI_CHIP_H */
|
||||
51
boards/arm/rtl8721dx/pke8721daf/configs/spi/defconfig
Normal file
51
boards/arm/rtl8721dx/pke8721daf/configs/spi/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_SPI=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_NSH=y
|
||||
CONFIG_SYSTEM_NSH_STACKSIZE=2500
|
||||
CONFIG_SYSTEM_SPITOOL=y
|
||||
CONFIG_TIMER=y
|
||||
CONFIG_TIMER_ARCH=y
|
||||
CONFIG_USEC_PER_TICK=1000
|
||||
|
|
@ -34,11 +34,16 @@ if(CONFIG_AMEBA_I2C)
|
|||
list(APPEND SRCS rtl8721dx_i2c.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_AMEBA_SPI)
|
||||
list(APPEND SRCS rtl8721dx_spi.c)
|
||||
endif()
|
||||
|
||||
target_sources(board PRIVATE ${SRCS})
|
||||
|
||||
if(CONFIG_AMEBA_GPIO
|
||||
OR CONFIG_AMEBA_UART
|
||||
OR CONFIG_AMEBA_I2C)
|
||||
OR CONFIG_AMEBA_I2C
|
||||
OR CONFIG_AMEBA_SPI)
|
||||
# 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
|
||||
|
|
|
|||
|
|
@ -51,4 +51,13 @@ CSRCS += rtl8721dx_i2c.c
|
|||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_AMEBA_SPI),y)
|
||||
CSRCS += rtl8721dx_spi.c
|
||||
|
||||
# The board SPI 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
|
||||
|
|
|
|||
|
|
@ -138,6 +138,16 @@ int rtl8721dx_bringup(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMEBA_SPI
|
||||
/* Register the board's SPI master buses at /dev/spiN. */
|
||||
|
||||
ret = rtl8721dx_spi_initialize();
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: rtl8721dx_spi_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.
|
||||
|
|
|
|||
|
|
@ -108,6 +108,19 @@ int rtl8721dx_uart_initialize(void);
|
|||
int rtl8721dx_i2c_initialize(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMEBA_SPI
|
||||
/****************************************************************************
|
||||
* Name: rtl8721dx_spi_initialize
|
||||
*
|
||||
* Description:
|
||||
* Register the board's SPI master buses at /dev/spiN
|
||||
* (boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_spi.c).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rtl8721dx_spi_initialize(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTL8721DX_FLASH_FS
|
||||
/****************************************************************************
|
||||
* Name: ameba_flash_fs_initialize
|
||||
|
|
|
|||
103
boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_spi.c
Normal file
103
boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_spi.c
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/****************************************************************************
|
||||
* boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_spi.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 <errno.h>
|
||||
|
||||
#include "ameba_gpio.h"
|
||||
#include "ameba_spi.h"
|
||||
#include "rtl8721dx_pke8721daf.h"
|
||||
|
||||
#ifdef CONFIG_AMEBA_SPI
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* One entry per SPI bus exposed to NuttX at /dev/spiN. The CLK/MOSI/MISO/CS
|
||||
* pads below are examples used by the `spi` config (system/spi spitool);
|
||||
* adjust them to match your board's wiring.
|
||||
*/
|
||||
|
||||
struct rtl8721dx_spi_s
|
||||
{
|
||||
int bus; /* Controller index (AMEBA_SPI0/AMEBA_SPI1) */
|
||||
uint8_t clkpin; /* SCLK pad (AMEBA_PA()/AMEBA_PB() encoding) */
|
||||
uint8_t mosipin; /* MOSI pad */
|
||||
uint8_t misopin; /* MISO pad */
|
||||
uint8_t cspin; /* Chip-select pad (software CS GPIO) */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct rtl8721dx_spi_s g_spi_buses[] =
|
||||
{
|
||||
{
|
||||
AMEBA_SPI0, AMEBA_PA(14), AMEBA_PA(15), AMEBA_PA(16), AMEBA_PA(17)
|
||||
},
|
||||
{
|
||||
AMEBA_SPI1, AMEBA_PB(18), AMEBA_PB(19), AMEBA_PB(20), AMEBA_PB(21)
|
||||
},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rtl8721dx_spi_initialize
|
||||
*
|
||||
* Description:
|
||||
* Register the board's SPI master buses at /dev/spiN.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int rtl8721dx_spi_initialize(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)nitems(g_spi_buses); i++)
|
||||
{
|
||||
if (ameba_spi_register(g_spi_buses[i].bus, g_spi_buses[i].clkpin,
|
||||
g_spi_buses[i].mosipin, g_spi_buses[i].misopin,
|
||||
g_spi_buses[i].cspin) == NULL)
|
||||
{
|
||||
syslog(LOG_ERR,
|
||||
"ERROR: ameba_spi_register(/dev/spi%d) failed\n",
|
||||
g_spi_buses[i].bus);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_AMEBA_SPI */
|
||||
|
|
@ -275,6 +275,7 @@ static const char *g_white_prefix[] =
|
|||
"FLASH_",
|
||||
"GPIO_",
|
||||
"Get_OSC131_", /* Get_OSC131_STATE — Ameba SDK RTC accessor */
|
||||
"HPERI_", /* HPERI_ClkGet — amebagreen2 SPI ip_clk query */
|
||||
"I2C_", /* I2C_Init, I2C_MasterWrite, I2C_InitTypeDef, etc. */
|
||||
"IPC_",
|
||||
"LOGUART_",
|
||||
|
|
@ -282,14 +283,17 @@ static const char *g_white_prefix[] =
|
|||
"OSC4M_",
|
||||
"OSC131K_",
|
||||
"PAD_",
|
||||
"PLL_", /* PLL_ClkGet — amebadplus SPI ip_clk query */
|
||||
"Pinmux_",
|
||||
"RCC_",
|
||||
"RTC_", /* RTC_InitTypeDef, RTC_Enable, RTC_SetTime, etc. */
|
||||
"RTCIO_",
|
||||
"SDM32K_", /* SDM32K_Enable */
|
||||
"SSI_", /* SSI_Init, SSI_SetRole, SSI_WriteData, etc. */
|
||||
"Set_OSC131_", /* Set_OSC131_STATE — Ameba SDK RTC accessor */
|
||||
"SYSCFG_",
|
||||
"SYSTIMER_",
|
||||
"SYS_PLL_", /* SYS_PLL_ClkGet — RTL8720F SPI ip_clk query */
|
||||
"UART_",
|
||||
"SystemCoreClock", /* SystemCoreClock, SystemCoreClockUpdate */
|
||||
"cmse_", /* ARM CMSE TrustZone intrinsics (arm_cmse.h) */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue