6a3c2aded6
* Simplify EINTR/ECANCEL error handling 1. Add semaphore uninterruptible wait function 2 .Replace semaphore wait loop with a single uninterruptible wait 3. Replace all sem_xxx to nxsem_xxx * Unify the void cast usage 1. Remove void cast for function because many place ignore the returned value witout cast 2. Replace void cast for variable with UNUSED macro
2313 lines
61 KiB
C
2313 lines
61 KiB
C
/****************************************************************************
|
|
* drivers/modem/altmdm/altmdm_spi.c
|
|
*
|
|
* Copyright 2018 Sony Semiconductor Solutions Corporation
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name of Sony Semiconductor Solutions Corporation nor
|
|
* the names of its contributors may be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
#include <string.h>
|
|
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/signal.h>
|
|
#include <nuttx/spi/spi.h>
|
|
#include <nuttx/modem/altmdm.h>
|
|
|
|
#include "altmdm_sys.h"
|
|
#include "altmdm_pm.h"
|
|
#include "altmdm_pm_state.h"
|
|
|
|
#if defined(CONFIG_MODEM_ALTMDM)
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define EVENT_BIT(b) (1<<(b))
|
|
#define EVENT_NONE (0)
|
|
#define EVENT_TXREQ EVENT_BIT(0)
|
|
#define EVENT_RXREQ EVENT_BIT(1)
|
|
#define EVENT_CANCEL EVENT_BIT(2)
|
|
#define EVENT_EXIT EVENT_BIT(3)
|
|
#define EVENT_RXRDY EVENT_BIT(4)
|
|
#define EVENT_RXBUFRDY EVENT_BIT(5)
|
|
#define EVENT_TX_DONE EVENT_BIT(6)
|
|
#define EVENT_RX_DONE EVENT_BIT(7)
|
|
#define EVENT_SLEEPREQ EVENT_BIT(8)
|
|
#define EVENT_SLEEP_DONE EVENT_BIT(9)
|
|
#define EVENT_SV_TIMER_EXP EVENT_BIT(10)
|
|
#define EVENT_XFERRDY EVENT_BIT(11)
|
|
#define EVENT_REQMASK (EVENT_TXREQ | EVENT_RXREQ | EVENT_SLEEPREQ | \
|
|
EVENT_SV_TIMER_EXP)
|
|
#define EVENT_TRANS_WAIT (EVENT_TXREQ | EVENT_RXREQ | EVENT_RXBUFRDY | \
|
|
EVENT_SLEEPREQ | EVENT_SV_TIMER_EXP | EVENT_EXIT)
|
|
#define XFER_TASK_PRI (90)
|
|
#define XFER_TASK_STKSIZE (1536)
|
|
#define XFER_TASK_NAME "altmdm_xfer_task"
|
|
#if defined(CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE)
|
|
# if ((CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE & 0x3) != 0)
|
|
# error MODEM_ALTMDM_MAX_PACKET_SIZE must be aligned 0x4 (4B)
|
|
# endif
|
|
# define MAX_PKT_SIZE (CONFIG_MODEM_ALTMDM_MAX_PACKET_SIZE)
|
|
#else
|
|
# define MAX_PKT_SIZE (2064)
|
|
#endif
|
|
#define UNIT_SIZE (4)
|
|
#define RX_ENABLE (0)
|
|
#define RX_DISABLE (1)
|
|
#define SLEEP_OK (0)
|
|
#define SLEEP_NG (-EBUSY)
|
|
|
|
/* Timeout is counted in units of millisecond. */
|
|
|
|
#define WAIT_RXREQ_TIMEOUT (1000)
|
|
#define WAIT_XFERRDY_TIMEOUT (25 * 1000)
|
|
#if defined(CONFIG_MODEM_ALTMDM_SLEEP_TIMER_VAL)
|
|
# if (CONFIG_MODEM_ALTMDM_SLEEP_TIMER_VAL < 20)
|
|
# error MODEM_ALTMDM_SLEEP_TIMER_VAL too small
|
|
# endif
|
|
# define SV_TIMER_TIMOUT_VAL (CONFIG_MODEM_ALTMDM_SLEEP_TIMER_VAL)
|
|
#else
|
|
# define SV_TIMER_TIMOUT_VAL (20)
|
|
#endif
|
|
#define WRITE_WAIT_TIMEOUT (ALTMDM_SYS_FLAG_TMOFEVR)
|
|
#define SREQ_WAIT_TIMEOUT (ALTMDM_SYS_FLAG_TMOFEVR)
|
|
|
|
#define SPI_MAXFREQUENCY (13000000) /* 13MHz. */
|
|
|
|
#define GPIO_SREQ_INT_POLARITY (ALTMDM_GPIOINT_LEVEL_HIGH)
|
|
#define GPIO_SREQ_INT_NOISE_FILTER (ALTMDM_GPIOINT_NOISE_FILTER_DISABLE)
|
|
|
|
/* Defines for transfer mode */
|
|
|
|
#define MODE_RXDATA (0) /* Data receive mode. */
|
|
#define MODE_TXDATA (1) /* Data send mode. */
|
|
#define MODE_TRXDATA (2) /* Data send and receive mode. */
|
|
#define MODE_RXDATANOBUFF (3) /* Data receive mode when there is no
|
|
* receiving buffer.
|
|
*/
|
|
#define MODE_TRXDATANOBUFF (4) /* Data send and receive mode when
|
|
* there is no receiving buffer.
|
|
*/
|
|
#define MODE_RXINVALID (5) /* Data receive mode when receiving
|
|
* header is wrong.
|
|
*/
|
|
#define MODE_TRXHEADERFAILTXREQ (6) /* Data send and receive mode when
|
|
* header transfer fails. Send request
|
|
* triggered.
|
|
*/
|
|
#define MODE_TRXHEADERFAILRXREQ (7) /* Data receive mode when header
|
|
* transfer fails. Receive request
|
|
* triggered.
|
|
*/
|
|
#define MODE_RXRESET (8) /* Reset packet receive mode. */
|
|
#define MODE_TRXRESET (9) /* Data send and reset packet receive
|
|
* mode.
|
|
*/
|
|
|
|
/* Defines for transfer result code */
|
|
|
|
#define TRANS_OK (1) /* OK. */
|
|
#define TRANS_OK_RXDATANOBUFF (-1) /* OK when MODE_RXDATANOBUFF mode. */
|
|
#define TRANS_OK_TRXDATANORXBUFF (-2) /* OK when MODE_TRXDATANOBUFF mode. */
|
|
#define TRANS_RXINVALID (-3) /* NG when MODE_RXINVALID mode. */
|
|
#define TRANS_WAITRCVRTMO (-4) /* NG when receiver ready timeout. */
|
|
#define TRANS_OK_RCVBUFFUL (-5) /* OK when receiver is buffer full. */
|
|
|
|
#define RESET_BOOTSTAT_BOOTING (0) /* Boot stat: booting */
|
|
#define RESET_BOOTSTAT_UPDATING (1) /* Boot stat: updating */
|
|
|
|
#define STAT_INF_GET_BOOTSTAT (1 << 1) /* Status info: Get bootstatus bit */
|
|
#define STAT_INF_RESET (1 << 2) /* Status info: Reset bit */
|
|
#define STAT_INF_BUFFFULL (1 << 3) /* Status info: Buffer full bit */
|
|
|
|
#define STAT_INF_IS_RESET(info) ((info & STAT_INF_RESET) >> 2)
|
|
#define STAT_INF_IS_BUFF_FULL(info) ((info & STAT_INF_BUFFFULL) >> 3)
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static struct altmdm_dev_s *g_privdata = NULL;
|
|
static char g_tmp_rxbuff[MAX_PKT_SIZE];
|
|
static char g_tmp_txbuff[MAX_PKT_SIZE];
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: svtimer_handler
|
|
*
|
|
* Description:
|
|
* Timeout handler for supervisory timer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void svtimer_handler(int signo, FAR siginfo_t * info,
|
|
FAR void *ucontext)
|
|
{
|
|
FAR struct altmdm_dev_s *priv =
|
|
(FAR struct altmdm_dev_s *)(info->si_value.sival_ptr);
|
|
|
|
altmdm_sys_setflag(&priv->spidev.xfer_flag, EVENT_SV_TIMER_EXP);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: init_svtimer
|
|
*
|
|
* Description:
|
|
* Initialize supervisory timer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int init_svtimer(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
priv->spidev.sleep_param.sv_timerid = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: delete_svtimer
|
|
*
|
|
* Description:
|
|
* Delete supervisory timer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int delete_svtimer(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
altmdm_sys_stoptimer(priv->spidev.sleep_param.sv_timerid);
|
|
priv->spidev.sleep_param.sv_timerid = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: start_svtimer
|
|
*
|
|
* Description:
|
|
* Start supervisory timer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int start_svtimer(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
timer_t timerid;
|
|
|
|
timerid = altmdm_sys_starttimer(SV_TIMER_TIMOUT_VAL, SV_TIMER_TIMOUT_VAL,
|
|
svtimer_handler, 0, priv);
|
|
if (timerid == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
priv->spidev.sleep_param.sv_timerid = timerid;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: stop_svtimer
|
|
*
|
|
* Description:
|
|
* Stop supervisory timer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int stop_svtimer(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
altmdm_sys_stoptimer(priv->spidev.sleep_param.sv_timerid);
|
|
priv->spidev.sleep_param.sv_timerid = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_dmaxfer
|
|
*
|
|
* Description:
|
|
* Execute DMA transfer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_dmaxfer(FAR struct altmdm_dev_s *priv, FAR void *tx_buffer,
|
|
FAR void *rx_buffer, size_t dma_size)
|
|
{
|
|
SPI_EXCHANGE(priv->spi, tx_buffer, rx_buffer, dma_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: get_dmasize
|
|
*
|
|
* Description:
|
|
* Get the data size used for DMA transfer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int get_dmasize(FAR struct altmdm_dev_s *priv, int data_size)
|
|
{
|
|
return data_size;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: wait_receiverready
|
|
*
|
|
* Description:
|
|
* Wait until reciever is ready.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int wait_receiverready(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
uint32_t ptn;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
ret = altmdm_sys_waitflag(&spidev->xfer_flag, EVENT_RXREQ,
|
|
ALTMDM_SYS_FLAG_WMODEOR, &ptn,
|
|
WAIT_RXREQ_TIMEOUT);
|
|
if (ret != 0)
|
|
{
|
|
m_err("receiver ready timeout.\n");
|
|
return TRANS_WAITRCVRTMO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: wait_xferready
|
|
*
|
|
* Description:
|
|
* Wait until xfer is ready.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int wait_xferready(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
uint32_t ptn;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
ret = altmdm_sys_waitflag(&spidev->xferready_flag, EVENT_XFERRDY,
|
|
ALTMDM_SYS_FLAG_WMODEOR, &ptn,
|
|
WAIT_XFERRDY_TIMEOUT);
|
|
if (ret != 0)
|
|
{
|
|
m_err("xfer ready timeout.\n");
|
|
|
|
/* Make it ready to transfer.
|
|
* It is assumed that modem does not implement reset packet.
|
|
*/
|
|
|
|
if (!spidev->is_xferready)
|
|
{
|
|
spidev->is_xferready = true;
|
|
m_info("ready to xfer\n");
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: notify_xferready
|
|
*
|
|
* Description:
|
|
* Notify xfer is ready.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int notify_xferready(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
ret = altmdm_sys_setflag(&spidev->xferready_flag, EVENT_XFERRDY);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: init_rxbuffer
|
|
*
|
|
* Description:
|
|
* Initialize the receive buffer used for data transfer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void init_rxbuffer(FAR struct altmdm_dev_s *priv,
|
|
FAR struct altmdm_spi_rxbuff_s **rxbuff,
|
|
uint32_t unit_size)
|
|
{
|
|
FAR struct altmdm_spi_rxbuff_s *l_buff = NULL;
|
|
|
|
l_buff = (FAR struct altmdm_spi_rxbuff_s *)kmm_malloc
|
|
(sizeof(struct altmdm_spi_rxbuff_s));
|
|
if (l_buff == NULL)
|
|
{
|
|
m_err("cannot allocate memory for received buffer\n");
|
|
}
|
|
else
|
|
{
|
|
memset(l_buff, 0x00, sizeof(struct altmdm_spi_rxbuff_s));
|
|
|
|
l_buff->buff_addr = (char *)kmm_malloc(unit_size);
|
|
if (l_buff->buff_addr == NULL)
|
|
{
|
|
m_err("cannot allocate memory for received buffer\n");
|
|
kmm_free(l_buff);
|
|
l_buff = NULL;
|
|
}
|
|
else
|
|
{
|
|
l_buff->buff_size = unit_size;
|
|
}
|
|
}
|
|
|
|
*rxbuff = l_buff;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: uninit_rxbuffer
|
|
*
|
|
* Description:
|
|
* Uninitialize the receive buffer used for data transfer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void uninit_rxbuffer(FAR struct altmdm_dev_s *priv,
|
|
FAR struct altmdm_spi_rxbuff_s *rxbuff)
|
|
{
|
|
if (rxbuff != NULL)
|
|
{
|
|
if (rxbuff->buff_addr != NULL)
|
|
{
|
|
kmm_free(rxbuff->buff_addr);
|
|
}
|
|
|
|
kmm_free(rxbuff);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: alloc_rxbuffer
|
|
*
|
|
* Description:
|
|
* Get the allocated receive buffer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void alloc_rxbuffer(FAR struct altmdm_dev_s *priv,
|
|
FAR struct altmdm_spi_rxbuff_s **rxbuff,
|
|
uint32_t size)
|
|
{
|
|
if (priv->spidev.rxbuffinfo.free_buff == NULL)
|
|
{
|
|
m_err("cannot allocate free rx buffer\n");
|
|
}
|
|
else
|
|
{
|
|
*rxbuff = priv->spidev.rxbuffinfo.free_buff;
|
|
priv->spidev.rxbuffinfo.free_buff = NULL;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: free_rxbuffer
|
|
*
|
|
* Description:
|
|
* Release allocated receive buffer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void free_rxbuffer(FAR struct altmdm_dev_s *priv,
|
|
FAR struct altmdm_spi_rxbuff_s *rxbuff)
|
|
{
|
|
if (priv->spidev.rxbuffinfo.free_buff != NULL)
|
|
{
|
|
m_err("cannot free rx buffer\n");
|
|
}
|
|
else
|
|
{
|
|
priv->spidev.rxbuffinfo.free_buff = rxbuff;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: create_rxbufffifo
|
|
*
|
|
* Description:
|
|
* Create receiving FIFO. This fifo is used when copying to the buffer
|
|
* specified by the user.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void create_rxbufffifo(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo;
|
|
|
|
init_rxbuffer(priv, &priv->spidev.rxbuffinfo.free_buff, MAX_PKT_SIZE);
|
|
|
|
fifo->head = NULL;
|
|
fifo->tail = NULL;
|
|
|
|
altmdm_sys_initcsem(&fifo->csem);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: destroy_rxbufffifo
|
|
*
|
|
* Description:
|
|
* Destroy receiving FIFO.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void destroy_rxbufffifo(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo;
|
|
|
|
uninit_rxbuffer(priv, priv->spidev.rxbuffinfo.free_buff);
|
|
|
|
altmdm_sys_deletecsem(&fifo->csem);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: put_rxbufffifo
|
|
*
|
|
* Description:
|
|
* Put date into the receiving FIFO.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void put_rxbufffifo(FAR struct altmdm_dev_s *priv,
|
|
FAR struct altmdm_spi_rxbuff_s *rxbuff)
|
|
{
|
|
FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo;
|
|
irqstate_t flags;
|
|
|
|
flags = enter_critical_section();
|
|
|
|
if (fifo->head == NULL)
|
|
{
|
|
fifo->head = rxbuff;
|
|
fifo->tail = rxbuff;
|
|
rxbuff->next = NULL;
|
|
}
|
|
else
|
|
{
|
|
fifo->tail->next = rxbuff;
|
|
fifo->tail = rxbuff;
|
|
rxbuff->next = NULL;
|
|
}
|
|
|
|
leave_critical_section(flags);
|
|
|
|
altmdm_sys_postcsem(&fifo->csem);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: get_rxbufffifo
|
|
*
|
|
* Description:
|
|
* Get date from the receiving FIFO. If the FIFO is empty,
|
|
* it is kept waiting until data is put in the FIFO.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void get_rxbufffifo(FAR struct altmdm_dev_s *priv,
|
|
FAR struct altmdm_spi_rxbuff_s **rxbuff)
|
|
{
|
|
FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo;
|
|
irqstate_t flags;
|
|
|
|
*rxbuff = NULL;
|
|
|
|
altmdm_sys_waitcsem(&fifo->csem);
|
|
|
|
flags = enter_critical_section();
|
|
|
|
if (fifo->head != NULL)
|
|
{
|
|
*rxbuff = fifo->head;
|
|
fifo->head = fifo->head->next;
|
|
}
|
|
|
|
leave_critical_section(flags);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: abort_get_rxbufffifo
|
|
*
|
|
* Description:
|
|
* If waiting for data to be put in the FIFO, then abort it.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void abort_get_rxbufffifo(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int val;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
FAR struct altmdm_spi_rxbufffifo_s *fifo = &priv->spidev.rxbuffinfo.fifo;
|
|
|
|
if (!altmdm_sys_getcsemvalue(&fifo->csem, &val))
|
|
{
|
|
if (val < 0)
|
|
{
|
|
spidev->rx_param.rxabort = true;
|
|
altmdm_sys_postcsem(&fifo->csem);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: clear_txheader
|
|
*
|
|
* Description:
|
|
* Clear the header for transmission.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void clear_txheader(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
memset(&priv->spidev.tx_param.header, 0x00,
|
|
sizeof(struct altmdm_spi_xferhdr_s));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: clear_rxheader
|
|
*
|
|
* Description:
|
|
* Clear the header for reception.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void clear_rxheader(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
memset(&priv->spidev.rx_param.header, 0x00,
|
|
sizeof(struct altmdm_spi_xferhdr_s));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: set_txheader_datasize
|
|
*
|
|
* Description:
|
|
* Set transmission data size in the header.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void set_txheader_datasize(FAR struct altmdm_dev_s *priv,
|
|
int total_size, int actual_size)
|
|
{
|
|
FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header;
|
|
|
|
tx_header->header[0] =
|
|
(tx_header->header[0] & 0xf0) + ((total_size >> 10) & 0x0000000f);
|
|
tx_header->header[1] = (total_size >> 2) & 0x000000ff;
|
|
tx_header->header[2] =
|
|
((total_size & 0x00000003) << 6) + ((actual_size >> 8) & 0x0000003f);
|
|
tx_header->header[3] = (actual_size & 0x000000ff);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: set_txheader_possibleofrx
|
|
*
|
|
* Description:
|
|
* Set flag in the header. The flag indicates that master can receive data.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void set_txheader_possibleofrx(FAR struct altmdm_dev_s *priv,
|
|
bool possible)
|
|
{
|
|
FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header;
|
|
|
|
if (!possible)
|
|
{
|
|
tx_header->header[0] = 0x80 + (tx_header->header[0] & 0x7f);
|
|
}
|
|
else
|
|
{
|
|
tx_header->header[0] = 0x00 + (tx_header->header[0] & 0x7f);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: set_txheader_sleepreq
|
|
*
|
|
* Description:
|
|
* Set flag in the header. The flag indicates that sleep request.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void set_txheader_sleepreq(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header;
|
|
|
|
tx_header->header[0] = 0x10 + (tx_header->header[0] & 0xef);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: show_txheader
|
|
*
|
|
* Description:
|
|
* Show header for transmission.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void show_txheader(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
#ifdef MODEM_ALTMDM_DEBUG
|
|
FAR struct altmdm_spi_xferhdr_s *tx_header = &priv->spidev.tx_param.header;
|
|
|
|
m_info("[TXHDR]=%02x,%02x,%02x,%02x\n",
|
|
tx_header->header[0], tx_header->header[1],
|
|
tx_header->header[2], tx_header->header[3]);
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: parse_rxheader
|
|
*
|
|
* Description:
|
|
* Parse header for receiving.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void parse_rxheader(FAR struct altmdm_dev_s *priv,
|
|
FAR int *total_size, FAR int *actual_size,
|
|
FAR int *is_reset, FAR int *is_bufful)
|
|
{
|
|
FAR struct altmdm_spi_xferhdr_s *rx_header = &priv->spidev.rx_param.header;
|
|
|
|
m_info("[RXHDR]%02x,%02x,%02x,%02x\n",
|
|
rx_header->header[0], rx_header->header[1],
|
|
rx_header->header[2], rx_header->header[3]);
|
|
|
|
*total_size = ((rx_header->header[0] & 0x0f) << 10) +
|
|
((rx_header->header[1] & 0xff) << 2) + (rx_header->header[2] >> 6);
|
|
*actual_size = ((rx_header->header[2] & 0x3f) << 8) +
|
|
(rx_header->header[3] & 0xff);
|
|
|
|
priv->spidev.rx_param.status_info = (rx_header->header[0] & 0xf0) >> 4;
|
|
|
|
*is_reset = STAT_INF_IS_RESET(priv->spidev.rx_param.status_info);
|
|
*is_bufful = STAT_INF_IS_BUFF_FULL(priv->spidev.rx_param.status_info);
|
|
|
|
m_info("t=%d a=%d r=%d b=%d\n",
|
|
*total_size, *actual_size, *is_reset, *is_bufful);
|
|
|
|
return;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: verify_rxheader
|
|
*
|
|
* Description:
|
|
* Verify header for receiving.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int verify_rxheader(FAR struct altmdm_dev_s *priv,
|
|
int total_size, int actual_size)
|
|
{
|
|
int calc_total_size;
|
|
|
|
if ((total_size == 0) || (actual_size == 0))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if ((total_size > MAX_PKT_SIZE) || (actual_size > MAX_PKT_SIZE))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (total_size % UNIT_SIZE)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (total_size != actual_size)
|
|
{
|
|
calc_total_size = ((actual_size / UNIT_SIZE) + 1) * UNIT_SIZE;
|
|
|
|
if (total_size != calc_total_size)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_xferheader
|
|
*
|
|
* Description:
|
|
* Execute header transfer.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_xferheader(FAR struct altmdm_dev_s *priv,
|
|
uint32_t is_rxreq, uint32_t is_txreq,
|
|
uint32_t is_sleepreq, uint32_t is_rcvrready)
|
|
{
|
|
int ret;
|
|
int dma_xfer_size;
|
|
struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
bool possibleofrx = true;
|
|
|
|
/* Make transfer header */
|
|
|
|
clear_txheader(priv);
|
|
|
|
if ((is_sleepreq) || (is_txreq))
|
|
{
|
|
if (is_sleepreq)
|
|
{
|
|
set_txheader_sleepreq(priv);
|
|
}
|
|
else
|
|
{
|
|
set_txheader_datasize(priv, spidev->tx_param.total_size,
|
|
spidev->tx_param.actual_size);
|
|
}
|
|
}
|
|
|
|
if (!is_sleepreq)
|
|
{
|
|
alloc_rxbuffer(priv, &spidev->rx_param.rxbuff, MAX_PKT_SIZE);
|
|
if (spidev->rx_param.rxbuff == NULL)
|
|
{
|
|
possibleofrx = false;
|
|
}
|
|
set_txheader_possibleofrx(priv, possibleofrx);
|
|
}
|
|
|
|
show_txheader(priv);
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
if ((!is_rxreq) && (!is_rcvrready))
|
|
{
|
|
ret = wait_receiverready(priv);
|
|
if (ret < 0)
|
|
{
|
|
goto trans_header_error;
|
|
}
|
|
}
|
|
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, sizeof(struct altmdm_spi_xferhdr_s));
|
|
|
|
ret = do_dmaxfer(priv, (void *)&spidev->tx_param.header,
|
|
(void *)&spidev->rx_param.header, dma_xfer_size);
|
|
if (ret < 0)
|
|
{
|
|
goto trans_header_error;
|
|
}
|
|
|
|
return ret;
|
|
|
|
trans_header_error:
|
|
m_err("ERR:%04d Transfer Header Failed. ret = %d.\n", __LINE__, ret);
|
|
|
|
/* Clear Header */
|
|
|
|
clear_rxheader(priv);
|
|
set_txheader_datasize(priv, 0, 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_receivedata
|
|
*
|
|
* Description:
|
|
* Executes the receive only transfer mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_receivedata(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
int dma_xfer_size;
|
|
FAR void *rxbuff;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, spidev->rx_param.total_size);
|
|
|
|
rxbuff = spidev->rx_param.rxbuff->buff_addr;
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, rxbuff, dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("Rcv Data Failed. ret = %d.\n", ret);
|
|
clear_rxheader(priv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_senddata
|
|
*
|
|
* Description:
|
|
* Executes the transmission only transfer mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_senddata(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
int dma_xfer_size;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, spidev->tx_param.total_size);
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr,
|
|
(void *)g_tmp_rxbuff, dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("ERR:%04d Snd Data Failed. ret = %d.\n", __LINE__, ret);
|
|
clear_txheader(priv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_trxdata
|
|
*
|
|
* Description:
|
|
* Executes the transmission and receive transfer mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_trxdata(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
int xfer_size;
|
|
int dma_xfer_size;
|
|
FAR void *rxbuff;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Choose the larger one. */
|
|
|
|
if (spidev->tx_param.total_size < spidev->rx_param.total_size)
|
|
{
|
|
xfer_size = spidev->rx_param.total_size;
|
|
}
|
|
else
|
|
{
|
|
xfer_size = spidev->tx_param.total_size;
|
|
}
|
|
|
|
rxbuff = spidev->rx_param.rxbuff->buff_addr;
|
|
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, xfer_size);
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr, rxbuff,
|
|
dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("ERR:%04d Trx Data Failed. ret = %d.\n", __LINE__, ret);
|
|
clear_txheader(priv);
|
|
clear_rxheader(priv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_receivedata_nobuff
|
|
*
|
|
* Description:
|
|
* Executes the receive only transfer mode. When receiving buffer cannot
|
|
* be prepared.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_receivedata_nobuff(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
int dma_xfer_size;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, spidev->rx_param.total_size);
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, (void *)g_tmp_rxbuff,
|
|
dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("ERR:%04d Rcv Data Nobuff Failed. ret = %d.\n", __LINE__, ret);
|
|
clear_rxheader(priv);
|
|
}
|
|
else
|
|
{
|
|
ret = TRANS_OK_RXDATANOBUFF;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_trxdata_norxbuff
|
|
*
|
|
* Description:
|
|
* Executes the transmission and receive transfer mode. When receiving
|
|
* buffer cannot be prepared.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_trxdata_norxbuff(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
int xfer_size;
|
|
int dma_xfer_size;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Choose the larger one. */
|
|
|
|
if (spidev->tx_param.total_size < spidev->rx_param.total_size)
|
|
{
|
|
xfer_size = spidev->rx_param.total_size;
|
|
}
|
|
else
|
|
{
|
|
xfer_size = spidev->tx_param.total_size;
|
|
}
|
|
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, xfer_size);
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr,
|
|
(void *)g_tmp_rxbuff, dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("ERR:%04d Trx Data Norxbuff Failed. ret = %d.\n", __LINE__, ret);
|
|
clear_txheader(priv);
|
|
clear_rxheader(priv);
|
|
}
|
|
else
|
|
{
|
|
ret = TRANS_OK_TRXDATANORXBUFF;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_receivesleepdata
|
|
*
|
|
* Description:
|
|
* Executes the sleep data transfer mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_receivesleepdata(FAR struct altmdm_dev_s *priv, FAR int *resp)
|
|
{
|
|
int ret;
|
|
int dma_xfer_size;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, UNIT_SIZE);
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, (void *)g_tmp_rxbuff,
|
|
dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("ERR:%04d Rcv Sleep Resp Data Failed. ret = %d.\n",
|
|
__LINE__, ret);
|
|
}
|
|
else
|
|
{
|
|
m_info("[SRESP] 0x%02x,0x%02x,0x%02x,0x%02x\n",
|
|
g_tmp_rxbuff[0], g_tmp_rxbuff[1],
|
|
g_tmp_rxbuff[2], g_tmp_rxbuff[3]);
|
|
|
|
if (!memcmp(g_tmp_rxbuff, "OK", 2))
|
|
{
|
|
*resp = SLEEP_OK;
|
|
}
|
|
else
|
|
{
|
|
*resp = SLEEP_NG;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_receivereset
|
|
*
|
|
* Description:
|
|
* Executes the reset packet receive only transfer mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_receivereset(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
int dma_xfer_size;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, spidev->rx_param.total_size);
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)g_tmp_txbuff, (void *)g_tmp_rxbuff,
|
|
dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("ERR:%04d Rcv Reset Failed. ret = %d.\n", __LINE__, ret);
|
|
clear_rxheader(priv);
|
|
}
|
|
else
|
|
{
|
|
if ((STAT_INF_GET_BOOTSTAT | STAT_INF_RESET) ==
|
|
(spidev->rx_param.
|
|
status_info & (STAT_INF_GET_BOOTSTAT | STAT_INF_RESET)))
|
|
{
|
|
switch (g_tmp_rxbuff[0])
|
|
{
|
|
case RESET_BOOTSTAT_BOOTING:
|
|
altmdm_pm_set_bootstatus(priv,
|
|
MODEM_PM_ERR_RESET_BOOTSTAT_BOOTING);
|
|
break;
|
|
|
|
case RESET_BOOTSTAT_UPDATING:
|
|
altmdm_pm_set_bootstatus(priv,
|
|
MODEM_PM_ERR_RESET_BOOTSTAT_UPDATING);
|
|
break;
|
|
|
|
default:
|
|
m_err
|
|
("ERR:%04d Invalid payload of reset packet. %02x,%02x,%02x,%02x\n",
|
|
__LINE__, g_tmp_rxbuff[0], g_tmp_rxbuff[1], g_tmp_rxbuff[2],
|
|
g_tmp_rxbuff[3]);
|
|
break;
|
|
}
|
|
}
|
|
else if (STAT_INF_RESET ==
|
|
(spidev->rx_param.status_info & STAT_INF_RESET))
|
|
{
|
|
altmdm_pm_set_bootstatus(priv, MODEM_PM_ERR_RESET_BOOTSTAT_DONE);
|
|
}
|
|
else
|
|
{
|
|
m_err("ERR:%04d Unexpected status info. %04x\n", __LINE__,
|
|
spidev->rx_param.status_info);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_trxreset
|
|
*
|
|
* Description:
|
|
* Executes the transmission and receive reset packet transfer mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_trxreset(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
int xfer_size;
|
|
int dma_xfer_size;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
/* Wait for Receiver Ready to receive. */
|
|
|
|
ret = wait_receiverready(priv);
|
|
if (ret >= 0)
|
|
{
|
|
/* Choose the larger one. */
|
|
|
|
if (spidev->tx_param.total_size < spidev->rx_param.total_size)
|
|
{
|
|
xfer_size = spidev->rx_param.total_size;
|
|
}
|
|
else
|
|
{
|
|
xfer_size = spidev->tx_param.total_size;
|
|
}
|
|
|
|
/* Get DMA transfer size */
|
|
|
|
dma_xfer_size = get_dmasize(priv, xfer_size);
|
|
|
|
/* Do DMA transfer */
|
|
|
|
ret = do_dmaxfer(priv, (void *)spidev->tx_param.buff_addr,
|
|
(void *)g_tmp_rxbuff, dma_xfer_size);
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
m_err("ERR:%04d Trx Reset Failed. ret = %d.\n", __LINE__, ret);
|
|
clear_txheader(priv);
|
|
clear_rxheader(priv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: do_xfersleep
|
|
*
|
|
* Description:
|
|
* Executes the sleep request.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int do_xfersleep(FAR struct altmdm_dev_s *priv, uint32_t is_rcvrready)
|
|
{
|
|
int ret;
|
|
int resp;
|
|
int is_reset = 0;
|
|
int total_size;
|
|
int actual_size;
|
|
int is_bufful;
|
|
|
|
/* Transfer header for sleep request */
|
|
|
|
ret = do_xferheader(priv, 0, 0, 1, is_rcvrready);
|
|
if (ret >= 0)
|
|
{
|
|
parse_rxheader(priv, &total_size, &actual_size, &is_reset, &is_bufful);
|
|
|
|
/* Transfer data for sleep request */
|
|
|
|
ret = do_receivesleepdata(priv, &resp);
|
|
if (ret >= 0)
|
|
{
|
|
ret = resp;
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
ret = SLEEP_NG;
|
|
}
|
|
|
|
if (is_reset)
|
|
{
|
|
if (!priv->spidev.is_xferready)
|
|
{
|
|
priv->spidev.is_xferready = true;
|
|
m_info("ready to xfer\n");
|
|
notify_xferready(priv);
|
|
}
|
|
|
|
altmdm_pm_notify_reset(priv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: decide_xfermode
|
|
*
|
|
* Description:
|
|
* Decide transfer mode.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint32_t decide_xfermode(FAR struct altmdm_dev_s *priv,
|
|
uint32_t is_rxreq, uint32_t is_txreq, int ret)
|
|
{
|
|
int retval;
|
|
int is_reset;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
uint32_t mode = MODE_RXINVALID;
|
|
|
|
if (ret < 0)
|
|
{
|
|
if (is_txreq)
|
|
{
|
|
mode = MODE_TRXHEADERFAILTXREQ;
|
|
}
|
|
else
|
|
{
|
|
mode = MODE_TRXHEADERFAILRXREQ;
|
|
}
|
|
|
|
if (spidev->rx_param.rxbuff != NULL)
|
|
{
|
|
free_rxbuffer(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
parse_rxheader(priv, &spidev->rx_param.total_size,
|
|
&spidev->rx_param.actual_size, &is_reset,
|
|
&spidev->tx_param.is_bufful);
|
|
|
|
if (is_rxreq)
|
|
{
|
|
retval = verify_rxheader(priv, spidev->rx_param.total_size,
|
|
spidev->rx_param.actual_size);
|
|
if (retval != 0)
|
|
{
|
|
m_info("RX header:total=0x%02x, actual=0x%02x.\n",
|
|
spidev->rx_param.total_size,
|
|
spidev->rx_param.actual_size);
|
|
|
|
if (spidev->rx_param.rxbuff != NULL)
|
|
{
|
|
free_rxbuffer(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
|
|
if (!is_txreq)
|
|
{
|
|
return mode;
|
|
}
|
|
|
|
is_rxreq = 0;
|
|
|
|
m_info("RX Header invalid. But Send will be done.\n");
|
|
}
|
|
}
|
|
else if ((spidev->rx_param.actual_size != 0) ||
|
|
(spidev->rx_param.total_size != 0))
|
|
{
|
|
retval = verify_rxheader(priv, spidev->rx_param.total_size,
|
|
spidev->rx_param.actual_size);
|
|
if (retval == 0)
|
|
{
|
|
is_rxreq = 1;
|
|
}
|
|
}
|
|
|
|
/* Diceide transfer mode here. */
|
|
|
|
if (is_txreq)
|
|
{
|
|
if (is_rxreq)
|
|
{
|
|
if (is_reset)
|
|
{
|
|
if (spidev->rx_param.rxbuff != NULL)
|
|
{
|
|
free_rxbuffer(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
|
|
mode = MODE_TRXRESET;
|
|
}
|
|
else
|
|
{
|
|
if (spidev->rx_param.rxbuff == NULL)
|
|
{
|
|
mode = MODE_TRXDATANOBUFF;
|
|
}
|
|
else
|
|
{
|
|
mode = MODE_TRXDATA;
|
|
spidev->rx_param.rxbuff->rx_size =
|
|
spidev->rx_param.actual_size;
|
|
m_info("received size = %d.\n",
|
|
spidev->rx_param.rxbuff->rx_size);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (spidev->rx_param.rxbuff != NULL)
|
|
{
|
|
free_rxbuffer(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
|
|
mode = MODE_TXDATA;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (is_reset)
|
|
{
|
|
if (spidev->rx_param.rxbuff != NULL)
|
|
{
|
|
free_rxbuffer(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
|
|
mode = MODE_RXRESET;
|
|
}
|
|
else
|
|
{
|
|
if (spidev->rx_param.rxbuff == NULL)
|
|
{
|
|
mode = MODE_RXDATANOBUFF;
|
|
}
|
|
else
|
|
{
|
|
mode = MODE_RXDATA;
|
|
spidev->rx_param.rxbuff->rx_size =
|
|
spidev->rx_param.actual_size;
|
|
m_info("received size = %d.\n",
|
|
spidev->rx_param.rxbuff->rx_size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
clear_rxheader(priv);
|
|
clear_txheader(priv);
|
|
|
|
return mode;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: done_xfer
|
|
*
|
|
* Description:
|
|
* Notify that transfer has completed.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void done_xfer(FAR struct altmdm_dev_s *priv, uint32_t xfer_mode,
|
|
int ret)
|
|
{
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
switch (xfer_mode)
|
|
{
|
|
case MODE_RXDATA:
|
|
if (ret < 0)
|
|
{
|
|
free_rxbuffer(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
else
|
|
{
|
|
put_rxbufffifo(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
break;
|
|
|
|
case MODE_TXDATA:
|
|
if (spidev->tx_param.is_bufful)
|
|
{
|
|
spidev->tx_param.is_bufful = 0;
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL;
|
|
}
|
|
else
|
|
{
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK;
|
|
}
|
|
|
|
altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE);
|
|
break;
|
|
|
|
case MODE_TRXDATA:
|
|
if (spidev->tx_param.is_bufful)
|
|
{
|
|
spidev->tx_param.is_bufful = 0;
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL;
|
|
}
|
|
else
|
|
{
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK;
|
|
}
|
|
|
|
altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE);
|
|
|
|
if (ret < 0)
|
|
{
|
|
free_rxbuffer(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
else
|
|
{
|
|
put_rxbufffifo(priv, spidev->rx_param.rxbuff);
|
|
spidev->rx_param.rxbuff = NULL;
|
|
}
|
|
break;
|
|
|
|
case MODE_TRXDATANOBUFF:
|
|
if (spidev->tx_param.is_bufful)
|
|
{
|
|
spidev->tx_param.is_bufful = 0;
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL;
|
|
}
|
|
else
|
|
{
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK;
|
|
}
|
|
|
|
altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE);
|
|
break;
|
|
|
|
case MODE_TRXHEADERFAILTXREQ:
|
|
spidev->tx_param.result = ret;
|
|
altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE);
|
|
break;
|
|
|
|
case MODE_RXRESET:
|
|
if (!spidev->is_xferready)
|
|
{
|
|
spidev->is_xferready = true;
|
|
m_info("ready to xfer\n");
|
|
notify_xferready(priv);
|
|
}
|
|
|
|
altmdm_pm_notify_reset(priv);
|
|
break;
|
|
|
|
case MODE_TRXRESET:
|
|
if (!spidev->is_xferready)
|
|
{
|
|
spidev->is_xferready = true;
|
|
m_info("ready to xfer\n");
|
|
notify_xferready(priv);
|
|
}
|
|
|
|
altmdm_pm_notify_reset(priv);
|
|
if (spidev->tx_param.is_bufful)
|
|
{
|
|
spidev->tx_param.is_bufful = 0;
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK_RCVBUFFUL;
|
|
}
|
|
else
|
|
{
|
|
spidev->tx_param.result = (ret < 0) ? ret : TRANS_OK;
|
|
}
|
|
|
|
altmdm_sys_setflag(&spidev->tx_param.done_flag, EVENT_TX_DONE);
|
|
break;
|
|
|
|
case MODE_TRXHEADERFAILRXREQ:
|
|
case MODE_RXDATANOBUFF:
|
|
case MODE_RXINVALID:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: done_sleep
|
|
*
|
|
* Description:
|
|
* Notify that sleep request has completed.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void done_sleep(FAR struct altmdm_dev_s *priv, int ret)
|
|
{
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
spidev->sleep_param.result = ret;
|
|
altmdm_sys_setflag(&spidev->sleep_param.done_flag, EVENT_SLEEP_DONE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: xfer_task_init
|
|
*
|
|
* Description:
|
|
* Initialize SPI transfer task.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void xfer_task_init(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
sigset_t mask;
|
|
|
|
sigfillset(&mask);
|
|
sigprocmask(SIG_SETMASK, &mask, NULL);
|
|
|
|
init_svtimer(priv);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: xfer_task
|
|
*
|
|
* Description:
|
|
* ALTMDM SPI transfer task.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int xfer_task(int argc, char *argv[])
|
|
{
|
|
int ret;
|
|
int sleep_result;
|
|
int res_code;
|
|
uint32_t is_txreq;
|
|
uint32_t is_rxreq;
|
|
uint32_t is_sleepreq;
|
|
uint32_t is_timerexp;
|
|
uint32_t do_sleep;
|
|
uint32_t ptn;
|
|
uint32_t xfer_mode;
|
|
uint32_t modem_state;
|
|
uint32_t is_rcvrready = 0;
|
|
FAR struct altmdm_dev_s *priv = g_privdata;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
xfer_task_init(priv);
|
|
|
|
while (!spidev->is_not_run)
|
|
{
|
|
ret = altmdm_sys_waitflag(&spidev->xfer_flag, EVENT_TRANS_WAIT,
|
|
ALTMDM_SYS_FLAG_WMODEOR, &ptn,
|
|
ALTMDM_SYS_FLAG_TMOFEVR);
|
|
if (ret != 0)
|
|
{
|
|
m_err("wait flag failed:%d.\n", ret);
|
|
continue;
|
|
}
|
|
|
|
m_info("ptn:%x.\n", ptn);
|
|
|
|
if (ptn & EVENT_REQMASK)
|
|
{
|
|
is_txreq = ptn & EVENT_TXREQ;
|
|
is_rxreq = ptn & EVENT_RXREQ;
|
|
is_sleepreq = ptn & EVENT_SLEEPREQ;
|
|
is_timerexp = ptn & EVENT_SV_TIMER_EXP;
|
|
do_sleep = 0;
|
|
sleep_result = SLEEP_NG;
|
|
|
|
/* Sleep transition event received. Check if it can sleep. */
|
|
|
|
if (is_sleepreq || is_timerexp)
|
|
{
|
|
/* If data transfer required at the same time, cannot sleep. */
|
|
|
|
if (!(is_txreq || is_rxreq))
|
|
{
|
|
if (altmdm_pm_cansleep(priv))
|
|
{
|
|
do_sleep = 1;
|
|
}
|
|
else if (is_timerexp)
|
|
{
|
|
/* Case where modem spontaneously enters sleep state and
|
|
* timer is not stopped.
|
|
*/
|
|
|
|
modem_state = altmdm_pm_getinternalstate();
|
|
if (modem_state == MODEM_PM_INTERNAL_STATE_SLEEP)
|
|
{
|
|
stop_svtimer(priv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (do_sleep)
|
|
{
|
|
stop_svtimer(priv);
|
|
|
|
/* Transfer sleep packet */
|
|
|
|
sleep_result = do_xfersleep(priv, 0);
|
|
if (sleep_result == SLEEP_OK)
|
|
{
|
|
altmdm_pm_sleepmodem(priv);
|
|
}
|
|
}
|
|
|
|
if (is_sleepreq)
|
|
{
|
|
/* Send sleep response */
|
|
|
|
done_sleep(priv, sleep_result);
|
|
}
|
|
|
|
/* Receive data transfer request */
|
|
|
|
if (is_txreq || is_rxreq)
|
|
{
|
|
stop_svtimer(priv);
|
|
|
|
if (is_txreq)
|
|
{
|
|
/* Wakeup modem before data transfer */
|
|
|
|
res_code = altmdm_pm_wakeup(priv);
|
|
if (res_code == MODEM_PM_WAKEUP_FAIL)
|
|
{
|
|
done_xfer(priv, MODE_TXDATA, TRANS_WAITRCVRTMO);
|
|
start_svtimer(priv);
|
|
continue;
|
|
}
|
|
#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1
|
|
else if (res_code == MODEM_PM_WAKEUP_DONE)
|
|
{
|
|
is_rcvrready = 1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* transfer header */
|
|
|
|
ret = do_xferheader(priv, is_rxreq, is_txreq, 0, is_rcvrready);
|
|
|
|
#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1
|
|
if (is_rcvrready)
|
|
{
|
|
is_rcvrready = 0;
|
|
}
|
|
#endif
|
|
xfer_mode = decide_xfermode(priv, is_rxreq, is_txreq, ret);
|
|
|
|
switch (xfer_mode)
|
|
{
|
|
case MODE_RXDATA:
|
|
ret = do_receivedata(priv);
|
|
break;
|
|
|
|
case MODE_TXDATA:
|
|
ret = do_senddata(priv);
|
|
break;
|
|
|
|
case MODE_TRXDATA:
|
|
ret = do_trxdata(priv);
|
|
break;
|
|
|
|
case MODE_RXDATANOBUFF:
|
|
ret = do_receivedata_nobuff(priv);
|
|
break;
|
|
|
|
case MODE_TRXDATANOBUFF:
|
|
ret = do_trxdata_norxbuff(priv);
|
|
break;
|
|
|
|
case MODE_RXRESET:
|
|
ret = do_receivereset(priv);
|
|
break;
|
|
|
|
case MODE_TRXRESET:
|
|
ret = do_trxreset(priv);
|
|
break;
|
|
|
|
case MODE_RXINVALID:
|
|
ret = TRANS_RXINVALID;
|
|
break;
|
|
|
|
case MODE_TRXHEADERFAILTXREQ:
|
|
case MODE_TRXHEADERFAILRXREQ:
|
|
break;
|
|
|
|
default:
|
|
m_err("ERR:%04d Unknown decision of transfer: %d.\n",
|
|
__LINE__, xfer_mode);
|
|
break;
|
|
}
|
|
|
|
m_info("m=%d\n", xfer_mode);
|
|
done_xfer(priv, xfer_mode, ret);
|
|
start_svtimer(priv);
|
|
}
|
|
}
|
|
|
|
if (ptn & EVENT_EXIT)
|
|
{
|
|
spidev->is_not_run = true;
|
|
}
|
|
}
|
|
|
|
delete_svtimer(priv);
|
|
task_delete(0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_gpioreadyisr
|
|
*
|
|
* Description:
|
|
* Interrupt handler for SLAVE_REQUEST GPIO line.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_gpioreadyisr(int irq, FAR void *context, FAR void *arg)
|
|
{
|
|
uint32_t modem_state;
|
|
FAR struct altmdm_dev_s *priv = g_privdata;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1
|
|
modem_state = altmdm_pm_getinternalstate();
|
|
if ((modem_state == MODEM_PM_INTERNAL_STATE_GOING_TO_SLEEP) ||
|
|
(modem_state == MODEM_PM_INTERNAL_STATE_GOING_TO_WAKE) ||
|
|
(modem_state == MODEM_PM_INTERNAL_STATE_SLEEP))
|
|
{
|
|
altmdm_pm_callgpiohandler(priv);
|
|
}
|
|
else
|
|
{
|
|
altmdm_sys_setflag(&spidev->xfer_flag, EVENT_RXREQ);
|
|
}
|
|
#else
|
|
altmdm_sys_setflag(&spidev->xfer_flag, EVENT_RXREQ);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_init
|
|
*
|
|
* Description:
|
|
* Initialize ALTMDM driver.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_init(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret = 0;
|
|
|
|
g_privdata = priv;
|
|
|
|
/* Initalize modem power management driver */
|
|
|
|
altmdm_pm_init(priv);
|
|
|
|
memset(&priv->spidev, 0, sizeof(struct altmdm_spi_dev_s));
|
|
memset(g_tmp_txbuff, 0, sizeof(g_tmp_txbuff));
|
|
priv->spidev.is_not_run = false;
|
|
priv->spidev.is_xferready = false;
|
|
|
|
altmdm_sys_initlock(&priv->spidev.tx_param.lock);
|
|
altmdm_sys_initlock(&priv->spidev.rx_param.lock);
|
|
altmdm_sys_initlock(&priv->spidev.sleep_param.lock);
|
|
|
|
altmdm_sys_initflag(&priv->spidev.xfer_flag);
|
|
altmdm_sys_initflag(&priv->spidev.xferready_flag);
|
|
altmdm_sys_initflag(&priv->spidev.tx_param.done_flag);
|
|
altmdm_sys_initflag(&priv->spidev.sleep_param.done_flag);
|
|
|
|
create_rxbufffifo(priv);
|
|
|
|
/* SPI settings */
|
|
|
|
SPI_LOCK(priv->spi, true);
|
|
SPI_SETMODE(priv->spi, SPIDEV_MODE0);
|
|
SPI_SETBITS(priv->spi, 8);
|
|
SPI_SETFREQUENCY(priv->spi, SPI_MAXFREQUENCY);
|
|
SPI_LOCK(priv->spi, false);
|
|
|
|
priv->spidev.task_id = task_create(XFER_TASK_NAME, XFER_TASK_PRI,
|
|
XFER_TASK_STKSIZE, xfer_task, NULL);
|
|
if (priv->spidev.task_id == ERROR)
|
|
{
|
|
m_err("Failed to create xfer task\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_uninit
|
|
*
|
|
* Description:
|
|
* Uninitialize ALTMDM driver.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_uninit(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
altmdm_sys_setflag(&priv->spidev.xfer_flag, EVENT_EXIT);
|
|
|
|
/* check transfer task is deleted or not */
|
|
|
|
while (1)
|
|
{
|
|
if (priv->spidev.is_not_run)
|
|
{
|
|
break;
|
|
}
|
|
|
|
nxsig_usleep(10);
|
|
}
|
|
|
|
altmdm_sys_deletelock(&priv->spidev.tx_param.lock);
|
|
altmdm_sys_deletelock(&priv->spidev.rx_param.lock);
|
|
altmdm_sys_deletelock(&priv->spidev.sleep_param.lock);
|
|
|
|
altmdm_sys_deleteflag(&priv->spidev.xfer_flag);
|
|
altmdm_sys_deleteflag(&priv->spidev.tx_param.done_flag);
|
|
altmdm_sys_deleteflag(&priv->spidev.sleep_param.done_flag);
|
|
|
|
if (priv->spidev.rx_param.rxbuff != NULL)
|
|
{
|
|
free_rxbuffer(priv, priv->spidev.rx_param.rxbuff);
|
|
priv->spidev.rx_param.rxbuff = NULL;
|
|
}
|
|
|
|
destroy_rxbufffifo(priv);
|
|
|
|
/* Uninitalize modem power management driver */
|
|
|
|
altmdm_pm_uninit(priv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_enable
|
|
*
|
|
* Description:
|
|
* Enable ALTMDM SPI driver.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_enable(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_disable
|
|
*
|
|
* Description:
|
|
* Disable ALTMDM SPI driver.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_disable(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
spidev->is_xferready = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_read
|
|
*
|
|
* Description:
|
|
* ALTMDM SPI driver read method.
|
|
*
|
|
****************************************************************************/
|
|
|
|
ssize_t altmdm_spi_read(FAR struct altmdm_dev_s * priv,
|
|
FAR const char *buffer, size_t readlen)
|
|
{
|
|
FAR struct altmdm_spi_dev_s *spidev;
|
|
FAR struct altmdm_spi_rxbuff_s *rbuff;
|
|
ssize_t rsize = readlen;
|
|
|
|
/* Check argument */
|
|
|
|
if ((priv == NULL) || (buffer == NULL))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!readlen || readlen > MAX_PKT_SIZE)
|
|
{
|
|
m_err("Invalid read length:%d.\n", readlen);
|
|
return -EINVAL;
|
|
}
|
|
|
|
spidev = &priv->spidev;
|
|
|
|
altmdm_sys_lock(&spidev->rx_param.lock);
|
|
|
|
get_rxbufffifo(priv, &rbuff);
|
|
if (spidev->rx_param.rxabort)
|
|
{
|
|
spidev->rx_param.rxabort = false;
|
|
if (rbuff != NULL)
|
|
{
|
|
m_info("rx buffer discard because of abort.%d\n", __LINE__);
|
|
free_rxbuffer(priv, rbuff);
|
|
}
|
|
rsize = -ECONNABORTED;
|
|
}
|
|
else
|
|
{
|
|
if (rbuff == NULL)
|
|
{
|
|
m_err("get rx buffer failed.\n");
|
|
rsize = -EIO;
|
|
}
|
|
else if (rbuff->rx_size > readlen)
|
|
{
|
|
m_info("get rx buffer.%d\n", __LINE__);
|
|
rsize = readlen;
|
|
memcpy((void *)buffer, rbuff->buff_addr, rsize);
|
|
free_rxbuffer(priv, rbuff);
|
|
}
|
|
else
|
|
{
|
|
m_info("get rx buffer.%d\n", __LINE__);
|
|
rsize = rbuff->rx_size;
|
|
memcpy((void *)buffer, rbuff->buff_addr, rsize);
|
|
free_rxbuffer(priv, rbuff);
|
|
}
|
|
}
|
|
|
|
altmdm_sys_unlock(&spidev->rx_param.lock);
|
|
|
|
return rsize;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_write
|
|
*
|
|
* Description:
|
|
* ALTMDM SPI driver write method.
|
|
*
|
|
****************************************************************************/
|
|
|
|
ssize_t altmdm_spi_write(FAR struct altmdm_dev_s * priv,
|
|
FAR const char *buffer, size_t witelen)
|
|
{
|
|
int ret;
|
|
int remainder;
|
|
uint32_t ptn;
|
|
FAR struct altmdm_spi_dev_s *spidev;
|
|
ssize_t wsize = witelen;
|
|
|
|
/* Check argument */
|
|
|
|
if ((priv == NULL) || (buffer == NULL))
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!witelen || witelen > MAX_PKT_SIZE)
|
|
{
|
|
m_err("Invalid write length:%d.\n", witelen);
|
|
return -EINVAL;
|
|
}
|
|
|
|
spidev = &priv->spidev;
|
|
|
|
if (!spidev->is_xferready)
|
|
{
|
|
wait_xferready(priv);
|
|
}
|
|
|
|
altmdm_sys_lock(&spidev->tx_param.lock);
|
|
|
|
again:
|
|
spidev->tx_param.buff_addr = (void *)buffer;
|
|
spidev->tx_param.actual_size = witelen;
|
|
|
|
remainder = witelen % UNIT_SIZE;
|
|
if (remainder == 0)
|
|
{
|
|
spidev->tx_param.total_size = spidev->tx_param.actual_size;
|
|
}
|
|
else
|
|
{
|
|
spidev->tx_param.total_size =
|
|
((spidev->tx_param.actual_size / UNIT_SIZE) + 1) * UNIT_SIZE;
|
|
}
|
|
|
|
spidev->tx_param.result = 0;
|
|
|
|
altmdm_sys_setflag(&spidev->xfer_flag, EVENT_TXREQ);
|
|
|
|
ret = altmdm_sys_waitflag(&spidev->tx_param.done_flag,
|
|
EVENT_TX_DONE,
|
|
ALTMDM_SYS_FLAG_WMODEOR,
|
|
&ptn,
|
|
WRITE_WAIT_TIMEOUT);
|
|
if (ret != OK)
|
|
{
|
|
m_err("wait failed:%d\n", ret);
|
|
wsize = -ETIME;
|
|
}
|
|
else
|
|
{
|
|
switch (spidev->tx_param.result)
|
|
{
|
|
case TRANS_OK:
|
|
case TRANS_OK_TRXDATANORXBUFF:
|
|
wsize = witelen;
|
|
break;
|
|
|
|
case TRANS_RXINVALID:
|
|
case TRANS_WAITRCVRTMO:
|
|
wsize = -EIO;
|
|
break;
|
|
|
|
case TRANS_OK_RCVBUFFUL:
|
|
nxsig_usleep(100);
|
|
goto again;
|
|
break;
|
|
|
|
default:
|
|
m_err("Unexpected situation. tx result = %d.\n",
|
|
spidev->tx_param.result);
|
|
wsize = -EIO;
|
|
break;
|
|
}
|
|
m_info("%s: tx result: %d.\n", __func__, spidev->tx_param.result);
|
|
m_info("%s: write size: %d.\n", __func__, wsize);
|
|
}
|
|
|
|
altmdm_sys_unlock(&spidev->tx_param.lock);
|
|
|
|
return wsize;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: spicom_read_abort
|
|
*
|
|
* Description:
|
|
* Abort the read process.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_readabort(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
/* Check argument */
|
|
|
|
if (priv == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
abort_get_rxbufffifo(priv);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_sleepmodem
|
|
*
|
|
* Description:
|
|
* Make ALTMDM sleep.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_sleepmodem(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
int ret;
|
|
bool sleep_requested;
|
|
uint32_t ptn;
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
altmdm_sys_lock(&spidev->sleep_param.lock);
|
|
sleep_requested = spidev->sleep_param.requested;
|
|
if (!sleep_requested)
|
|
{
|
|
spidev->sleep_param.requested = true;
|
|
}
|
|
|
|
altmdm_sys_unlock(&spidev->sleep_param.lock);
|
|
|
|
if (sleep_requested)
|
|
{
|
|
ret = -EBUSY;
|
|
}
|
|
else
|
|
{
|
|
spidev->sleep_param.result = 0;
|
|
|
|
altmdm_sys_setflag(&spidev->xfer_flag, EVENT_SLEEPREQ);
|
|
|
|
ret = altmdm_sys_waitflag(&spidev->sleep_param.done_flag,
|
|
EVENT_SLEEP_DONE, ALTMDM_SYS_FLAG_WMODEOR,
|
|
&ptn, SREQ_WAIT_TIMEOUT);
|
|
if (ret != OK)
|
|
{
|
|
m_err("wait failed:%d\n", ret);
|
|
}
|
|
else
|
|
{
|
|
ret = spidev->sleep_param.result;
|
|
m_info("%s: sleep result: %d.\n", __func__,
|
|
spidev->sleep_param.result);
|
|
}
|
|
|
|
spidev->sleep_param.requested = false;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_MODEM_ALTMDM_PROTCOL_V2_1
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_setreceiverready
|
|
*
|
|
* Description:
|
|
* Set receiver ready notification.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_setreceiverready(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
altmdm_sys_setflag(&spidev->xfer_flag, EVENT_RXREQ);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_isreceiverready
|
|
*
|
|
* Description:
|
|
* Check already notified or not by altmdm_spi_setreceiverready.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_isreceiverready(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
struct altmdm_sys_flagstate_s flag_status;
|
|
|
|
altmdm_sys_referflag(&spidev->xfer_flag, &flag_status);
|
|
if (flag_status.flag_pattern & EVENT_RXREQ)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: altmdm_spi_clearreceiverready
|
|
*
|
|
* Description:
|
|
* Clear receiver ready notification.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int altmdm_spi_clearreceiverready(FAR struct altmdm_dev_s *priv)
|
|
{
|
|
FAR struct altmdm_spi_dev_s *spidev = &priv->spidev;
|
|
|
|
altmdm_sys_clearflag(&spidev->xfer_flag, EVENT_RXREQ);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#endif /* CONFIG_MODEM_ALTMDM */
|