blob: 5882b43c0ed2f7c8bb02695e65440d3fdbd7ae77 [file] [log] [blame]
/*
* 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 <os/mynewt.h>
#include <mcu/da1469x_pd.h>
#include <mcu/da1469x_hal.h>
#include <hal/hal_spi.h>
#include <mcu/mcu.h>
/* The maximum number of SPI interfaces we will allow */
#define DA1469X_HAL_SPI_MAX (2)
#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_1_MASTER)
#define SPI_MASTER_CODE 1
#else
#define SPI_MASTER_CODE 0
#endif
#if MYNEWT_VAL(SPI_0_SLAVE) || MYNEWT_VAL(SPI_1_SLAVE)
#defien SPI_SLAVE_CODE 1
#else
#define SPI_SLAVE_CODE 0
#endif
#if SPI_MASTER_CODE || SPI_SLAVE_CODE
struct da1469x_hal_spi_controller {
SPI_Type *regs;
uint8_t spi_num;
uint8_t spi_clk_func;
uint8_t spi_do_func;
uint8_t spi_di_func;
uint8_t spi_ss_func;
uint8_t irq_num;
void (* irq_handler)(void);
};
struct da1469x_hal_spi {
uint8_t spi_type;
struct hal_spi_settings spi_cfg; /* Slave and master */
/* SPI controller data */
const struct da1469x_hal_spi_controller *hw;
const uint8_t *txbuf; /* Pointer to TX buffer */
uint8_t *rxbuf; /* Pointer to RX buffer */
uint16_t len; /* Length of buffer(s) */
uint16_t txlen; /* Number of bytes sent so far */
uint16_t rxlen; /* Number of bytes received so far */
/* Callback and arguments */
hal_spi_txrx_cb txrx_cb_func;
void *txrx_cb_arg;
};
void SPI_Handler(void);
void SPI2_Handler(void);
#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_0_SLAVE)
static const struct da1469x_hal_spi_controller hal_spi0_controller = {
.regs = (SPI_Type *)SPI,
.spi_num = 0,
.spi_clk_func = MCU_GPIO_FUNC_SPI_CLK,
.spi_do_func = MCU_GPIO_FUNC_SPI_DO,
.spi_di_func = MCU_GPIO_FUNC_SPI_DI,
.spi_ss_func = MCU_GPIO_FUNC_SPI_EN,
.irq_num = SPI_IRQn,
.irq_handler = SPI_Handler,
};
struct da1469x_hal_spi hal_spi0 = {
.hw = &hal_spi0_controller,
};
#endif
#if MYNEWT_VAL(SPI_1_MASTER) || MYNEWT_VAL(SPI_1_SLAVE)
static const struct da1469x_hal_spi_controller hal_spi1_controller = {
.regs = (SPI_Type *)SPI2,
.spi_num = 1,
.spi_clk_func = MCU_GPIO_FUNC_SPI2_CLK,
.spi_do_func = MCU_GPIO_FUNC_SPI2_DO,
.spi_di_func = MCU_GPIO_FUNC_SPI2_DI,
.spi_ss_func = MCU_GPIO_FUNC_SPI2_EN,
.irq_num = SPI2_IRQn,
.irq_handler = SPI2_Handler,
};
struct da1469x_hal_spi hal_spi1 = {
.hw = &hal_spi1_controller,
};
#endif
static struct da1469x_hal_spi *da1469x_hal_spis[DA1469X_HAL_SPI_MAX] = {
#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_0_SLAVE)
&hal_spi0,
#else
NULL,
#endif
#if MYNEWT_VAL(SPI_1_MASTER) || MYNEWT_VAL(SPI_1_SLAVE)
&hal_spi1
#else
NULL
#endif
};
static struct da1469x_hal_spi *
hal_spi_resolve(int spi_num)
{
if (spi_num >= DA1469X_HAL_SPI_MAX) {
return NULL;
}
return da1469x_hal_spis[spi_num];
}
static bool
da1469x_hal_spi_do_transfer(struct da1469x_hal_spi *spi)
{
SPI_Type *regs = spi->hw->regs;
uint32_t ctrl_reg;
while (spi->rxlen < spi->len || spi->txlen < spi->len) {
ctrl_reg = regs->SPI_CTRL_REG;
if (0 == (ctrl_reg & SPI_SPI_CTRL_REG_SPI_RX_FIFO_EMPTY_Msk)) {
if (spi->rxlen < spi->len) {
spi->rxbuf[spi->rxlen++] = (uint8_t)regs->SPI_RX_TX_REG;
}
} else if (0 != (ctrl_reg & SPI_SPI_CTRL_REG_SPI_TXH_Msk)) {
if (spi->txlen < spi->len) {
regs->SPI_RX_TX_REG = spi->txbuf[spi->txlen++];
}
} else {
/* Transfer not finished yet, but there is nothing more to send
* or TX FIFO is full for now */
return false;
}
}
return true;
}
static void
da1469x_hal_spi_irq_handler(struct da1469x_hal_spi *spi)
{
SPI_Type *regs = spi->hw->regs;
if (!da1469x_hal_spi_do_transfer(spi)) {
if (spi->txlen >= spi->len) {
/* No need for interrupt from TX fifo */
regs->SPI_CTRL_REG &= ~SPI_SPI_CTRL_REG_SPI_TX_FIFO_NOTFULL_MASK_Msk;
}
regs->SPI_CLEAR_INT_REG = 1;
} else {
regs->SPI_CTRL_REG &= ~(SPI_SPI_CTRL_REG_SPI_TX_FIFO_NOTFULL_MASK_Msk |
SPI_SPI_CTRL_REG_SPI_MINT_Msk);
if (spi->txrx_cb_func) {
spi->txrx_cb_func(spi->txrx_cb_arg, spi->len);
}
}
}
#if MYNEWT_VAL(SPI_0_MASTER) || MYNEWT_VAL(SPI_0_SLAVE)
void
SPI_Handler(void)
{
da1469x_hal_spi_irq_handler(&hal_spi0);
}
#endif
#if MYNEWT_VAL(SPI_1_MASTER) || MYNEWT_VAL(SPI_1_SLAVE)
void
SPI2_Handler(void)
{
da1469x_hal_spi_irq_handler(&hal_spi1);
}
#endif
static int
hal_spi_init_master(const struct da1469x_hal_spi *spi,
const struct da1469x_hal_spi_cfg *cfg)
{
int irq_num = spi->hw->irq_num;
/* Configure pins */
mcu_gpio_set_pin_function(cfg->pin_sck, MCU_GPIO_MODE_OUTPUT,
spi->hw->spi_clk_func);
if (cfg->pin_do >= 0) {
mcu_gpio_set_pin_function(cfg->pin_do, MCU_GPIO_MODE_OUTPUT,
spi->hw->spi_do_func);
}
if (cfg->pin_di >= 0) {
mcu_gpio_set_pin_function(cfg->pin_di, MCU_GPIO_MODE_INPUT,
spi->hw->spi_di_func);
}
spi->hw->regs->SPI_CLEAR_INT_REG = 0;
spi->hw->regs->SPI_CTRL_REG = 0;
if (spi->hw->spi_num == 0 && MYNEWT_VAL(SPI_0_MASTER)) {
CRG_COM->RESET_CLK_COM_REG = CRG_COM_RESET_CLK_COM_REG_SPI_CLK_SEL_Msk;
CRG_COM->SET_CLK_COM_REG = CRG_COM_RESET_CLK_COM_REG_SPI_ENABLE_Msk;
} else if (spi->hw->spi_num == 1 && MYNEWT_VAL(SPI_1_MASTER)) {
CRG_COM->RESET_CLK_COM_REG = CRG_COM_RESET_CLK_COM_REG_SPI2_CLK_SEL_Msk;
CRG_COM->SET_CLK_COM_REG = CRG_COM_RESET_CLK_COM_REG_SPI2_ENABLE_Msk;
}
NVIC_SetVector(irq_num, (uint32_t)spi->hw->irq_handler);
NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1);
NVIC_ClearPendingIRQ(irq_num);
NVIC_EnableIRQ(irq_num);
return 0;
}
static int
hal_spi_init_slave(const struct da1469x_hal_spi *spi,
const struct da1469x_hal_spi_cfg *cfg)
{
return -1;
}
int
hal_spi_init(int spi_num, void *cfg, uint8_t spi_type)
{
int rc;
struct da1469x_hal_spi *spi;
if (cfg == NULL) {
return SYS_EINVAL;
}
spi = hal_spi_resolve(spi_num);
if (!spi) {
return SYS_EINVAL;
}
if ((spi_type != HAL_SPI_TYPE_MASTER) && (spi_type != HAL_SPI_TYPE_SLAVE)) {
return SYS_EINVAL;
}
da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
spi->spi_type = spi_type;
rc = hal_spi_disable(spi_num);
if (rc) {
return rc;
}
if (spi_type == HAL_SPI_TYPE_MASTER && SPI_MASTER_CODE) {
rc = hal_spi_init_master(spi, (struct da1469x_hal_spi_cfg *)cfg);
} else if (SPI_SLAVE_CODE) {
rc = hal_spi_init_slave(spi, (struct da1469x_hal_spi_cfg *)cfg);
} else {
rc = SYS_EINVAL;
}
return rc;
}
int
hal_spi_config(int spi_num, struct hal_spi_settings *settings)
{
SPI_Type *regs;
uint32_t ctrl_reg;
struct da1469x_hal_spi *spi;
if (settings == NULL) {
return SYS_EINVAL;
}
spi = hal_spi_resolve(spi_num);
if (!spi) {
return SYS_EINVAL;
}
regs = spi->hw->regs;
regs->SPI_CTRL_REG &= ~SPI_SPI_CTRL_REG_SPI_ON_Msk;
regs->SPI_CTRL_REG |= SPI_SPI_CTRL_REG_SPI_RST_Msk;
/* Preserve some register fields only */
ctrl_reg = regs->SPI_CTRL_REG & (SPI_SPI_CTRL_REG_SPI_TX_FIFO_NOTFULL_MASK_Msk |
SPI_SPI_CTRL_REG_SPI_DMA_TXREQ_MODE_Msk |
SPI_SPI_CTRL_REG_SPI_PRIORITY_Msk |
SPI_SPI_CTRL_REG_SPI_EN_CTRL_Msk |
SPI_SPI_CTRL_REG_SPI_SMN_Msk |
SPI_SPI_CTRL_REG_SPI_DO_Msk |
SPI_SPI_CTRL_REG_SPI_RST_Msk);
assert(settings->data_order == HAL_SPI_MSB_FIRST);
switch (settings->baudrate) {
case 16000:
ctrl_reg |= (2U << SPI_SPI_CTRL_REG_SPI_CLK_Pos);
break;
case 8000:
ctrl_reg |= (1U << SPI_SPI_CTRL_REG_SPI_CLK_Pos);
break;
case 4000:
ctrl_reg |= (0U << SPI_SPI_CTRL_REG_SPI_CLK_Pos);
break;
default:
/* Slowest possibly clock, divider 14, 2.28MHz */
ctrl_reg |= (3U << SPI_SPI_CTRL_REG_SPI_CLK_Pos);
break;
}
switch (settings->data_mode) {
case HAL_SPI_MODE0:
/* Bits already zeroed */
break;
case HAL_SPI_MODE1:
ctrl_reg |= (1U << SPI_SPI_CTRL_REG_SPI_PHA_Pos);
break;
case HAL_SPI_MODE2:
ctrl_reg |= (1U << SPI_SPI_CTRL_REG_SPI_POL_Pos);
break;
case HAL_SPI_MODE3:
ctrl_reg |= (1U << SPI_SPI_CTRL_REG_SPI_PHA_Pos) |
(1U << SPI_SPI_CTRL_REG_SPI_POL_Pos);
break;
default:
assert(0);
break;
}
if (settings->word_size == HAL_SPI_WORD_SIZE_9BIT) {
ctrl_reg |= (1U << SPI_SPI_CTRL_REG_SPI_WORD_Pos);
}
regs->SPI_CTRL_REG = ctrl_reg;
/* At this point interrupt is cleared, FIFO is enabled, controller is disabled */
return 0;
}
int
hal_spi_enable(int spi_num)
{
SPI_Type *regs;
struct da1469x_hal_spi *spi;
spi = hal_spi_resolve(spi_num);
if (!spi) {
return SYS_EINVAL;
}
regs = spi->hw->regs;
if (regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_BUSY_Msk) {
return SYS_EBUSY;
}
regs->SPI_CTRL_REG |= SPI_SPI_CTRL_REG_SPI_ON_Msk;
regs->SPI_CTRL_REG &= ~SPI_SPI_CTRL_REG_SPI_RST_Msk;
return 0;
}
int
hal_spi_disable(int spi_num)
{
SPI_Type *regs;
struct da1469x_hal_spi *spi;
spi = hal_spi_resolve(spi_num);
if (!spi) {
return SYS_EINVAL;
}
regs = spi->hw->regs;
while (regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_BUSY_Msk) {
}
regs->SPI_CTRL_REG &= ~(SPI_SPI_CTRL_REG_SPI_ON_Msk |
SPI_SPI_CTRL_REG_SPI_INT_BIT_Msk);
regs->SPI_CTRL_REG |= SPI_SPI_CTRL_REG_SPI_RST_Msk;
return 0;
}
uint16_t
hal_spi_tx_val(int spi_num, uint16_t val)
{
SPI_Type *regs;
struct da1469x_hal_spi *spi;
uint16_t dummy;
uint32_t ctrl_reg;
bool nine_bits = false;
spi = hal_spi_resolve(spi_num);
if (!spi || spi->spi_type == HAL_SPI_TYPE_SLAVE) {
return 0xFFFF;
}
regs = spi->hw->regs;
/* Get rid of old data if any */
while (!(regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_TX_FIFO_EMPTY_Msk)) {
}
while (!(regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_RX_FIFO_EMPTY_Msk)) {
dummy = regs->SPI_RX_TX_REG;
(void)dummy;
}
ctrl_reg = regs->SPI_CTRL_REG;
/* 9-bit word */
nine_bits = (ctrl_reg & SPI_SPI_CTRL_REG_SPI_WORD_Msk) ==
(3U << SPI_SPI_CTRL_REG_SPI_WORD_Pos);
if (nine_bits) {
ctrl_reg &= ~SPI_SPI_CTRL_REG_SPI_9BIT_VAL_Msk;
ctrl_reg |= (val << (SPI_SPI_CTRL_REG_SPI_9BIT_VAL_Pos - 8) ) &
SPI_SPI_CTRL_REG_SPI_9BIT_VAL_Msk;
}
regs->SPI_RX_TX_REG = (uint8_t)val;
while (regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_RX_FIFO_EMPTY_Msk) {
}
ctrl_reg = regs->SPI_CTRL_REG;
val = (uint8_t)regs->SPI_RX_TX_REG;
if (nine_bits) {
val |= (ctrl_reg & SPI_SPI_CTRL_REG_SPI_9BIT_VAL_Msk) >>
(SPI_SPI_CTRL_REG_SPI_9BIT_VAL_Pos - 8);
}
return val;
}
int
hal_spi_set_txrx_cb(int spi_num, hal_spi_txrx_cb txrx_cb, void *arg)
{
SPI_Type *regs;
struct da1469x_hal_spi *spi;
int rc = 0;
spi = hal_spi_resolve(spi_num);
if (!spi) {
rc = SYS_EINVAL;
goto err;
}
regs = spi->hw->regs;
if ((regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_ON_Msk) != 0) {
rc = SYS_EINVAL;
} else {
spi->txrx_cb_func = txrx_cb;
spi->txrx_cb_arg = arg;
}
err:
return rc;
}
int
hal_spi_txrx(int spi_num, void *txbuf, void *rxbuf, int len)
{
SPI_Type *regs;
struct da1469x_hal_spi *spi;
int rc = 0;
const uint8_t *tx;
uint8_t *rx;
int rxlen = 0;
uint8_t val;
spi = hal_spi_resolve(spi_num);
if (spi == NULL || txbuf == NULL || spi->spi_type != HAL_SPI_TYPE_MASTER) {
rc = SYS_EINVAL;
goto err;
}
regs = spi->hw->regs;
tx = txbuf;
rx = rxbuf;
/* Flush RX FIFO */
while (!(regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_RX_FIFO_EMPTY_Msk)) {
val = (uint8_t)regs->SPI_RX_TX_REG;
}
rxlen = len;
while (len) {
if (0 == (regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_TXH_Msk)) {
regs->SPI_RX_TX_REG = *tx++;
len--;
}
if (0 == (regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_RX_FIFO_EMPTY_Msk)) {
val = (uint8_t)regs->SPI_RX_TX_REG;
if (rx) {
*rx++ = val;
}
rxlen--;
}
}
while (rxlen) {
if (0 == (regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_RX_FIFO_EMPTY_Msk)) {
val = (uint8_t)regs->SPI_RX_TX_REG;
if (rx) {
*rx++ = val;
}
rxlen--;
}
}
err:
return rc;
}
int
hal_spi_txrx_noblock(int spi_num, void *txbuf, void *rxbuf, int len)
{
SPI_Type *regs;
struct da1469x_hal_spi *spi;
uint32_t ctrl_reg;
int rc = 0;
spi = hal_spi_resolve(spi_num);
if (spi == NULL) {
rc = SYS_EINVAL;
goto err;
}
if (SPI_MASTER_CODE && txbuf == NULL && spi->spi_type != HAL_SPI_TYPE_MASTER) {
rc = SYS_EINVAL;
goto err;
} else if (SPI_SLAVE_CODE && txbuf == NULL && rxbuf == NULL &&
spi->spi_type == HAL_SPI_TYPE_SLAVE) {
rc = SYS_EINVAL;
goto err;
}
regs = spi->hw->regs;
spi->txbuf = txbuf;
spi->rxbuf = rxbuf;
spi->len = (uint16_t)len;
spi->txlen = 0;
spi->rxlen = 0;
if (da1469x_hal_spi_do_transfer(spi)) {
if (spi->txrx_cb_func) {
spi->txrx_cb_func(spi->txrx_cb_arg, spi->len);
}
} else {
ctrl_reg = regs->SPI_CTRL_REG | SPI_SPI_CTRL_REG_SPI_MINT_Msk;
if (spi->txlen < spi->len) {
ctrl_reg |= SPI_SPI_CTRL_REG_SPI_TX_FIFO_NOTFULL_MASK_Msk;
}
regs->SPI_CTRL_REG = ctrl_reg;
}
err:
return rc;
}
int
hal_spi_slave_set_def_tx_val(int spi_num, uint16_t val)
{
return 0;
}
int
hal_spi_abort(int spi_num)
{
SPI_Type *regs;
struct da1469x_hal_spi *spi;
int rc = 0;
spi = hal_spi_resolve(spi_num);
if (spi == NULL) {
rc = SYS_EINVAL;
goto err;
}
regs = spi->hw->regs;
regs->SPI_CTRL_REG &= ~(SPI_SPI_CTRL_REG_SPI_MINT_Msk |
SPI_SPI_CTRL_REG_SPI_TX_FIFO_NOTFULL_MASK_Msk);
spi->len = 0;
spi->txlen = 0;
spi->rxlen = 0;
err:
return rc;
}
int
hal_spi_init_hw(uint8_t spi_num, uint8_t spi_type,
const struct hal_spi_hw_settings *cfg)
{
struct da1469x_hal_spi_cfg hal_cfg;
hal_cfg.pin_sck = (uint8_t)cfg->pin_sck;
if (spi_type == HAL_SPI_TYPE_MASTER) {
hal_cfg.pin_do = (uint8_t)cfg->pin_mosi;
hal_cfg.pin_di = (uint8_t)cfg->pin_miso;
} else {
hal_cfg.pin_di = (uint8_t)cfg->pin_mosi;
hal_cfg.pin_do = (uint8_t)cfg->pin_miso;
}
hal_cfg.pin_ss = (uint8_t)cfg->pin_ss;
return hal_spi_init(spi_num, &hal_cfg, spi_type);
}
#endif