hw/mcu/ambiq/apollo3/src/hal_spi.c (852 lines of code) (raw):
/*
* 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.
*/
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stdbool.h>
#include "os/mynewt.h"
#include "hal/hal_spi.h"
#include "mcu/hal_apollo3.h"
#include "mcu/cmsis_nvic.h"
#include "am_mcu_apollo.h"
/* Prevent CMSIS from breaking apollo3 macros. */
#undef GPIO
#undef IOSLAVE
#undef CLKGEN
#define SPI_MASTER_ANY_ENABLED ( \
MYNEWT_VAL(SPI_0_MASTER) || \
MYNEWT_VAL(SPI_1_MASTER) || \
MYNEWT_VAL(SPI_2_MASTER) || \
MYNEWT_VAL(SPI_3_MASTER) || \
MYNEWT_VAL(SPI_4_MASTER) || \
MYNEWT_VAL(SPI_5_MASTER))
#define SPI_SLAVE_ANY_ENABLED ( \
MYNEWT_VAL(SPI_0_SLAVE))
#if SPI_MASTER_ANY_ENABLED || SPI_SLAVE_ANY_ENABLED
struct apollo3_spi {
uint8_t spi_num;
uint8_t spi_type;
int8_t ss_pin[4];
void *spi_handle;
int8_t cur_ss_pin;
bool cont_tx;
hal_spi_txrx_cb txrx_cb_func;
void *txrx_cb_arg;
};
#if MYNEWT_VAL(SPI_0_MASTER)
static struct apollo3_spi apollo3_spi0_master;
#endif
#if MYNEWT_VAL(SPI_1_MASTER)
static struct apollo3_spi apollo3_spi1_master;
#endif
#if MYNEWT_VAL(SPI_2_MASTER)
static struct apollo3_spi apollo3_spi2_master;
#endif
#if MYNEWT_VAL(SPI_3_MASTER)
static struct apollo3_spi apollo3_spi3_master;
#endif
#if MYNEWT_VAL(SPI_4_MASTER)
static struct apollo3_spi apollo3_spi4_master;
#endif
#if MYNEWT_VAL(SPI_5_MASTER)
static struct apollo3_spi apollo3_spi5_master;
#endif
static am_hal_iom_config_t g_iom_spi_config =
{
.eInterfaceMode = AM_HAL_IOM_SPI_MODE,
.ui32ClockFreq = AM_HAL_IOM_4MHZ,
.eSpiMode = AM_HAL_IOM_SPI_MODE_0, /* CPOL = 0; CPHA = 0 */
};
#define AM_IOS_TX_BUFSIZE_MAX 1023
uint8_t g_tx_fifo_buffer[AM_IOS_TX_BUFSIZE_MAX];
static am_hal_ios_config_t g_ios_spi_config =
{
/* Configure the IOS in SPI mode. */
.ui32InterfaceSelect = AM_HAL_IOS_USE_SPI,
/* Eliminate the "read-only" section, so an external host can use the entire "direct write" section. */
.ui32ROBase = 0x78,
/* Making the "FIFO" section as big as possible. */
.ui32FIFOBase = 0x80,
/* We don't need any RAM space, so extend the FIFO all the way to the end of the LRAM. */
.ui32RAMBase = 0x100,
/* FIFO Threshold - set to half the size */
.ui32FIFOThreshold = 0x20,
.pui8SRAMBuffer = g_tx_fifo_buffer,
.ui32SRAMBufferCap = AM_IOS_TX_BUFSIZE_MAX,
};
static struct apollo3_spi *
apollo3_spi_resolve(int spi_num)
{
switch (spi_num) {
#if MYNEWT_VAL(SPI_0_MASTER)
case 0:
return &apollo3_spi0_master;
#endif
#if MYNEWT_VAL(SPI_1_MASTER)
case 1:
return &apollo3_spi1_master;
#endif
#if MYNEWT_VAL(SPI_2_MASTER)
case 2:
return &apollo3_spi2_master;
#endif
#if MYNEWT_VAL(SPI_3_MASTER)
case 3:
return &apollo3_spi3_master;
#endif
#if MYNEWT_VAL(SPI_4_MASTER)
case 4:
return &apollo3_spi4_master;
#endif
#if MYNEWT_VAL(SPI_5_MASTER)
case 5:
return &apollo3_spi5_master;
#endif
default:
return NULL;
}
}
static uint32_t
apollo3_spi_data_mode(int spi_mode)
{
switch (spi_mode) {
case HAL_SPI_MODE0: return AM_HAL_IOM_SPI_MODE_0;
case HAL_SPI_MODE1: return AM_HAL_IOM_SPI_MODE_1;
case HAL_SPI_MODE2: return AM_HAL_IOM_SPI_MODE_2;
case HAL_SPI_MODE3: return AM_HAL_IOM_SPI_MODE_3;
default: return -1;
}
}
static int
hal_spi_config_master(int spi_num, const struct hal_spi_settings *settings)
{
am_hal_iom_config_t sdk_config;
struct apollo3_spi *spi;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
sdk_config.eInterfaceMode = AM_HAL_IOM_SPI_MODE;
sdk_config.ui32ClockFreq = settings->baudrate;
sdk_config.eSpiMode = (am_hal_iom_spi_mode_e)apollo3_spi_data_mode(settings->data_mode);
am_hal_iom_configure(spi->spi_handle, &sdk_config);
return 0;
}
static int
hal_spi_config_slave(int spi_num, const struct hal_spi_settings *settings)
{
struct apollo3_spi *spi;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
am_hal_ios_configure(spi->spi_handle, &g_ios_spi_config);
return 0;
}
/* | spi:cfg | sck | miso | mosi |
* |-----------+-------+-------+-------|
* | 0:1 | 5 | 6 | 7 |
* | 1:1 | 8 | 9 | 10 |
* | 2:5 | 27 | 28 | 25 |
* | 3:5 | 42 | 43 | 38 |
* | 4:5 | 39 | 40 | 44 |
* | 5:5 | 48 | 49 | 47 |
*/
static int
hal_spi_pin_config_master(int spi_num, const struct apollo3_spi_cfg *pins)
{
#if SPI_MASTER_ANY_ENABLED
const int8_t miso = pins->miso_pin;
const int8_t mosi = pins->mosi_pin;
const int8_t sck = pins->sck_pin;
#endif
switch (spi_num) {
#if MYNEWT_VAL(SPI_0_MASTER)
case 0:
if (sck == 5 && miso == 6 && mosi == 7) {
return 1;
} else {
return -1;
}
#endif
#if MYNEWT_VAL(SPI_1_MASTER)
case 1:
if (sck == 8 && miso == 9 && mosi == 10) {
return 1;
} else {
return -1;
}
#endif
#if MYNEWT_VAL(SPI_2_MASTER)
case 2:
if (sck == 27 && miso == 25 && mosi == 28) {
return 5;
} else {
return -1;
}
#endif
#if MYNEWT_VAL(SPI_3_MASTER)
case 3:
if (sck == 42 && miso == 43 && mosi == 38) {
return 5;
} else {
return -1;
}
#endif
#if MYNEWT_VAL(SPI_4_MASTER)
case 4:
if (sck == 39 && miso == 40 && mosi == 44) {
return 5;
} else {
return -1;
}
#endif
#if MYNEWT_VAL(SPI_5_MASTER)
case 5:
if (sck == 48 && miso == 49 && mosi == 47) {
return 5;
} else {
return -1;
}
#endif
default:
return -1;
}
}
static int
hal_spi_pin_config_slave(int spi_num, const struct apollo3_spi_cfg *pins)
{
#if SPI_SLAVE_ANY_ENABLED
const int8_t miso = pins->miso_pin;
const int8_t mosi = pins->mosi_pin;
const int8_t sck = pins->sck_pin;
#endif
switch (spi_num) {
#if MYNEWT_VAL(SPI_0_SLAVE)
case 0:
if (sck == 0 && miso == 2 && mosi == 1) {
return 1;
} else {
return -1;
}
#endif
default:
return -1;
}
}
static int
hal_spi_ss_pin_config_master(int spi_num, int8_t ss_pin)
{
switch (ss_pin) {
case 7:
case 41:
return 0;
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
case 48:
case 49:
return 1;
case 3:
case 4:
case 8:
case 9:
case 10:
return 2;
case 0:
case 1:
case 2:
return 7;
default:
return -1;
}
}
static int
hal_spi_ss_pin_config_slave(int spi_num, int8_t ss_pin)
{
switch (spi_num) {
#if MYNEWT_VAL(SPI_0_SLAVE)
case 0:
switch (ss_pin) {
case 3:
return 1;
default:
return -1;
}
#endif
default:
return -1;
}
}
static uint32_t
hal_spi_get_uNCE(int spi_num, int ss_pin) {
switch(spi_num) {
#if MYNEWT_VAL(SPI_0_MASTER)
case 0:
switch (ss_pin) {
case 8:
case 11:
case 16:
case 23:
case 31:
case 35:
case 42:
return 0;
case 13:
case 17:
case 24:
case 32:
case 41:
case 43:
case 47:
return 1;
case 1:
case 14:
case 18:
case 25:
case 33:
case 37:
case 44:
case 48:
return 2;
case 15:
case 19:
case 22:
case 30:
case 34:
case 38:
case 49:
return 3;
default:
return -1;
}
#endif
#if MYNEWT_VAL(SPI_1_MASTER)
case 1:
switch (ss_pin) {
case 11:
case 16:
case 23:
case 27:
case 31:
case 35:
case 42:
return 0;
case 4:
case 17:
case 24:
case 32:
case 41:
case 43:
case 47:
return 1;
case 1:
case 14:
case 18:
case 29:
case 33:
case 44:
case 48:
return 2;
case 0:
case 15:
case 19:
case 26:
case 34:
case 38:
case 45:
case 49:
return 3;
default:
return -1;
}
#endif
#if MYNEWT_VAL(SPI_2_MASTER)
case 2:
switch (ss_pin) {
case 3:
case 11:
case 16:
case 23:
case 31:
case 35:
case 42:
return 0;
case 2:
case 17:
case 20:
case 24:
case 32:
case 41:
case 43:
case 47:
return 1;
case 1:
case 14:
case 18:
case 21:
case 33:
case 44:
case 48:
return 2;
case 9:
case 15:
case 34:
case 38:
case 49:
return 3;
default:
return -1;
}
#endif
#if MYNEWT_VAL(SPI_3_MASTER)
case 3:
switch (ss_pin) {
case 3:
case 8:
case 11:
case 12:
case 27:
case 35:
case 46:
return 0;
case 4:
case 7:
case 13:
case 20:
case 28:
case 36:
case 47:
return 1;
case 0:
case 10:
case 18:
case 21:
case 25:
case 29:
case 37:
case 48:
return 2;
case 2:
case 9:
case 19:
case 22:
case 26:
case 30:
case 34:
case 45:
return 3;
default:
return -1;
}
#endif
#if MYNEWT_VAL(SPI_4_MASTER)
case 4:
switch (ss_pin) {
case 3:
case 8:
case 12:
case 23:
case 27:
case 31:
case 46:
return 0;
case 4:
case 7:
case 13:
case 17:
case 20:
case 28:
case 36:
return 1;
case 0:
case 10:
case 14:
case 21:
case 25:
case 29:
case 37:
return 2;
case 2:
case 9:
case 22:
case 26:
case 30:
case 45:
case 49:
return 3;
default:
return -1;
}
#endif
#if MYNEWT_VAL(SPI_5_MASTER)
case 5:
switch (ss_pin) {
case 3:
case 8:
case 12:
case 16:
case 27:
case 42:
case 46:
return 0;
case 4:
case 7:
case 13:
case 20:
case 24:
case 28:
case 36:
return 1;
case 0:
case 10:
case 21:
case 25:
case 29:
case 33:
case 37:
case 44:
return 2;
case 2:
case 9:
case 22:
case 26:
case 30:
case 38:
case 45:
return 3;
default:
return -1;
}
#endif
default:
return -1;
}
}
static int
hal_spi_pin_config(int spi_num, int master, const struct apollo3_spi_cfg *pins)
{
if (master) {
return hal_spi_pin_config_master(spi_num, pins);
} else {
return hal_spi_pin_config_slave(spi_num, pins);
}
}
static int
hal_spi_ss_pin_config(int spi_num, int master, int8_t ss_pin)
{
if (master) {
return hal_spi_ss_pin_config_master(spi_num, ss_pin);
} else {
return hal_spi_ss_pin_config_slave(spi_num, ss_pin);
}
}
static int
hal_spi_ss_pin_init(struct apollo3_spi *spi, int8_t ss_index, int8_t ss_pin)
{
am_hal_gpio_pincfg_t spi_ss_cfg;
int ss_pin_func_sel;
if (spi->ss_pin[ss_index] != ss_pin) {
ss_pin_func_sel = hal_spi_ss_pin_config(spi->spi_num, 1, ss_pin);
if (ss_pin_func_sel != -1 && ss_index != -1) {
memset(&spi_ss_cfg, 0x0, sizeof(am_hal_gpio_pincfg_t));
spi_ss_cfg.uFuncSel = ss_pin_func_sel;
spi_ss_cfg.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA;
spi_ss_cfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL;
spi_ss_cfg.eGPInput = AM_HAL_GPIO_PIN_INPUT_NONE;
spi_ss_cfg.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI;
spi_ss_cfg.uIOMnum = spi->spi_num;
spi_ss_cfg.uNCE = ss_index;
spi_ss_cfg.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW;
if (am_hal_gpio_pinconfig(ss_pin, spi_ss_cfg) != AM_HAL_STATUS_SUCCESS) {
return SYS_EINVAL;
}
spi->ss_pin[ss_index] = ss_pin;
} else {
return SYS_EINVAL;
}
}
return 0;
}
static int
hal_spi_init_master(int spi_num, const struct apollo3_spi_cfg *cfg)
{
struct apollo3_spi *spi;
int spi_pin_func_sel, ss_pin_func_sel, i;
am_hal_gpio_pincfg_t spi_sck_cfg, spi_miso_cfg, spi_mosi_cfg, spi_ss_cfg;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
memset(spi, 0, sizeof *spi);
/* Initialize the IOM. */
if (am_hal_iom_initialize(spi_num, &(spi->spi_handle)) != AM_HAL_STATUS_SUCCESS) {
return SYS_EINVAL;
}
if (am_hal_iom_power_ctrl(spi->spi_handle, AM_HAL_SYSCTRL_WAKE, false) != AM_HAL_STATUS_SUCCESS) {
return SYS_EINVAL;
}
/* Set the required configuration settings for the IOM. */
if (am_hal_iom_configure(spi->spi_handle, &g_iom_spi_config) != AM_HAL_STATUS_SUCCESS) {
return SYS_EINVAL;
}
/* Configure the IOM pins. */
spi_pin_func_sel = hal_spi_pin_config(spi_num, 1, cfg);
if (spi_pin_func_sel == -1) {
return SYS_EINVAL;
}
for (i = 0; i < 4; i++) {
ss_pin_func_sel = hal_spi_ss_pin_config(spi_num, 1, cfg->ss_pin[i]);
if (ss_pin_func_sel != -1) {
memset(&spi_ss_cfg, 0x0, sizeof(am_hal_gpio_pincfg_t));
spi_ss_cfg.uFuncSel = ss_pin_func_sel;
spi_ss_cfg.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA;
spi_ss_cfg.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL;
spi_ss_cfg.eGPInput = AM_HAL_GPIO_PIN_INPUT_NONE;
spi_ss_cfg.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI;
spi_ss_cfg.uIOMnum = spi_num;
spi_ss_cfg.uNCE = hal_spi_get_uNCE(spi_num, cfg->ss_pin[i]);
spi_ss_cfg.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW;
if (am_hal_gpio_pinconfig(cfg->ss_pin[i], spi_ss_cfg) != AM_HAL_STATUS_SUCCESS) {
return SYS_EINVAL;
}
spi->ss_pin[i] = cfg->ss_pin[i];
spi->cur_ss_pin = cfg->ss_pin[i];
} else {
spi->ss_pin[i] = -1;
}
}
memset(&spi_sck_cfg, 0x0, sizeof(am_hal_gpio_pincfg_t));
spi_sck_cfg.uFuncSel = spi_pin_func_sel;
spi_sck_cfg.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA;
spi_sck_cfg.uIOMnum = spi_num;
if (am_hal_gpio_pinconfig(cfg->sck_pin, spi_sck_cfg) != AM_HAL_STATUS_SUCCESS){
return SYS_EINVAL;
}
memset(&spi_miso_cfg, 0x0, sizeof(am_hal_gpio_pincfg_t));
spi_miso_cfg.uFuncSel = spi_pin_func_sel;
spi_miso_cfg.uIOMnum = spi_num;
if (am_hal_gpio_pinconfig(cfg->miso_pin, spi_miso_cfg) != AM_HAL_STATUS_SUCCESS) {
return SYS_EINVAL;
}
memset(&spi_mosi_cfg, 0x0, sizeof(am_hal_gpio_pincfg_t));
spi_mosi_cfg.uFuncSel = spi_pin_func_sel;
spi_mosi_cfg.eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA;
spi_mosi_cfg.uIOMnum = spi_num;
if (am_hal_gpio_pinconfig(cfg->mosi_pin, spi_mosi_cfg) != AM_HAL_STATUS_SUCCESS) {
return SYS_EINVAL;
}
/* Enable the IOM. */
hal_spi_enable(spi_num);
spi->spi_num = spi_num;
spi->cont_tx = false;
spi->spi_type = HAL_SPI_TYPE_MASTER;
return 0;
}
static int
hal_spi_init_slave(int spi_num, struct apollo3_spi_cfg *cfg)
{
return SYS_ERANGE;
}
int apollo3_spi_set_ss_pin(int spi_num, int8_t ss_pin)
{
struct apollo3_spi *spi;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
spi->cur_ss_pin = ss_pin;
return 0;
}
int apollo3_spi_set_continuation(int spi_num, bool cont)
{
struct apollo3_spi *spi;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
spi->cont_tx = cont;
return 0;
}
/**
* Initialize the SPI, given by spi_num.
*
* @param spi_num The number of the SPI to initialize
* @param cfg HW/MCU specific configuration,
* passed to the underlying implementation, providing extra
* configuration.
* @param spi_type SPI type (master or slave)
*
* @return int 0 on success, non-zero error code on failure.
*/
int
hal_spi_init(int spi_num, void *cfg, uint8_t spi_type)
{
int rc;
if (cfg == NULL) {
return SYS_EINVAL;
}
switch (spi_type) {
case HAL_SPI_TYPE_MASTER:
rc = hal_spi_init_master(spi_num, cfg);
if (rc != 0) {
return rc;
}
break;
case HAL_SPI_TYPE_SLAVE:
rc = hal_spi_init_slave(spi_num, cfg);
if (rc != 0) {
return rc;
}
break;
default:
return SYS_EINVAL;
}
return 0;
}
int
hal_spi_init_hw(uint8_t spi_num, uint8_t spi_type,
const struct hal_spi_hw_settings *cfg)
{
int i;
struct apollo3_spi_cfg hal_cfg;
hal_cfg.sck_pin = cfg->pin_sck;
hal_cfg.mosi_pin = cfg->pin_mosi;
hal_cfg.miso_pin = cfg->pin_miso;
for (i = 0; i < 4; i++) {
hal_cfg.ss_pin[i] = -1;
}
if (spi_type == HAL_SPI_TYPE_MASTER) {
int spi_index = hal_spi_get_uNCE(spi_num, cfg->pin_ss);
if (spi_index != -1) {
hal_cfg.ss_pin[spi_index] = cfg->pin_ss;
}
} else {
hal_cfg.ss_pin[0] = cfg->pin_ss;
}
return hal_spi_init(spi_num, &hal_cfg, spi_type);
}
/**
* Configure the spi. Must be called after the spi is initialized (after
* hal_spi_init is called) and when the spi is disabled (user must call
* hal_spi_disable if the spi has been enabled through hal_spi_enable prior
* to calling this function). Can also be used to reconfigure an initialized
* SPI (assuming it is disabled as described previously).
*
* @param spi_num The number of the SPI to configure.
* @param psettings The settings to configure this SPI with
*
* @return int 0 on success, non-zero error code on failure.
*/
int
hal_spi_config(int spi_num, struct hal_spi_settings *settings)
{
const struct apollo3_spi *spi;
int rc;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
if (spi->spi_type == HAL_SPI_TYPE_MASTER) {
rc = hal_spi_config_master(spi_num, settings);
} else {
rc = hal_spi_config_slave(spi_num, settings);
}
return rc;
}
/**
* Enables the SPI. This does not start a transmit or receive operation;
* it is used for power mgmt. Cannot be called when a SPI transfer is in
* progress.
*
* @param spi_num
*
* @return int 0 on success, non-zero error code on failure.
*/
int
hal_spi_enable(int spi_num)
{
struct apollo3_spi *spi;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
am_hal_iom_enable(spi->spi_handle);
return 0;
}
/**
* Disables the SPI. Used for power mgmt. It will halt any current SPI transfers
* in progress.
*
* @param spi_num
*
* @return int 0 on success, non-zero error code on failure.
*/
int
hal_spi_disable(int spi_num)
{
struct apollo3_spi *spi;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
am_hal_iom_disable(spi->spi_handle);
return 0;
}
/**
* Blocking call to send a value on the SPI. Returns the value received from
* the SPI slave.
*
* MASTER: Sends the value and returns the received value from the slave.
* SLAVE: Invalid API. Returns 0xFFFF
*
* @param spi_num Spi interface to use
* @param val Value to send
*
* @return uint16_t Value received on SPI interface from slave. Returns 0xFFFF
* if called when the SPI is configured to be a slave
*/
uint16_t
hal_spi_tx_val(int spi_num, uint16_t val)
{
am_hal_iom_transfer_t transaction;
struct apollo3_spi *spi;
uint32_t tx_buf = val;
uint32_t rx_buf = 0xffff;
int ss_pin_index;
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
ss_pin_index = hal_spi_get_uNCE(spi_num, spi->cur_ss_pin);
if (hal_spi_ss_pin_init(spi, ss_pin_index, spi->cur_ss_pin) != 0) {
return SYS_EINVAL;
}
memset(&transaction, 0x0, sizeof(am_hal_iom_transfer_t ));
transaction.eDirection = AM_HAL_IOM_FULLDUPLEX;
transaction.ui32NumBytes = sizeof(val);
transaction.pui32TxBuffer = &tx_buf;
transaction.pui32RxBuffer = &rx_buf;
transaction.bContinue = spi->cont_tx;
transaction.uPeerInfo.ui32SpiChipSelect = ss_pin_index;
if (am_hal_iom_spi_blocking_fullduplex(spi->spi_handle, &transaction) != AM_HAL_STATUS_SUCCESS) {
return 0xffff;
}
return rx_buf;
}
/**
* Sets the txrx callback (executed at interrupt context) when the
* buffer is transferred by the master or the slave using the non-blocking API.
* Cannot be called when the spi is enabled. This callback will also be called
* when chip select is de-asserted on the slave.
*
* NOTE: This callback is only used for the non-blocking interface and must
* be called prior to using the non-blocking API.
*
* @param spi_num SPI interface on which to set callback
* @param txrx Callback function
* @param arg Argument to be passed to callback function
*
* @return int 0 on success, non-zero error code on failure.
*/
int
hal_spi_set_txrx_cb(int spi_num, hal_spi_txrx_cb txrx_cb, void *arg)
{
/* Not implemented */
return SYS_ERANGE;
}
/**
* Blocking interface to send a buffer and store the received values from the
* slave. The transmit and receive buffers are either arrays of 8-bit (uint8_t)
* values or 16-bit values depending on whether the spi is configured for 8 bit
* data or more than 8 bits per value. The 'cnt' parameter is the number of
* 8-bit or 16-bit values. Thus, if 'cnt' is 10, txbuf/rxbuf would point to an
* array of size 10 (in bytes) if the SPI is using 8-bit data; otherwise
* txbuf/rxbuf would point to an array of size 20 bytes (ten, uint16_t values).
*
* NOTE: these buffers are in the native endian-ness of the platform.
*
* MASTER: master sends all the values in the buffer and stores the
* stores the values in the receive buffer if rxbuf is not NULL.
* The txbuf parameter cannot be NULL.
* SLAVE: cannot be called for a slave; returns -1
*
* @param spi_num SPI interface to use
* @param txbuf Pointer to buffer where values to transmit are stored.
* @param rxbuf Pointer to buffer to store values received from peer.
* @param cnt Number of 8-bit or 16-bit values to be transferred.
*
* @return int 0 on success, non-zero error code on failure.
*/
int
hal_spi_txrx(int spi_num, void *txbuf, void *rxbuf, int num_bytes)
{
am_hal_iom_transfer_t transaction;
struct apollo3_spi *spi;
int ss_pin_index;
/* Cannot operate if both tx and rx buf are NULL */
if(txbuf == NULL && rxbuf == NULL) {
return SYS_EINVAL;
}
spi = apollo3_spi_resolve(spi_num);
if (spi == NULL) {
return SYS_EINVAL;
}
ss_pin_index = hal_spi_get_uNCE(spi_num, spi->cur_ss_pin);
if (hal_spi_ss_pin_init(spi, ss_pin_index, spi->cur_ss_pin) != 0) {
return SYS_EINVAL;
}
memset(&transaction, 0x0, sizeof(am_hal_iom_transfer_t ));
transaction.ui32NumBytes = num_bytes;
transaction.bContinue = spi->cont_tx;
transaction.uPeerInfo.ui32SpiChipSelect = ss_pin_index;
if (rxbuf == NULL) {
/* Perform half duplex tx */
transaction.eDirection = AM_HAL_IOM_TX;
transaction.pui32TxBuffer = txbuf;
return am_hal_iom_blocking_transfer(spi->spi_handle, &transaction);
}
else if (txbuf == NULL) {
/* Perform half duplex rx */
transaction.eDirection = AM_HAL_IOM_RX;
transaction.pui32RxBuffer = rxbuf;
return am_hal_iom_blocking_transfer(spi->spi_handle, &transaction);
}
else {
/* Perform full duplex txrx */
transaction.eDirection = AM_HAL_IOM_FULLDUPLEX;
transaction.pui32TxBuffer = txbuf;
transaction.pui32RxBuffer = rxbuf;
return am_hal_iom_spi_blocking_fullduplex(spi->spi_handle, &transaction);
}
}
int
hal_spi_txrx_noblock(int spi_num, void *txbuf, void *rxbuf, int num_bytes)
{
/* Not implemented */
return SYS_ERANGE;
}
/**
* Sets the default value transferred by the slave. Not valid for master
*
* @param spi_num SPI interface to use
*
* @return int 0 on success, non-zero error code on failure.
*/
int
hal_spi_slave_set_def_tx_val(int spi_num, uint16_t val)
{
return SYS_ERANGE;
}
/**
* This aborts the current transfer but keeps the spi enabled.
*
* @param spi_num SPI interface on which transfer should be aborted.
*
* @return int 0 on success, non-zero error code on failure.
*
* NOTE: does not return an error if no transfer was in progress.
*/
int
hal_spi_abort(int spi_num)
{
return SYS_ERANGE;
}
#endif /* SPI_MASTER_ANY_ENABLED || SPI_SLAVE_ANY_ENABLED */