driver: eth: Implementation of Open Alliance's TC6 T1S communication
Those files provide generic functions to handle transmission between chip conforming OA TC6 standard and Zephyr's network stack represented by struct net_pkt. The communication is performed via SPI and is focused on reduced memory footprint (works with SOC equipped with 32 KiB of RAM) and robustness of operation. Signed-off-by: Lukasz Majewski <lukma@denx.de>
This commit is contained in:
parent
345f079e49
commit
1cef7f3250
|
@ -305,6 +305,7 @@
|
|||
/drivers/ethernet/*xlnx_gem* @ibirnbaum
|
||||
/drivers/ethernet/*smsc91x* @sgrrzhf
|
||||
/drivers/ethernet/*adin2111* @GeorgeCGV
|
||||
/drivers/ethernet/*oa_tc6* @lmajewski
|
||||
/drivers/ethernet/phy/ @rlubos @tbursztyka @arvinf @jukkar
|
||||
/drivers/ethernet/phy/*adin2111* @GeorgeCGV
|
||||
/drivers/mdio/ @rlubos @tbursztyka @arvinf
|
||||
|
|
393
drivers/ethernet/oa_tc6.c
Normal file
393
drivers/ethernet/oa_tc6.c
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* Copyright (c) 2023 DENX Software Engineering GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "oa_tc6.h"
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(oa_tc6, CONFIG_ETHERNET_LOG_LEVEL);
|
||||
|
||||
int oa_tc6_reg_read(struct oa_tc6 *tc6, const uint32_t reg, uint32_t *val)
|
||||
{
|
||||
uint8_t buf[OA_TC6_HDR_SIZE + 12] = { 0 };
|
||||
struct spi_buf tx_buf = { .buf = buf, .len = sizeof(buf) };
|
||||
const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
|
||||
struct spi_buf rx_buf = { .buf = buf, .len = sizeof(buf) };
|
||||
const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
|
||||
uint32_t rv, rvn, hdr_bkp, *hdr = (uint32_t *) &buf[0];
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Buffers are allocated for protected (larger) case (by 4 bytes).
|
||||
* When non-protected case - we need to decrase them
|
||||
*/
|
||||
if (!tc6->protected) {
|
||||
tx_buf.len -= sizeof(rvn);
|
||||
rx_buf.len -= sizeof(rvn);
|
||||
}
|
||||
|
||||
*hdr = FIELD_PREP(OA_CTRL_HDR_DNC, 0) |
|
||||
FIELD_PREP(OA_CTRL_HDR_WNR, 0) |
|
||||
FIELD_PREP(OA_CTRL_HDR_AID, 0) |
|
||||
FIELD_PREP(OA_CTRL_HDR_MMS, reg >> 16) |
|
||||
FIELD_PREP(OA_CTRL_HDR_ADDR, reg) |
|
||||
FIELD_PREP(OA_CTRL_HDR_LEN, 0); /* To read single register len = 0 */
|
||||
*hdr |= FIELD_PREP(OA_CTRL_HDR_P, oa_tc6_get_parity(*hdr));
|
||||
hdr_bkp = *hdr;
|
||||
*hdr = sys_cpu_to_be32(*hdr);
|
||||
|
||||
ret = spi_transceive_dt(tc6->spi, &tx, &rx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check if echoed control command header is correct */
|
||||
rv = sys_be32_to_cpu(*(uint32_t *)&buf[4]);
|
||||
if (hdr_bkp != rv) {
|
||||
LOG_ERR("Header transmission error!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = sys_be32_to_cpu(*(uint32_t *)&buf[8]);
|
||||
|
||||
/* In protected mode read data is followed by its compliment value */
|
||||
if (tc6->protected) {
|
||||
rvn = sys_be32_to_cpu(*(uint32_t *)&buf[12]);
|
||||
if (rv != ~rvn) {
|
||||
LOG_ERR("Protected mode transmission error!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*val = rv;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val)
|
||||
{
|
||||
uint8_t buf_tx[OA_TC6_HDR_SIZE + 12] = { 0 };
|
||||
uint8_t buf_rx[OA_TC6_HDR_SIZE + 12] = { 0 };
|
||||
struct spi_buf tx_buf = { .buf = buf_tx, .len = sizeof(buf_tx) };
|
||||
const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
|
||||
struct spi_buf rx_buf = { .buf = buf_rx, .len = sizeof(buf_rx) };
|
||||
const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
|
||||
uint32_t rv, rvn, hdr_bkp, *hdr = (uint32_t *) &buf_tx[0];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Buffers are allocated for protected (larger) case (by 4 bytes).
|
||||
* When non-protected case - we need to decrase them
|
||||
*/
|
||||
if (!tc6->protected) {
|
||||
tx_buf.len -= sizeof(rvn);
|
||||
rx_buf.len -= sizeof(rvn);
|
||||
}
|
||||
|
||||
*hdr = FIELD_PREP(OA_CTRL_HDR_DNC, 0) |
|
||||
FIELD_PREP(OA_CTRL_HDR_WNR, 1) |
|
||||
FIELD_PREP(OA_CTRL_HDR_AID, 0) |
|
||||
FIELD_PREP(OA_CTRL_HDR_MMS, reg >> 16) |
|
||||
FIELD_PREP(OA_CTRL_HDR_ADDR, reg) |
|
||||
FIELD_PREP(OA_CTRL_HDR_LEN, 0); /* To read single register len = 0 */
|
||||
*hdr |= FIELD_PREP(OA_CTRL_HDR_P, oa_tc6_get_parity(*hdr));
|
||||
hdr_bkp = *hdr;
|
||||
*hdr = sys_cpu_to_be32(*hdr);
|
||||
|
||||
*(uint32_t *)&buf_tx[4] = sys_cpu_to_be32(val);
|
||||
if (tc6->protected) {
|
||||
*(uint32_t *)&buf_tx[8] = sys_be32_to_cpu(~val);
|
||||
}
|
||||
|
||||
ret = spi_transceive_dt(tc6->spi, &tx, &rx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check if echoed control command header is correct */
|
||||
rv = sys_be32_to_cpu(*(uint32_t *)&buf_rx[4]);
|
||||
if (hdr_bkp != rv) {
|
||||
LOG_ERR("Header transmission error!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if echoed value is correct */
|
||||
rv = sys_be32_to_cpu(*(uint32_t *)&buf_rx[8]);
|
||||
if (val != rv) {
|
||||
LOG_ERR("Header transmission error!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* In protected mode check if read value is followed by its
|
||||
* compliment value
|
||||
*/
|
||||
if (tc6->protected) {
|
||||
rvn = sys_be32_to_cpu(*(uint32_t *)&buf_rx[12]);
|
||||
if (val != ~rvn) {
|
||||
LOG_ERR("Protected mode transmission error!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote)
|
||||
{
|
||||
uint32_t val;
|
||||
int ret;
|
||||
|
||||
ret = oa_tc6_reg_read(tc6, OA_CONFIG0, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (prote) {
|
||||
val |= OA_CONFIG0_PROTE;
|
||||
} else {
|
||||
val &= ~OA_CONFIG0_PROTE;
|
||||
}
|
||||
|
||||
ret = oa_tc6_reg_write(tc6, OA_CONFIG0, val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
tc6->protected = prote;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt)
|
||||
{
|
||||
uint16_t len = net_pkt_get_len(pkt);
|
||||
uint8_t oa_tx[tc6->cps];
|
||||
uint32_t hdr, ftr;
|
||||
uint8_t chunks, i;
|
||||
int ret;
|
||||
|
||||
chunks = (len / tc6->cps) + 1;
|
||||
|
||||
/* Check if LAN865x has any free internal buffer space */
|
||||
if (chunks > tc6->txc) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Transform struct net_pkt content into chunks */
|
||||
for (i = 1; i <= chunks; i++) {
|
||||
hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1) |
|
||||
FIELD_PREP(OA_DATA_HDR_DV, 1) |
|
||||
FIELD_PREP(OA_DATA_HDR_NORX, 1) |
|
||||
FIELD_PREP(OA_DATA_HDR_SWO, 0);
|
||||
|
||||
if (i == 1) {
|
||||
hdr |= FIELD_PREP(OA_DATA_HDR_SV, 1);
|
||||
}
|
||||
|
||||
if (i == chunks) {
|
||||
hdr |= FIELD_PREP(OA_DATA_HDR_EBO, len - 1) |
|
||||
FIELD_PREP(OA_DATA_HDR_EV, 1);
|
||||
}
|
||||
|
||||
hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr));
|
||||
|
||||
ret = net_pkt_read(pkt, oa_tx, len > tc6->cps ? tc6->cps : len);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = oa_tc6_chunk_spi_transfer(tc6, NULL, oa_tx, hdr, &ftr);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
len -= tc6->cps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void oa_tc6_update_status(struct oa_tc6 *tc6, uint32_t ftr)
|
||||
{
|
||||
tc6->exst = FIELD_GET(OA_DATA_FTR_EXST, ftr);
|
||||
tc6->sync = FIELD_GET(OA_DATA_FTR_SYNC, ftr);
|
||||
tc6->rca = FIELD_GET(OA_DATA_FTR_RCA, ftr);
|
||||
tc6->txc = FIELD_GET(OA_DATA_FTR_TXC, ftr);
|
||||
}
|
||||
|
||||
int oa_tc6_update_buf_info(struct oa_tc6 *tc6)
|
||||
{
|
||||
uint32_t val;
|
||||
int ret;
|
||||
|
||||
ret = oa_tc6_reg_read(tc6, OA_BUFSTS, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
tc6->rca = FIELD_GET(OA_BUFSTS_RCA, val);
|
||||
tc6->txc = FIELD_GET(OA_BUFSTS_TXC, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx,
|
||||
uint32_t hdr, uint32_t *ftr)
|
||||
{
|
||||
struct spi_buf tx_buf[2];
|
||||
struct spi_buf rx_buf[2];
|
||||
struct spi_buf_set tx;
|
||||
struct spi_buf_set rx;
|
||||
int ret;
|
||||
|
||||
hdr = sys_cpu_to_be32(hdr);
|
||||
tx_buf[0].buf = &hdr;
|
||||
tx_buf[0].len = sizeof(hdr);
|
||||
|
||||
tx_buf[1].buf = buf_tx;
|
||||
tx_buf[1].len = tc6->cps;
|
||||
|
||||
tx.buffers = tx_buf;
|
||||
tx.count = ARRAY_SIZE(tx_buf);
|
||||
|
||||
rx_buf[0].buf = buf_rx;
|
||||
rx_buf[0].len = tc6->cps;
|
||||
|
||||
rx_buf[1].buf = ftr;
|
||||
rx_buf[1].len = sizeof(*ftr);
|
||||
|
||||
rx.buffers = rx_buf;
|
||||
rx.count = ARRAY_SIZE(rx_buf);
|
||||
|
||||
ret = spi_transceive_dt(tc6->spi, &tx, &rx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
*ftr = sys_be32_to_cpu(*ftr);
|
||||
oa_tc6_update_status(tc6, *ftr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr)
|
||||
{
|
||||
uint32_t hdr;
|
||||
|
||||
hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1) |
|
||||
FIELD_PREP(OA_DATA_HDR_DV, 0) |
|
||||
FIELD_PREP(OA_DATA_HDR_NORX, 1);
|
||||
hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr));
|
||||
|
||||
return oa_tc6_chunk_spi_transfer(tc6, NULL, NULL, hdr, ftr);
|
||||
}
|
||||
|
||||
int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt)
|
||||
{
|
||||
struct net_buf *buf_rx = NULL;
|
||||
uint8_t chunks, sbo, ebo;
|
||||
uint32_t hdr, ftr;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Special case - append already received data (extracted from previous
|
||||
* chunk) to new packet.
|
||||
*/
|
||||
if (tc6->concat_buf) {
|
||||
net_pkt_append_buffer(pkt, tc6->concat_buf);
|
||||
tc6->concat_buf = NULL;
|
||||
}
|
||||
|
||||
for (chunks = tc6->rca; chunks; chunks--) {
|
||||
buf_rx = net_pkt_get_frag(pkt, tc6->cps, OA_TC6_BUF_ALLOC_TIMEOUT);
|
||||
if (!buf_rx) {
|
||||
LOG_ERR("OA RX: Can't allocate RX buffer fordata!");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hdr = FIELD_PREP(OA_DATA_HDR_DNC, 1);
|
||||
hdr |= FIELD_PREP(OA_DATA_HDR_P, oa_tc6_get_parity(hdr));
|
||||
|
||||
ret = oa_tc6_chunk_spi_transfer(tc6, buf_rx->data, NULL, hdr, &ftr);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("OA RX: transmission error: %d!", ret);
|
||||
goto unref_buf;
|
||||
}
|
||||
|
||||
ret = -EIO;
|
||||
if (oa_tc6_get_parity(ftr)) {
|
||||
LOG_ERR("OA RX: Footer parity error!");
|
||||
goto unref_buf;
|
||||
}
|
||||
|
||||
if (!FIELD_GET(OA_DATA_FTR_SYNC, ftr)) {
|
||||
LOG_ERR("OA RX: Configuration not SYNC'ed!");
|
||||
goto unref_buf;
|
||||
}
|
||||
|
||||
if (!FIELD_GET(OA_DATA_FTR_DV, ftr)) {
|
||||
LOG_ERR("OA RX: Data chunk not valid, skip!");
|
||||
goto unref_buf;
|
||||
}
|
||||
|
||||
sbo = FIELD_GET(OA_DATA_FTR_SWO, ftr) * sizeof(uint32_t);
|
||||
ebo = FIELD_GET(OA_DATA_FTR_EBO, ftr) + 1;
|
||||
|
||||
if (FIELD_GET(OA_DATA_FTR_SV, ftr)) {
|
||||
/*
|
||||
* Adjust beginning of the buffer with SWO only when
|
||||
* we DO NOT have two frames concatenated together
|
||||
* in one chunk.
|
||||
*/
|
||||
if (!(FIELD_GET(OA_DATA_FTR_EV, ftr) && (ebo <= sbo))) {
|
||||
if (sbo) {
|
||||
net_buf_pull(buf_rx, sbo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net_pkt_append_buffer(pkt, buf_rx);
|
||||
buf_rx->len = tc6->cps;
|
||||
|
||||
if (FIELD_GET(OA_DATA_FTR_EV, ftr)) {
|
||||
/*
|
||||
* Check if received frame shall be dropped - i.e. MAC has
|
||||
* detected error condition, which shall result in frame drop
|
||||
* by the SPI host.
|
||||
*/
|
||||
if (FIELD_GET(OA_DATA_FTR_FD, ftr)) {
|
||||
ret = -EIO;
|
||||
goto unref_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenation of frames in a single chunk - one frame ends
|
||||
* and second one starts just afterwards (ebo == sbo).
|
||||
*/
|
||||
if (FIELD_GET(OA_DATA_FTR_SV, ftr) && (ebo <= sbo)) {
|
||||
tc6->concat_buf = net_buf_clone(buf_rx, OA_TC6_BUF_ALLOC_TIMEOUT);
|
||||
if (!tc6->concat_buf) {
|
||||
LOG_ERR("OA RX: Can't allocate RX buffer for data!");
|
||||
ret = -ENOMEM;
|
||||
goto unref_buf;
|
||||
}
|
||||
net_buf_pull(tc6->concat_buf, sbo);
|
||||
}
|
||||
|
||||
/* Set final size of the buffer */
|
||||
buf_rx->len = ebo;
|
||||
/*
|
||||
* Exit when complete packet is read and added to
|
||||
* struct net_pkt
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unref_buf:
|
||||
net_buf_unref(buf_rx);
|
||||
return ret;
|
||||
}
|
233
drivers/ethernet/oa_tc6.h
Normal file
233
drivers/ethernet/oa_tc6.h
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright (c) 2023 DENX Software Engineering GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef OA_TC6_CFG_H__
|
||||
#define OA_TC6_CFG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/net/net_pkt.h>
|
||||
|
||||
#define MMS_REG(m, r) ((((m) & GENMASK(3, 0)) << 16) | ((r) & GENMASK(15, 0)))
|
||||
/* Memory Map Sector (MMS) 0 */
|
||||
#define OA_ID MMS_REG(0x0, 0x000) /* expect 0x11 */
|
||||
#define OA_PHYID MMS_REG(0x0, 0x001)
|
||||
#define OA_RESET MMS_REG(0x0, 0x003)
|
||||
#define OA_RESET_SWRESET BIT(0)
|
||||
#define OA_CONFIG0 MMS_REG(0x0, 0x004)
|
||||
#define OA_CONFIG0_SYNC BIT(15)
|
||||
#define OA_CONFIG0_PROTE BIT(5)
|
||||
#define OA_STATUS0 MMS_REG(0x0, 0x008)
|
||||
#define OA_STATUS0_RESETC BIT(6)
|
||||
#define OA_STATUS1 MMS_REG(0x0, 0x009)
|
||||
#define OA_BUFSTS MMS_REG(0x0, 0x00B)
|
||||
#define OA_BUFSTS_TXC GENMASK(15, 8)
|
||||
#define OA_BUFSTS_RCA GENMASK(7, 0)
|
||||
#define OA_IMASK0 MMS_REG(0x0, 0x00C)
|
||||
#define OA_IMASK0_TXPEM BIT(0)
|
||||
#define OA_IMASK0_TXBOEM BIT(1)
|
||||
#define OA_IMASK0_TXBUEM BIT(2)
|
||||
#define OA_IMASK0_RXBOEM BIT(3)
|
||||
#define OA_IMASK0_LOFEM BIT(4)
|
||||
#define OA_IMASK0_HDREM BIT(5)
|
||||
#define OA_IMASK1 MMS_REG(0x0, 0x00D)
|
||||
#define OA_IMASK0_UV18M BIT(19)
|
||||
|
||||
/* OA Control header */
|
||||
#define OA_CTRL_HDR_DNC BIT(31)
|
||||
#define OA_CTRL_HDR_HDRB BIT(30)
|
||||
#define OA_CTRL_HDR_WNR BIT(29)
|
||||
#define OA_CTRL_HDR_AID BIT(28)
|
||||
#define OA_CTRL_HDR_MMS GENMASK(27, 24)
|
||||
#define OA_CTRL_HDR_ADDR GENMASK(23, 8)
|
||||
#define OA_CTRL_HDR_LEN GENMASK(7, 1)
|
||||
#define OA_CTRL_HDR_P BIT(0)
|
||||
|
||||
/* OA Data header */
|
||||
#define OA_DATA_HDR_DNC BIT(31)
|
||||
#define OA_DATA_HDR_SEQ BIT(30)
|
||||
#define OA_DATA_HDR_NORX BIT(29)
|
||||
#define OA_DATA_HDR_DV BIT(21)
|
||||
#define OA_DATA_HDR_SV BIT(20)
|
||||
#define OA_DATA_HDR_SWO GENMASK(19, 16)
|
||||
#define OA_DATA_HDR_EV BIT(14)
|
||||
#define OA_DATA_HDR_EBO GENMASK(13, 8)
|
||||
#define OA_DATA_HDR_P BIT(0)
|
||||
|
||||
/* OA Data footer */
|
||||
#define OA_DATA_FTR_EXST BIT(31)
|
||||
#define OA_DATA_FTR_HDRB BIT(30)
|
||||
#define OA_DATA_FTR_SYNC BIT(29)
|
||||
#define OA_DATA_FTR_RCA GENMASK(28, 24)
|
||||
#define OA_DATA_FTR_DV BIT(21)
|
||||
#define OA_DATA_FTR_SV BIT(20)
|
||||
#define OA_DATA_FTR_SWO GENMASK(19, 16)
|
||||
#define OA_DATA_FTR_FD BIT(15)
|
||||
#define OA_DATA_FTR_EV BIT(14)
|
||||
#define OA_DATA_FTR_EBO GENMASK(13, 8)
|
||||
#define OA_DATA_FTR_TXC GENMASK(5, 1)
|
||||
#define OA_DATA_FTR_P BIT(0)
|
||||
|
||||
#define OA_TC6_HDR_SIZE 4
|
||||
#define OA_TC6_FTR_SIZE 4
|
||||
#define OA_TC6_BUF_ALLOC_TIMEOUT K_MSEC(10)
|
||||
|
||||
/**
|
||||
* @brief OA TC6 data.
|
||||
*/
|
||||
struct oa_tc6 {
|
||||
/** Pointer to SPI device */
|
||||
const struct spi_dt_spec *spi;
|
||||
|
||||
/** OA data payload (chunk) size */
|
||||
uint8_t cps;
|
||||
|
||||
/**
|
||||
* Number of available chunks buffers in OA TC6 device to store
|
||||
* data for transmission
|
||||
*/
|
||||
uint8_t txc;
|
||||
|
||||
/** Number of available chunks to read from OA TC6 device */
|
||||
uint8_t rca;
|
||||
|
||||
/** Indication of pending interrupt in OA TC6 device */
|
||||
bool exst;
|
||||
|
||||
/** Indication of OA TC6 device being ready for transmission */
|
||||
bool sync;
|
||||
|
||||
/** Indication of protected control transmission mode */
|
||||
bool protected;
|
||||
|
||||
/** Pointer to network buffer concatenated from received chunk */
|
||||
struct net_buf *concat_buf;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
uint32_t value;
|
||||
} oa_mem_map_t;
|
||||
|
||||
/**
|
||||
* @brief Calculate parity bit from data
|
||||
*
|
||||
* @param x data to calculate parity
|
||||
*
|
||||
* @return 0 if number of ones is odd, 1 otherwise.
|
||||
*/
|
||||
static inline bool oa_tc6_get_parity(const uint32_t x)
|
||||
{
|
||||
uint32_t y;
|
||||
|
||||
y = x ^ (x >> 1);
|
||||
y = y ^ (y >> 2);
|
||||
y = y ^ (y >> 4);
|
||||
y = y ^ (y >> 8);
|
||||
y = y ^ (y >> 16);
|
||||
|
||||
return !(y & 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read OA TC6 compliant device single register
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @param reg register to read
|
||||
|
||||
* @param val pointer to variable to store read value
|
||||
*
|
||||
* @return 0 if read was successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_reg_read(struct oa_tc6 *tc6, const uint32_t reg, uint32_t *val);
|
||||
|
||||
/**
|
||||
* @brief Write to OA TC6 compliant device a single register
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @param reg register to read
|
||||
|
||||
* @param val data to send to device
|
||||
*
|
||||
* @return 0 if write was successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the protected mode for control transactions
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @param prote enable or disable protected control transactions
|
||||
*
|
||||
* @return 0 if operation was successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote);
|
||||
|
||||
/**
|
||||
* @brief Send OA TC6 data chunks to the device
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @param pkt network packet to be send
|
||||
*
|
||||
* @return 0 if data send was successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt);
|
||||
|
||||
/**
|
||||
* @brief Read data chunks from OA TC6 device
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @param pkt network packet to store received data
|
||||
*
|
||||
* @return 0 if read was successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt);
|
||||
|
||||
/**
|
||||
* @brief Perform SPI transfer of single chunk from/to OA TC6 device
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @param buf_rx buffer to store read data
|
||||
*
|
||||
* @param buf_tx buffer with data to send
|
||||
*
|
||||
* @param hdr OA TC6 data transmission header value
|
||||
*
|
||||
* @param ftr poniter to OA TC6 data received footer
|
||||
*
|
||||
* @return 0 if transmission was successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx,
|
||||
uint32_t hdr, uint32_t *ftr);
|
||||
|
||||
/**
|
||||
* @brief Read status from OA TC6 device
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @param ftr poniter to OA TC6 data received footer
|
||||
*
|
||||
* @return 0 if successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr);
|
||||
|
||||
/**
|
||||
* @brief Read from OA TC6 device and update buffer information
|
||||
*
|
||||
* @param tc6 OA TC6 specific data
|
||||
*
|
||||
* @return 0 if successful, <0 otherwise.
|
||||
*/
|
||||
int oa_tc6_update_buf_info(struct oa_tc6 *tc6);
|
||||
#endif /* OA_TC6_CFG_H__ */
|
Loading…
Reference in a new issue