rpmsg_port_spi: add spi slave support
The rpmsg port spi slave version support Signed-off-by: liaoao <liaoao@xiaomi.com>
This commit is contained in:
parent
89ce5d5e02
commit
4827063958
@ -37,6 +37,10 @@ if(CONFIG_RPMSG)
|
||||
list(APPEND SRCS rpmsg_port_spi.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_RPMSG_PORT_SPI_SLAVE)
|
||||
list(APPEND SRCS rpmsg_port_spi_slave.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_RPMSG_VIRTIO)
|
||||
list(APPEND SRCS rpmsg_virtio.c)
|
||||
endif()
|
||||
|
@ -44,7 +44,14 @@ config RPMSG_PORT_SPI
|
||||
---help---
|
||||
Rpmsg SPI Port driver used for cross chip communication.
|
||||
|
||||
if RPMSG_PORT_SPI
|
||||
config RPMSG_PORT_SPI_SLAVE
|
||||
bool "Rpmsg SPI Slave Port Driver Support"
|
||||
default n
|
||||
select RPMSG_PORT
|
||||
---help---
|
||||
Rpmsg SPI Slave Port driver used for cross chip communication.
|
||||
|
||||
if RPMSG_PORT_SPI || RPMSG_PORT_SPI_SLAVE
|
||||
|
||||
config RPMSG_PORT_SPI_THREAD_PRIORITY
|
||||
int "Rpmsg SPI Port Thread Priority"
|
||||
|
@ -41,6 +41,10 @@ ifeq ($(CONFIG_RPMSG_PORT_SPI),y)
|
||||
CSRCS += rpmsg_port_spi.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RPMSG_PORT_SPI_SLAVE),y)
|
||||
CSRCS += rpmsg_port_spi_slave.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RPMSG_VIRTIO),y)
|
||||
CSRCS += rpmsg_virtio.c
|
||||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)openamp$(DELIM)open-amp$(DELIM)lib
|
||||
|
606
drivers/rpmsg/rpmsg_port_spi_slave.c
Normal file
606
drivers/rpmsg/rpmsg_port_spi_slave.c
Normal file
@ -0,0 +1,606 @@
|
||||
/****************************************************************************
|
||||
* drivers/rpmsg/rpmsg_port_spi_slave.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <nuttx/crc16.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/kthread.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/mutex.h>
|
||||
|
||||
#include "rpmsg_port.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_RPMSG_PORT_SPI_CRC
|
||||
# define rpmsg_port_spi_crc16(hdr) crc16((FAR uint8_t *)&(hdr)->cmd, \
|
||||
(hdr)->len - sizeof((hdr)->crc))
|
||||
#else
|
||||
# define rpmsg_port_spi_crc16(hdr) 0
|
||||
#endif
|
||||
|
||||
#define RPMSG_SPI_PORT_UNCONNECTED UINT16_MAX
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
enum rpmsg_port_spi_cmd_e
|
||||
{
|
||||
RPMSG_PORT_SPI_CMD_CONNECT = 0x01,
|
||||
RPMSG_PORT_SPI_CMD_AVAIL,
|
||||
RPMSG_PORT_SPI_CMD_DATA,
|
||||
};
|
||||
|
||||
struct rpmsg_port_spi_s
|
||||
{
|
||||
struct rpmsg_port_s port;
|
||||
FAR struct spi_slave_ctrlr_s *spictrlr;
|
||||
struct spi_slave_dev_s spislv;
|
||||
FAR struct ioexpander_dev_s *ioe;
|
||||
|
||||
/* GPIOs used for handshake */
|
||||
|
||||
uint8_t mreq;
|
||||
uint8_t sreq;
|
||||
|
||||
/* Reserved for cmd send */
|
||||
|
||||
FAR struct rpmsg_port_header_s *cmdhdr;
|
||||
|
||||
/* Used for sync data state between sreq_handler and complete_handler */
|
||||
|
||||
FAR struct rpmsg_port_header_s *txhdr;
|
||||
FAR struct rpmsg_port_header_s *rxhdr;
|
||||
|
||||
rpmsg_port_rx_cb_t rxcb;
|
||||
|
||||
/* Used for flow control */
|
||||
|
||||
uint16_t txavail;
|
||||
uint16_t rxavail;
|
||||
uint16_t rxthres;
|
||||
|
||||
atomic_int transferring;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_notify_tx_ready(FAR struct rpmsg_port_s *port);
|
||||
static void rpmsg_port_spi_notify_rx_free(FAR struct rpmsg_port_s *port);
|
||||
static void rpmsg_port_spi_register_cb(FAR struct rpmsg_port_s *port,
|
||||
rpmsg_port_rx_cb_t callback);
|
||||
static void rpmsg_port_spi_slave_select(FAR struct spi_slave_dev_s *dev,
|
||||
bool selected);
|
||||
static void rpmsg_port_spi_slave_cmddata(FAR struct spi_slave_dev_s *dev,
|
||||
bool data);
|
||||
static size_t rpmsg_port_spi_slave_getdata(FAR struct spi_slave_dev_s *dev,
|
||||
FAR const void **data);
|
||||
static size_t rpmsg_port_spi_slave_receive(FAR struct spi_slave_dev_s *dev,
|
||||
FAR const void *data,
|
||||
size_t nwords);
|
||||
static void rpmsg_port_spi_slave_notify(FAR struct spi_slave_dev_s *dev,
|
||||
spi_slave_state_t state);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct rpmsg_port_ops_s g_rpmsg_port_spi_ops =
|
||||
{
|
||||
rpmsg_port_spi_notify_tx_ready,
|
||||
rpmsg_port_spi_notify_rx_free,
|
||||
rpmsg_port_spi_register_cb,
|
||||
};
|
||||
|
||||
static const struct spi_slave_devops_s g_rpmsg_port_spi_slave_ops =
|
||||
{
|
||||
rpmsg_port_spi_slave_select, /* select */
|
||||
rpmsg_port_spi_slave_cmddata, /* cmddata */
|
||||
rpmsg_port_spi_slave_getdata, /* getdata */
|
||||
rpmsg_port_spi_slave_receive, /* receive */
|
||||
rpmsg_port_spi_slave_notify, /* notify */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_exchange
|
||||
****************************************************************************/
|
||||
|
||||
void rpmsg_port_spi_exchange(FAR struct rpmsg_port_spi_s *rpspi)
|
||||
{
|
||||
FAR struct rpmsg_port_header_s *txhdr;
|
||||
|
||||
if (atomic_fetch_add(&rpspi->transferring, 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpspi->txavail == RPMSG_SPI_PORT_UNCONNECTED)
|
||||
{
|
||||
txhdr = rpspi->cmdhdr;
|
||||
txhdr->cmd = RPMSG_PORT_SPI_CMD_CONNECT;
|
||||
strlcpy((FAR char *)(txhdr + 1), rpspi->port.cpuname, RPMSG_NAME_SIZE);
|
||||
}
|
||||
else if (rpspi->txavail > 0 &&
|
||||
rpmsg_port_queue_nused(&rpspi->port.txq) > 0)
|
||||
{
|
||||
txhdr = rpmsg_port_queue_get_buffer(&rpspi->port.txq, false);
|
||||
DEBUGASSERT(txhdr != NULL);
|
||||
|
||||
txhdr->cmd = RPMSG_PORT_SPI_CMD_DATA;
|
||||
rpspi->txhdr = txhdr;
|
||||
}
|
||||
else
|
||||
{
|
||||
txhdr = rpspi->cmdhdr;
|
||||
txhdr->cmd = RPMSG_PORT_SPI_CMD_AVAIL;
|
||||
}
|
||||
|
||||
txhdr->avail = rpmsg_port_queue_navail(&rpspi->port.rxq);
|
||||
txhdr->avail = txhdr->avail > 1 ? txhdr->avail - 1 : 0;
|
||||
txhdr->crc = rpmsg_port_spi_crc16(txhdr);
|
||||
|
||||
rpmsginfo("send cmd:%u avail:%u\n", txhdr->cmd, txhdr->avail);
|
||||
|
||||
SPIS_CTRLR_ENQUEUE(rpspi->spictrlr, txhdr, rpspi->cmdhdr->len);
|
||||
IOEXP_WRITEPIN(rpspi->ioe, rpspi->sreq, 1);
|
||||
|
||||
rpspi->rxavail = txhdr->avail;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_notify_tx_ready
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_notify_tx_ready(FAR struct rpmsg_port_s *port)
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi =
|
||||
container_of(port, struct rpmsg_port_spi_s, port);
|
||||
|
||||
rpmsg_port_spi_exchange(rpspi);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_notify_rx_free
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_notify_rx_free(FAR struct rpmsg_port_s *port)
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi =
|
||||
container_of(port, struct rpmsg_port_spi_s, port);
|
||||
|
||||
if (rpmsg_port_queue_navail(&port->rxq) - rpspi->rxavail >= rpspi->rxthres)
|
||||
{
|
||||
rpmsg_port_spi_exchange(rpspi);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_register_cb
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_register_cb(FAR struct rpmsg_port_s *port,
|
||||
rpmsg_port_rx_cb_t callback)
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi =
|
||||
container_of(port, struct rpmsg_port_spi_s, port);
|
||||
|
||||
rpspi->rxcb = callback;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_slave_select
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_slave_select(FAR struct spi_slave_dev_s *dev,
|
||||
bool selected)
|
||||
{
|
||||
rpmsginfo("sdev: %p CS: %s\n", dev, selected ? "select" : "free");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_slave_cmddata
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_slave_cmddata(FAR struct spi_slave_dev_s *dev,
|
||||
bool data)
|
||||
{
|
||||
rpmsginfo("sdev: %p CMD: %s\n", dev, data ? "data" : "command");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_slave_getdata
|
||||
****************************************************************************/
|
||||
|
||||
static size_t rpmsg_port_spi_slave_getdata(FAR struct spi_slave_dev_s *dev,
|
||||
FAR const void **data)
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi =
|
||||
container_of(dev, struct rpmsg_port_spi_s, spislv);
|
||||
|
||||
*data = rpspi->rxhdr;
|
||||
return rpspi->cmdhdr->len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_slave_receive
|
||||
****************************************************************************/
|
||||
|
||||
static size_t rpmsg_port_spi_slave_receive(FAR struct spi_slave_dev_s *dev,
|
||||
FAR const void *data,
|
||||
size_t nwords)
|
||||
{
|
||||
return nwords;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_slave_notify
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_slave_notify(FAR struct spi_slave_dev_s *dev,
|
||||
spi_slave_state_t state)
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi =
|
||||
container_of(dev, struct rpmsg_port_spi_s, spislv);
|
||||
uint16_t avail;
|
||||
|
||||
IOEXP_WRITEPIN(rpspi->ioe, rpspi->sreq, 0);
|
||||
SPIS_CTRLR_QPOLL(rpspi->spictrlr);
|
||||
|
||||
avail = rpspi->rxhdr->avail;
|
||||
rpmsginfo("received cmd:%u avail:%u\n", rpspi->rxhdr->cmd, avail);
|
||||
|
||||
if (rpspi->txhdr != NULL)
|
||||
{
|
||||
rpmsg_port_queue_return_buffer(&rpspi->port.txq, rpspi->txhdr);
|
||||
rpspi->txhdr = NULL;
|
||||
}
|
||||
|
||||
if (rpspi->rxhdr->crc != 0)
|
||||
{
|
||||
uint16_t crc = rpmsg_port_spi_crc16(rpspi->rxhdr);
|
||||
|
||||
if (crc != 0 && rpspi->rxhdr->crc != crc)
|
||||
{
|
||||
rpmsgerr("crc check fail received: %u calculated: %u\n",
|
||||
rpspi->rxhdr->crc, crc);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip any data received when connection is not established until a
|
||||
* connect req data packet has been received.
|
||||
*/
|
||||
|
||||
if (rpspi->txavail == RPMSG_SPI_PORT_UNCONNECTED &&
|
||||
rpspi->rxhdr->cmd != RPMSG_PORT_SPI_CMD_CONNECT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpspi->rxhdr->cmd != RPMSG_PORT_SPI_CMD_AVAIL)
|
||||
{
|
||||
rpmsg_port_queue_add_buffer(&rpspi->port.rxq, rpspi->rxhdr);
|
||||
rpspi->rxhdr = rpmsg_port_queue_get_available_buffer(
|
||||
&rpspi->port.rxq, false);
|
||||
DEBUGASSERT(rpspi->rxhdr != NULL);
|
||||
}
|
||||
|
||||
/* Do nothing when two sides are not connected. */
|
||||
|
||||
if (rpspi->txavail == RPMSG_SPI_PORT_UNCONNECTED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rpspi->txavail = avail;
|
||||
|
||||
out:
|
||||
if (atomic_exchange(&rpspi->transferring, 0) > 1 ||
|
||||
(rpspi->txavail > 0 && rpmsg_port_queue_nused(&rpspi->port.txq) > 0))
|
||||
{
|
||||
rpmsg_port_spi_exchange(rpspi);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_process_packet
|
||||
****************************************************************************/
|
||||
|
||||
static void
|
||||
rpmsg_port_spi_process_packet(FAR struct rpmsg_port_spi_s *rpspi,
|
||||
FAR struct rpmsg_port_header_s *rxhdr)
|
||||
{
|
||||
rpmsginfo("received cmd: %u avail: %u", rxhdr->cmd, rxhdr->avail);
|
||||
|
||||
switch (rxhdr->cmd)
|
||||
{
|
||||
case RPMSG_PORT_SPI_CMD_CONNECT:
|
||||
if (rpspi->txavail != RPMSG_SPI_PORT_UNCONNECTED)
|
||||
{
|
||||
rpmsg_port_unregister(&rpspi->port);
|
||||
rpspi->txavail = RPMSG_SPI_PORT_UNCONNECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
rpspi->txavail = rxhdr->avail;
|
||||
rpmsg_port_register(&rpspi->port, (FAR const char *)(rxhdr + 1));
|
||||
}
|
||||
|
||||
rpmsg_port_queue_return_buffer(&rpspi->port.rxq, rxhdr);
|
||||
break;
|
||||
|
||||
case RPMSG_PORT_SPI_CMD_DATA:
|
||||
rpspi->rxcb(&rpspi->port, rxhdr);
|
||||
break;
|
||||
|
||||
default:
|
||||
rpmsgerr("received a unexpected frame, dropped\n");
|
||||
rpmsg_port_queue_return_buffer(&rpspi->port.rxq, rxhdr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_mreq_handler
|
||||
****************************************************************************/
|
||||
|
||||
static int rpmsg_port_spi_mreq_handler(FAR struct ioexpander_dev_s *dev,
|
||||
ioe_pinset_t pinset, FAR void *arg)
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi = arg;
|
||||
|
||||
rpmsginfo("received a mreq\n");
|
||||
rpmsg_port_spi_exchange(rpspi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_connect
|
||||
****************************************************************************/
|
||||
|
||||
static void rpmsg_port_spi_connect(FAR struct rpmsg_port_spi_s *rpspi)
|
||||
{
|
||||
bool val;
|
||||
|
||||
IOEXP_READPIN(rpspi->ioe, rpspi->mreq, &val);
|
||||
if (val)
|
||||
{
|
||||
rpmsg_port_spi_mreq_handler(NULL, 0, rpspi);
|
||||
}
|
||||
else
|
||||
{
|
||||
IOEXP_WRITEPIN(rpspi->ioe, rpspi->sreq, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_thread
|
||||
****************************************************************************/
|
||||
|
||||
static int rpmsg_port_spi_thread(int argc, FAR char *argv[])
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi =
|
||||
(FAR struct rpmsg_port_spi_s *)((uintptr_t)strtoul(argv[2], NULL, 16));
|
||||
FAR struct rpmsg_port_queue_s *queue = &rpspi->port.rxq;
|
||||
FAR struct rpmsg_port_header_s *rxhdr;
|
||||
|
||||
rpmsg_port_spi_connect(rpspi);
|
||||
for (; ; )
|
||||
{
|
||||
while ((rxhdr = rpmsg_port_queue_get_buffer(queue, true)) != NULL)
|
||||
{
|
||||
rpmsg_port_spi_process_packet(rpspi, rxhdr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_gpio_init
|
||||
****************************************************************************/
|
||||
|
||||
static int
|
||||
rpmsg_port_spi_init_gpio(FAR struct ioexpander_dev_s *ioe,
|
||||
FAR uint8_t *gpio, uint8_t pin, int invert,
|
||||
ioe_callback_t callback, FAR void *args)
|
||||
{
|
||||
int direction = callback ?
|
||||
IOEXPANDER_DIRECTION_IN_PULLDOWN : IOEXPANDER_DIRECTION_OUT;
|
||||
int ret;
|
||||
|
||||
ret = IOEXP_SETOPTION(ioe, pin, IOEXPANDER_OPTION_INVERT,
|
||||
(FAR void *)invert);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("gpio set invert option error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = IOEXP_SETDIRECTION(ioe, pin, direction);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("gpio set direction %d error: %d\n", direction, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (direction == IOEXPANDER_DIRECTION_IN_PULLDOWN)
|
||||
{
|
||||
int intcfg = invert == IOEXPANDER_VAL_INVERT ?
|
||||
IOEXPANDER_VAL_FALLING : IOEXPANDER_VAL_RISING;
|
||||
FAR void *ptr;
|
||||
|
||||
ret = IOEXP_SETOPTION(ioe, pin, IOEXPANDER_OPTION_INTCFG,
|
||||
(FAR void *)intcfg);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("gpio set int option %d error: %d\n", intcfg, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptr = IOEP_ATTACH(ioe, pin, callback, args);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
rpmsgerr("gpio attach error: %d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
*gpio = pin;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_init_hardware
|
||||
****************************************************************************/
|
||||
|
||||
static int
|
||||
rpmsg_port_spi_init_hardware(FAR struct rpmsg_port_spi_s *rpspi,
|
||||
FAR const struct rpmsg_port_spi_config_s *spicfg,
|
||||
FAR struct spi_slave_ctrlr_s *spictrlr, FAR struct ioexpander_dev_s *ioe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (spictrlr == NULL || ioe == NULL || spicfg == NULL)
|
||||
{
|
||||
rpmsgerr("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Init mreq gpio */
|
||||
|
||||
ret = rpmsg_port_spi_init_gpio(ioe, &rpspi->mreq, spicfg->mreq_pin,
|
||||
spicfg->mreq_invert,
|
||||
rpmsg_port_spi_mreq_handler, rpspi);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("mreq init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Init sreq gpio */
|
||||
|
||||
ret = rpmsg_port_spi_init_gpio(ioe, &rpspi->sreq, spicfg->sreq_pin,
|
||||
spicfg->sreq_invert, NULL, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("sreq init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rpspi->ioe = ioe;
|
||||
rpspi->spictrlr = spictrlr;
|
||||
rpspi->spislv.ops = &g_rpmsg_port_spi_slave_ops;
|
||||
SPIS_CTRLR_BIND(spictrlr, &rpspi->spislv, spicfg->mode, 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_slave_initialize
|
||||
****************************************************************************/
|
||||
|
||||
int
|
||||
rpmsg_port_spi_slave_initialize(FAR const struct rpmsg_port_config_s *cfg,
|
||||
FAR const struct rpmsg_port_spi_config_s *spicfg,
|
||||
FAR struct spi_slave_ctrlr_s *spictrlr, FAR struct ioexpander_dev_s *ioe)
|
||||
{
|
||||
FAR struct rpmsg_port_spi_s *rpspi;
|
||||
FAR char *argv[3];
|
||||
char arg1[32];
|
||||
int ret;
|
||||
|
||||
rpspi = kmm_zalloc(sizeof(*rpspi));
|
||||
if (rpspi == NULL)
|
||||
{
|
||||
rpmsgerr("malloc rpmsg spi failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = rpmsg_port_spi_init_hardware(rpspi, spicfg, spictrlr, ioe);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("rpmsg port spi hardware init failed\n");
|
||||
goto rpmsg_err;
|
||||
}
|
||||
|
||||
DEBUGASSERT(cfg->txlen == cfg->rxlen);
|
||||
ret = rpmsg_port_initialize(&rpspi->port, cfg, &g_rpmsg_port_spi_ops);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("rpmsg port initialize failed\n");
|
||||
goto rpmsg_err;
|
||||
}
|
||||
|
||||
/* Always reserve one buffer for sending/receiving cmd packet */
|
||||
|
||||
rpspi->cmdhdr = rpmsg_port_queue_get_available_buffer(
|
||||
&rpspi->port.txq, true);
|
||||
rpspi->rxhdr = rpmsg_port_queue_get_available_buffer(
|
||||
&rpspi->port.rxq, true);
|
||||
DEBUGASSERT(rpspi->cmdhdr != NULL && rpspi->rxhdr != NULL);
|
||||
|
||||
rpspi->txavail = RPMSG_SPI_PORT_UNCONNECTED;
|
||||
rpspi->rxthres = rpmsg_port_queue_navail(&rpspi->port.rxq) *
|
||||
CONFIG_RPMSG_PORT_SPI_RX_THRESHOLD / 100;
|
||||
|
||||
snprintf(arg1, sizeof(arg1), "%p", rpspi);
|
||||
argv[0] = (FAR char *)cfg->remotecpu;
|
||||
argv[1] = arg1;
|
||||
argv[2] = NULL;
|
||||
ret = kthread_create("rpmsg-spi-slv",
|
||||
CONFIG_RPMSG_PORT_SPI_THREAD_PRIORITY,
|
||||
CONFIG_RPMSG_PORT_SPI_THREAD_STACKSIZE,
|
||||
rpmsg_port_spi_thread, argv);
|
||||
if (ret < 0)
|
||||
{
|
||||
rpmsgerr("rpmsg port spi create thread failed\n");
|
||||
goto thread_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
thread_err:
|
||||
rpmsg_port_uninitialize(&rpspi->port);
|
||||
rpmsg_err:
|
||||
kmm_free(rpspi);
|
||||
return ret;
|
||||
}
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include <nuttx/ioexpander/ioexpander.h>
|
||||
#include <nuttx/spi/spi.h>
|
||||
#include <nuttx/spi/slave.h>
|
||||
|
||||
#ifdef CONFIG_RPMSG_PORT
|
||||
|
||||
@ -77,7 +78,7 @@ struct rpmsg_port_spi_config_s
|
||||
int mreq_invert;
|
||||
int sreq_invert; /* Pin options described in ioexpander.h */
|
||||
|
||||
enum spi_mode_e mode;
|
||||
int mode; /* Mode of enum spi_mode_e */
|
||||
uint32_t devid; /* Device ID of enum spi_devtype_e */
|
||||
uint32_t freq; /* SPI frequency (Hz) */
|
||||
};
|
||||
@ -123,6 +124,34 @@ rpmsg_port_spi_initialize(FAR const struct rpmsg_port_config_s *cfg,
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RPMSG_PORT_SPI_SLAVE
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rpmsg_port_spi_slave_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize a rpmsg_port_spi_slave device to communicate between two
|
||||
* chips.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cfg - Configuration of buffers needed for communication.
|
||||
* spicfg - SPI device's configuration.
|
||||
* spictrlr - SPI slave controller used for transfer data between two
|
||||
* chips.
|
||||
* ioe - ioexpander used to config gpios.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success or an negative value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int
|
||||
rpmsg_port_spi_slave_initialize(FAR const struct rpmsg_port_config_s *cfg,
|
||||
FAR const struct rpmsg_port_spi_config_s *spicfg,
|
||||
FAR struct spi_slave_ctrlr_s *spictrlr, FAR struct ioexpander_dev_s *ioe);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user