drivers: spi: create Ambiq SPI BLEIF driver
Some Ambiq Apollox Blue SOC (e.g. Apollo3 Blue) uses internal designed BLEIF module which is different from the general IOM module for SPI transceiver. The called HAL API will also be independent. This driver is implemented for the BLEIF module usage scenarios. Signed-off-by: Aaron Ye <aye@ambiq.com>
This commit is contained in:
parent
f5fd2cf49e
commit
d84874309e
6 changed files with 266 additions and 1 deletions
|
@ -45,6 +45,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_SMARTBOND spi_smartbond.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_OPENTITAN spi_opentitan.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_OPENTITAN spi_opentitan.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_NUMAKER spi_numaker.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_NUMAKER spi_numaker.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_AMBIQ spi_ambiq.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_AMBIQ spi_ambiq.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SPI_AMBIQ_BLEIF spi_ambiq_bleif.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_RPI_PICO_PIO spi_rpi_pico_pio.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_RPI_PICO_PIO spi_rpi_pico_pio.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ mspi_ambiq.c)
|
zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ mspi_ambiq.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_MCHP_MSS spi_mchp_mss.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_MCHP_MSS spi_mchp_mss.c)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Ambiq SDK SPI
|
# Ambiq SDK SPI
|
||||||
#
|
#
|
||||||
# Copyright (c) 2023 Antmicro <www.antmicro.com>
|
# Copyright (c) 2023 Antmicro <www.antmicro.com>
|
||||||
|
# Copyright (c) 2024 Ambiq Micro Inc. <www.ambiq.com>
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
@ -22,3 +23,28 @@ config MSPI_AMBIQ
|
||||||
select AMBIQ_HAL_USE_MSPI
|
select AMBIQ_HAL_USE_MSPI
|
||||||
help
|
help
|
||||||
Enable driver for Ambiq MSPI.
|
Enable driver for Ambiq MSPI.
|
||||||
|
|
||||||
|
config SPI_AMBIQ_BLEIF
|
||||||
|
bool "AMBIQ SPI-BLEIF driver"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_AMBIQ_SPI_BLEIF_ENABLED
|
||||||
|
select AMBIQ_HAL
|
||||||
|
select AMBIQ_HAL_USE_BLEIF
|
||||||
|
help
|
||||||
|
Enable driver for Ambiq Apollox Blue SOC (e.g. Apollo3 Blue)
|
||||||
|
which uses internal designed BLEIF module (different from the
|
||||||
|
general IOM module) for SPI transceiver. It is always used for
|
||||||
|
the Bluetooth HCI communication.
|
||||||
|
|
||||||
|
if SPI_AMBIQ_BLEIF
|
||||||
|
|
||||||
|
config SPI_AMBIQ_BLEIF_TIMING_TRACE
|
||||||
|
bool "Ambiq SPI-BLEIF timing trace"
|
||||||
|
help
|
||||||
|
The pins for the SPI transceiver are not exposed from the chips
|
||||||
|
and no need for user to confiugre them. But the chips design the
|
||||||
|
configurable BLEIF timing observation functions on other exposed
|
||||||
|
pins. The user can enable it to configure the pins for timing
|
||||||
|
trace purpose.
|
||||||
|
|
||||||
|
endif # SPI_AMBIQ_BLEIF
|
||||||
|
|
215
drivers/spi/spi_ambiq_bleif.c
Normal file
215
drivers/spi/spi_ambiq_bleif.c
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Ambiq Micro Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Some Ambiq Apollox Blue SOC (e.g. Apollo3 Blue) uses internal designed BLEIF module which is
|
||||||
|
* different from the general IOM module for SPI transceiver. The called HAL API will also be
|
||||||
|
* independent. This driver is implemented for the BLEIF module usage scenarios.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT ambiq_spi_bleif
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(spi_ambiq_bleif);
|
||||||
|
|
||||||
|
#include <zephyr/drivers/spi.h>
|
||||||
|
#include <zephyr/drivers/pinctrl.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "spi_context.h"
|
||||||
|
#include <am_mcu_apollo.h>
|
||||||
|
|
||||||
|
#define PWRCTRL_MAX_WAIT_US 5
|
||||||
|
|
||||||
|
typedef int (*ambiq_spi_pwr_func_t)(void);
|
||||||
|
|
||||||
|
struct spi_ambiq_config {
|
||||||
|
uint32_t base;
|
||||||
|
int size;
|
||||||
|
const struct pinctrl_dev_config *pcfg;
|
||||||
|
ambiq_spi_pwr_func_t pwr_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spi_ambiq_data {
|
||||||
|
struct spi_context ctx;
|
||||||
|
am_hal_ble_config_t ble_cfg;
|
||||||
|
void *BLEhandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SPI_BASE (((const struct spi_ambiq_config *)(dev)->config)->base)
|
||||||
|
#define REG_STAT 0x268
|
||||||
|
#define SPI_STAT(dev) (SPI_BASE + REG_STAT)
|
||||||
|
#define SPI_WORD_SIZE 8
|
||||||
|
|
||||||
|
static int spi_config(const struct device *dev, const struct spi_config *config)
|
||||||
|
{
|
||||||
|
struct spi_ambiq_data *data = dev->data;
|
||||||
|
struct spi_context *ctx = &(data->ctx);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (spi_context_configured(ctx, config)) {
|
||||||
|
/* Already configured. No need to do it again. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SPI_WORD_SIZE_GET(config->operation) != SPI_WORD_SIZE) {
|
||||||
|
LOG_ERR("Word size must be %d", SPI_WORD_SIZE);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
|
||||||
|
LOG_ERR("Only supports single mode");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->operation & SPI_LOCK_ON) {
|
||||||
|
LOG_ERR("Lock On not supported");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->operation & SPI_TRANSFER_LSB) {
|
||||||
|
LOG_ERR("LSB first not supported");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->operation & SPI_OP_MODE_SLAVE) {
|
||||||
|
LOG_ERR("Slave mode not supported");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
if (config->operation & SPI_MODE_LOOP) {
|
||||||
|
LOG_ERR("Loopback mode not supported");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We consider only the default configuration defined in HAL is tested and stable. */
|
||||||
|
data->ble_cfg = am_hal_ble_default_config;
|
||||||
|
|
||||||
|
ctx->config = config;
|
||||||
|
|
||||||
|
ret = am_hal_ble_config(data->BLEhandle, &data->ble_cfg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_ambiq_xfer(const struct device *dev, const struct spi_config *config)
|
||||||
|
{
|
||||||
|
struct spi_ambiq_data *data = dev->data;
|
||||||
|
struct spi_context *ctx = &data->ctx;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
am_hal_ble_transfer_t trans = {0};
|
||||||
|
|
||||||
|
if (ctx->tx_len) {
|
||||||
|
trans.ui8Command = AM_HAL_BLE_WRITE;
|
||||||
|
trans.pui32Data = (uint32_t *)ctx->tx_buf;
|
||||||
|
trans.ui16Length = ctx->tx_len;
|
||||||
|
trans.bContinue = false;
|
||||||
|
} else {
|
||||||
|
trans.ui8Command = AM_HAL_BLE_READ;
|
||||||
|
trans.pui32Data = (uint32_t *)ctx->rx_buf;
|
||||||
|
trans.ui16Length = ctx->rx_len;
|
||||||
|
trans.bContinue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = am_hal_ble_blocking_transfer(data->BLEhandle, &trans);
|
||||||
|
spi_context_complete(ctx, dev, 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_ambiq_transceive(const struct device *dev, const struct spi_config *config,
|
||||||
|
const struct spi_buf_set *tx_bufs,
|
||||||
|
const struct spi_buf_set *rx_bufs)
|
||||||
|
{
|
||||||
|
struct spi_ambiq_data *data = dev->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = spi_config(dev, config);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tx_bufs && !rx_bufs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);
|
||||||
|
|
||||||
|
ret = spi_ambiq_xfer(dev, config);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_ambiq_release(const struct device *dev, const struct spi_config *config)
|
||||||
|
{
|
||||||
|
struct spi_ambiq_data *data = dev->data;
|
||||||
|
|
||||||
|
if (!sys_read32(SPI_STAT(dev))) {
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_context_unlock_unconditionally(&data->ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct spi_driver_api spi_ambiq_driver_api = {
|
||||||
|
.transceive = spi_ambiq_transceive,
|
||||||
|
.release = spi_ambiq_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int spi_ambiq_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct spi_ambiq_data *data = dev->data;
|
||||||
|
const struct spi_ambiq_config *cfg = dev->config;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#if defined(CONFIG_SPI_AMBIQ_BLEIF_TIMING_TRACE)
|
||||||
|
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SPI_AMBIQ_BLEIF_TIMING_TRACE */
|
||||||
|
|
||||||
|
ret = am_hal_ble_initialize((cfg->base - REG_BLEIF_BASEADDR) / cfg->size, &data->BLEhandle);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = am_hal_ble_power_control(data->BLEhandle, AM_HAL_BLE_POWER_ACTIVE);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = cfg->pwr_func();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AMBIQ_SPI_BLEIF_INIT(n) \
|
||||||
|
PINCTRL_DT_INST_DEFINE(n); \
|
||||||
|
static int pwr_on_ambiq_spi_##n(void) \
|
||||||
|
{ \
|
||||||
|
uint32_t addr = DT_REG_ADDR(DT_INST_PHANDLE(n, ambiq_pwrcfg)) + \
|
||||||
|
DT_INST_PHA(n, ambiq_pwrcfg, offset); \
|
||||||
|
sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \
|
||||||
|
k_busy_wait(PWRCTRL_MAX_WAIT_US); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
static struct spi_ambiq_data spi_ambiq_data##n = { \
|
||||||
|
SPI_CONTEXT_INIT_LOCK(spi_ambiq_data##n, ctx), \
|
||||||
|
SPI_CONTEXT_INIT_SYNC(spi_ambiq_data##n, ctx)}; \
|
||||||
|
static const struct spi_ambiq_config spi_ambiq_config##n = { \
|
||||||
|
.base = DT_INST_REG_ADDR(n), \
|
||||||
|
.size = DT_INST_REG_SIZE(n), \
|
||||||
|
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
||||||
|
.pwr_func = pwr_on_ambiq_spi_##n}; \
|
||||||
|
DEVICE_DT_INST_DEFINE(n, spi_ambiq_init, NULL, &spi_ambiq_data##n, &spi_ambiq_config##n, \
|
||||||
|
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, &spi_ambiq_driver_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(AMBIQ_SPI_BLEIF_INIT)
|
18
dts/bindings/spi/ambiq,spi-bleif.yaml
Normal file
18
dts/bindings/spi/ambiq,spi-bleif.yaml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Copyright (c) 2024 Ambiq Micro Inc.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: |
|
||||||
|
This binding gives a representation of SPI controller in some Ambiq
|
||||||
|
Apollox Blue SOC (e.g. Apollo3 Blue) which uses BLEIF module for SPI
|
||||||
|
transceiver.
|
||||||
|
|
||||||
|
compatible: "ambiq,spi-bleif"
|
||||||
|
|
||||||
|
include: [spi-controller.yaml, pinctrl-device.yaml, ambiq-pwrcfg.yaml]
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
ambiq,pwrcfg:
|
||||||
|
required: true
|
|
@ -50,4 +50,9 @@ config AMBIQ_HAL_USE_HWINFO
|
||||||
help
|
help
|
||||||
Use the HWINFO driver from Ambiq HAL
|
Use the HWINFO driver from Ambiq HAL
|
||||||
|
|
||||||
|
config AMBIQ_HAL_USE_BLEIF
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Use the BLEIF driver from Ambiq HAL
|
||||||
|
|
||||||
endif # AMBIQ_HAL
|
endif # AMBIQ_HAL
|
||||||
|
|
2
west.yml
2
west.yml
|
@ -142,7 +142,7 @@ manifest:
|
||||||
groups:
|
groups:
|
||||||
- hal
|
- hal
|
||||||
- name: hal_ambiq
|
- name: hal_ambiq
|
||||||
revision: 94dd874cd726ba8185a301e78337c5c39685123f
|
revision: fcbbd99e20db1432196f4aec92678bd1f5b19c96
|
||||||
path: modules/hal/ambiq
|
path: modules/hal/ambiq
|
||||||
groups:
|
groups:
|
||||||
- hal
|
- hal
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue