2016-11-11 22:46:28 +01:00
|
|
|
/* ieee802154_cc2520.c - TI CC2520 driver */
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
#define DT_DRV_COMPAT ti_cc2520
|
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Intel Corporation.
|
|
|
|
*
|
2017-01-19 02:01:01 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2016-03-18 13:08:40 +01:00
|
|
|
*/
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
#define LOG_MODULE_NAME ieee802154_cc2520
|
2018-11-09 15:30:56 +01:00
|
|
|
#define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL
|
2018-09-03 16:28:47 +02:00
|
|
|
|
|
|
|
#include <logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
2016-08-10 11:05:51 +02:00
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
#include <errno.h>
|
|
|
|
|
2016-11-09 16:53:16 +01:00
|
|
|
#include <kernel.h>
|
2016-03-18 13:08:40 +01:00
|
|
|
#include <arch/cpu.h>
|
2020-03-19 18:32:37 +01:00
|
|
|
#include <debug/stack.h>
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
#include <device.h>
|
|
|
|
#include <init.h>
|
2016-06-15 10:46:10 +02:00
|
|
|
#include <net/net_if.h>
|
2017-04-03 17:14:35 +02:00
|
|
|
#include <net/net_pkt.h>
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2019-06-26 16:33:41 +02:00
|
|
|
#include <sys/byteorder.h>
|
2016-03-18 13:08:40 +01:00
|
|
|
#include <string.h>
|
2017-10-14 00:45:02 +02:00
|
|
|
#include <random/rand32.h>
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2019-06-25 21:53:52 +02:00
|
|
|
#include <drivers/gpio.h>
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-02-22 08:37:51 +01:00
|
|
|
#ifdef CONFIG_IEEE802154_CC2520_CRYPTO
|
|
|
|
|
|
|
|
#include <crypto/cipher.h>
|
|
|
|
#include <crypto/cipher_structs.h>
|
|
|
|
|
|
|
|
#endif /* CONFIG_IEEE802154_CC2520_CRYPTO */
|
|
|
|
|
2016-06-15 10:46:10 +02:00
|
|
|
#include <net/ieee802154_radio.h>
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
#include "ieee802154_cc2520.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Content is split as follows:
|
|
|
|
* 1 - Debug related functions
|
|
|
|
* 2 - Generic helper functions (for any parts)
|
|
|
|
* 3 - GPIO related functions
|
|
|
|
* 4 - TX related helper functions
|
|
|
|
* 5 - RX related helper functions
|
|
|
|
* 6 - Radio device API functions
|
|
|
|
* 7 - Legacy radio device API functions
|
|
|
|
* 8 - Initialization
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#define CC2520_AUTOMATISM (FRMCTRL0_AUTOCRC | FRMCTRL0_AUTOACK)
|
|
|
|
#define CC2520_TX_THRESHOLD (0x7F)
|
|
|
|
#define CC2520_FCS_LENGTH (2)
|
|
|
|
|
2020-05-08 19:04:55 +02:00
|
|
|
#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
|
2017-09-29 09:33:25 +02:00
|
|
|
static struct spi_cs_control cs_ctrl;
|
|
|
|
#endif
|
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
/*********
|
|
|
|
* DEBUG *
|
|
|
|
********/
|
2018-11-09 15:30:56 +01:00
|
|
|
#if LOG_LEVEL == LOG_LEVEL_DBG
|
2019-03-12 22:15:42 +01:00
|
|
|
static inline void cc2520_print_gpio_config(struct device *dev)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("GPIOCTRL0/1/2/3/4/5 = 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x",
|
2017-09-29 09:33:25 +02:00
|
|
|
read_reg_gpioctrl0(cc2520),
|
|
|
|
read_reg_gpioctrl1(cc2520),
|
|
|
|
read_reg_gpioctrl2(cc2520),
|
|
|
|
read_reg_gpioctrl3(cc2520),
|
|
|
|
read_reg_gpioctrl4(cc2520),
|
|
|
|
read_reg_gpioctrl5(cc2520));
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("GPIOPOLARITY: 0x%x",
|
2017-09-29 09:33:25 +02:00
|
|
|
read_reg_gpiopolarity(cc2520));
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("GPIOCTRL: 0x%x",
|
2017-09-29 09:33:25 +02:00
|
|
|
read_reg_gpioctrl(cc2520));
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
static inline void cc2520_print_exceptions(struct cc2520_context *cc2520)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t flag = read_reg_excflag0(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("EXCFLAG0:");
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_RF_IDLE) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RF_IDLE");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_TX_FRM_DONE) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" TX_FRM_DONE");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_TX_ACK_DONE) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" TX_ACK_DONE");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_TX_UNDERFLOW) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" TX_UNDERFLOW");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_TX_OVERFLOW) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" TX_OVERFLOW");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_RX_UNDERFLOW) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RX_UNDERFLOW");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_RX_OVERFLOW) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RX_OVERFLOW");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG0_RXENABLE_ZERO) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RXENABLE_ZERO");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
flag = read_reg_excflag1(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2018-10-16 14:33:14 +02:00
|
|
|
LOG_DBG("EXCFLAG1:");
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_RX_FRM_DONE) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RX_FRM_DONE");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_RX_FRM_ACCEPTED) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RX_FRM_ACCEPTED");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_SRC_MATCH_DONE) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" SRC_MATCH_DONE");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_SRC_MATCH_FOUND) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" SRC_MATCH_FOUND");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_FIFOP) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" FIFOP");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_SFD) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" SFD");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_DPU_DONE_L) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" DPU_DONE_L");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG1_DPU_DONE_H) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" DPU_DONE_H");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
static inline void cc2520_print_errors(struct cc2520_context *cc2520)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t flag = read_reg_excflag2(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2018-10-16 14:33:14 +02:00
|
|
|
LOG_DBG("EXCFLAG2:");
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG2_MEMADDR_ERROR) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" MEMADDR_ERROR");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG2_USAGE_ERROR) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" USAGE_ERROR");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG2_OPERAND_ERROR) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" OPERAND_ERROR");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG2_SPI_ERROR) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" SPI_ERROR");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG2_RF_NO_LOCK) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RF_NO_LOCK");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG2_RX_FRM_ABORTED) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RX_FRM_ABORTED");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
if (flag & EXCFLAG2_RFBUFMOV_TIMEOUT) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG(" RFBUFMOV_TIMEOUT");
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
}
|
2016-12-02 10:49:34 +01:00
|
|
|
#else
|
2019-03-12 22:15:42 +01:00
|
|
|
#define cc2520_print_gpio_config(...)
|
|
|
|
#define cc2520_print_exceptions(...)
|
|
|
|
#define cc2520_print_errors(...)
|
2018-11-09 15:30:56 +01:00
|
|
|
#endif /* LOG_LEVEL == LOG_LEVEL_DBG */
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*********************
|
|
|
|
* Generic functions *
|
|
|
|
********************/
|
2019-03-12 22:15:42 +01:00
|
|
|
#define z_usleep(usec) k_busy_wait(usec)
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
bool z_cc2520_access(struct cc2520_context *ctx, bool read, uint8_t ins,
|
|
|
|
uint16_t addr, void *data, size_t length)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t cmd_buf[2];
|
2017-09-29 09:33:25 +02:00
|
|
|
struct spi_buf buf[2] = {
|
|
|
|
{
|
|
|
|
.buf = cmd_buf,
|
|
|
|
.len = 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.buf = data,
|
|
|
|
.len = length,
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
struct spi_buf_set tx = {
|
|
|
|
.buffers = buf,
|
|
|
|
};
|
2016-06-20 09:23:57 +02:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
cmd_buf[0] = ins;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (ins == CC2520_INS_MEMRD || ins == CC2520_INS_MEMWR) {
|
|
|
|
buf[0].len = 2;
|
2020-05-27 18:26:57 +02:00
|
|
|
cmd_buf[0] |= (uint8_t)(addr >> 8);
|
|
|
|
cmd_buf[1] = (uint8_t)(addr & 0xff);
|
2017-09-29 09:33:25 +02:00
|
|
|
} else if (ins == CC2520_INS_REGRD || ins == CC2520_INS_REGWR) {
|
2020-05-27 18:26:57 +02:00
|
|
|
cmd_buf[0] |= (uint8_t)(addr & 0xff);
|
2017-09-29 09:33:25 +02:00
|
|
|
}
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (read) {
|
|
|
|
const struct spi_buf_set rx = {
|
|
|
|
.buffers = buf,
|
|
|
|
.count = 2
|
|
|
|
};
|
2017-02-22 08:37:51 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
tx.count = 1;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
return (spi_transceive(ctx->spi, &ctx->spi_cfg, &tx, &rx) == 0);
|
|
|
|
}
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
tx.count = data ? 2 : 1;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
return (spi_write(ctx->spi, &ctx->spi_cfg, &tx) == 0);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline uint8_t cc2520_status(struct cc2520_context *ctx)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t status;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
if (z_cc2520_access(ctx, true, CC2520_INS_SNOP, 0, &status, 1)) {
|
2017-09-29 09:33:25 +02:00
|
|
|
return status;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool verify_osc_stabilization(struct cc2520_context *cc2520)
|
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t timeout = 100U;
|
|
|
|
uint8_t status;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
do {
|
2019-03-12 22:15:42 +01:00
|
|
|
status = cc2520_status(cc2520);
|
|
|
|
z_usleep(1);
|
2016-03-18 13:08:40 +01:00
|
|
|
timeout--;
|
|
|
|
} while (!(status & CC2520_STATUS_XOSC_STABLE_N_RUNNING) && timeout);
|
|
|
|
|
|
|
|
return !!(status & CC2520_STATUS_XOSC_STABLE_N_RUNNING);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline uint8_t *get_mac(struct device *dev)
|
2016-06-15 10:46:10 +02:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
2017-03-16 13:44:12 +01:00
|
|
|
|
|
|
|
#if defined(CONFIG_IEEE802154_CC2520_RANDOM_MAC)
|
2020-05-27 18:26:57 +02:00
|
|
|
uint32_t *ptr = (uint32_t *)(cc2520->mac_addr + 4);
|
2016-06-15 10:46:10 +02:00
|
|
|
|
2017-03-16 13:44:12 +01:00
|
|
|
UNALIGNED_PUT(sys_rand32_get(), ptr);
|
|
|
|
|
|
|
|
cc2520->mac_addr[7] = (cc2520->mac_addr[7] & ~0x01) | 0x02;
|
|
|
|
#else
|
|
|
|
cc2520->mac_addr[4] = CONFIG_IEEE802154_CC2520_MAC4;
|
|
|
|
cc2520->mac_addr[5] = CONFIG_IEEE802154_CC2520_MAC5;
|
|
|
|
cc2520->mac_addr[6] = CONFIG_IEEE802154_CC2520_MAC6;
|
|
|
|
cc2520->mac_addr[7] = CONFIG_IEEE802154_CC2520_MAC7;
|
|
|
|
#endif
|
|
|
|
|
2016-10-31 13:32:02 +01:00
|
|
|
cc2520->mac_addr[0] = 0x00;
|
|
|
|
cc2520->mac_addr[1] = 0x12;
|
|
|
|
cc2520->mac_addr[2] = 0x4b;
|
|
|
|
cc2520->mac_addr[3] = 0x00;
|
2016-06-15 10:46:10 +02:00
|
|
|
|
|
|
|
return cc2520->mac_addr;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static int cc2520_set_pan_id(struct device *dev, uint16_t pan_id)
|
2017-09-05 14:20:35 +02:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("0x%x", pan_id);
|
2017-09-05 14:20:35 +02:00
|
|
|
|
|
|
|
pan_id = sys_le16_to_cpu(pan_id);
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
if (!write_mem_pan_id(cc2520, (uint8_t *) &pan_id)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Failed");
|
2017-09-05 14:20:35 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static int cc2520_set_short_addr(struct device *dev, uint16_t short_addr)
|
2017-09-05 14:20:35 +02:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("0x%x", short_addr);
|
2017-09-05 14:20:35 +02:00
|
|
|
|
|
|
|
short_addr = sys_le16_to_cpu(short_addr);
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
if (!write_mem_short_addr(cc2520, (uint8_t *) &short_addr)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Failed");
|
2017-09-05 14:20:35 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static int cc2520_set_ieee_addr(struct device *dev, const uint8_t *ieee_addr)
|
2017-09-05 14:20:35 +02:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!write_mem_ext_addr(cc2520, (void *)ieee_addr)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Failed");
|
2017-09-05 14:20:35 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
|
2017-09-05 14:20:35 +02:00
|
|
|
ieee_addr[7], ieee_addr[6], ieee_addr[5], ieee_addr[4],
|
|
|
|
ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
/******************
|
|
|
|
* GPIO functions *
|
|
|
|
*****************/
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline void set_reset(struct device *dev, uint32_t value)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_set_raw(cc2520->gpios[CC2520_GPIO_IDX_RESET].dev,
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_RESET].pin, value);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline void set_vreg_en(struct device *dev, uint32_t value)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_set_raw(cc2520->gpios[CC2520_GPIO_IDX_VREG_EN].dev,
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_VREG_EN].pin, value);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline uint32_t get_fifo(struct cc2520_context *cc2520)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint32_t pin_value;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2020-01-27 15:10:48 +01:00
|
|
|
pin_value = gpio_pin_get_raw(cc2520->gpios[CC2520_GPIO_IDX_FIFO].dev,
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFO].pin);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
return pin_value;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline uint32_t get_fifop(struct cc2520_context *cc2520)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint32_t pin_value;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2020-01-27 15:10:48 +01:00
|
|
|
pin_value = gpio_pin_get_raw(cc2520->gpios[CC2520_GPIO_IDX_FIFOP].dev,
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFOP].pin);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
return pin_value;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline uint32_t get_cca(struct cc2520_context *cc2520)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint32_t pin_value;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2020-01-27 15:10:48 +01:00
|
|
|
pin_value = gpio_pin_get_raw(cc2520->gpios[CC2520_GPIO_IDX_CCA].dev,
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_CCA].pin);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
return pin_value;
|
|
|
|
}
|
|
|
|
|
2016-04-12 11:28:05 +02:00
|
|
|
static inline void sfd_int_handler(struct device *port,
|
2020-05-27 18:26:57 +02:00
|
|
|
struct gpio_callback *cb, uint32_t pins)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2016-04-12 11:28:05 +02:00
|
|
|
struct cc2520_context *cc2520 =
|
|
|
|
CONTAINER_OF(cb, struct cc2520_context, sfd_cb);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
if (atomic_get(&cc2520->tx) == 1) {
|
|
|
|
atomic_set(&cc2520->tx, 0);
|
2016-11-09 16:53:16 +01:00
|
|
|
k_sem_give(&cc2520->tx_sync);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-12 11:28:05 +02:00
|
|
|
static inline void fifop_int_handler(struct device *port,
|
2020-05-27 18:26:57 +02:00
|
|
|
struct gpio_callback *cb, uint32_t pins)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2016-04-12 11:28:05 +02:00
|
|
|
struct cc2520_context *cc2520 =
|
|
|
|
CONTAINER_OF(cb, struct cc2520_context, fifop_cb);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
/* Note: Errata document - 1.2 */
|
|
|
|
if (!get_fifop(cc2520) && !get_fifop(cc2520)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_fifo(cc2520)) {
|
|
|
|
cc2520->overflow = true;
|
|
|
|
}
|
|
|
|
|
2016-11-09 16:53:16 +01:00
|
|
|
k_sem_give(&cc2520->rx_lock);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void enable_fifop_interrupt(struct cc2520_context *cc2520,
|
|
|
|
bool enable)
|
|
|
|
{
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_interrupt_configure(
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFOP].dev,
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFOP].pin,
|
|
|
|
enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void enable_sfd_interrupt(struct cc2520_context *cc2520,
|
|
|
|
bool enable)
|
|
|
|
{
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_interrupt_configure(
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_SFD].dev,
|
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_SFD].pin,
|
|
|
|
enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void setup_gpio_callbacks(struct device *dev)
|
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2016-11-28 17:06:15 +01:00
|
|
|
gpio_init_callback(&cc2520->sfd_cb, sfd_int_handler,
|
|
|
|
BIT(cc2520->gpios[CC2520_GPIO_IDX_SFD].pin));
|
|
|
|
gpio_add_callback(cc2520->gpios[CC2520_GPIO_IDX_SFD].dev,
|
2016-04-12 11:28:05 +02:00
|
|
|
&cc2520->sfd_cb);
|
|
|
|
|
2016-11-28 17:06:15 +01:00
|
|
|
gpio_init_callback(&cc2520->fifop_cb, fifop_int_handler,
|
|
|
|
BIT(cc2520->gpios[CC2520_GPIO_IDX_FIFOP].pin));
|
|
|
|
gpio_add_callback(cc2520->gpios[CC2520_GPIO_IDX_FIFOP].dev,
|
2016-04-12 11:28:05 +02:00
|
|
|
&cc2520->fifop_cb);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* TX functions *
|
|
|
|
***************/
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline bool write_txfifo_length(struct cc2520_context *ctx, uint8_t len)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t length = len + CC2520_FCS_LENGTH;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
return z_cc2520_access(ctx, false, CC2520_INS_TXBUF, 0, &length, 1);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
static inline bool write_txfifo_content(struct cc2520_context *ctx,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *frame, uint8_t len)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2019-03-12 22:15:42 +01:00
|
|
|
return z_cc2520_access(ctx, false, CC2520_INS_TXBUF, 0, frame, len);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool verify_txfifo_status(struct cc2520_context *cc2520,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t len)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2017-09-29 09:33:25 +02:00
|
|
|
if (read_reg_txfifocnt(cc2520) < len ||
|
|
|
|
(read_reg_excflag0(cc2520) & EXCFLAG0_TX_UNDERFLOW)) {
|
2016-03-18 13:08:40 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool verify_tx_done(struct cc2520_context *cc2520)
|
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t timeout = 10U;
|
|
|
|
uint8_t status;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
do {
|
2019-03-12 22:15:42 +01:00
|
|
|
z_usleep(1);
|
2016-03-18 13:08:40 +01:00
|
|
|
timeout--;
|
2017-09-29 09:33:25 +02:00
|
|
|
status = read_reg_excflag0(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
} while (!(status & EXCFLAG0_TX_FRM_DONE) && timeout);
|
|
|
|
|
|
|
|
return !!(status & EXCFLAG0_TX_FRM_DONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* RX functions *
|
|
|
|
***************/
|
2016-05-04 11:16:17 +02:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
static inline void flush_rxfifo(struct cc2520_context *cc2520)
|
|
|
|
{
|
|
|
|
/* Note: Errata document - 1.1 */
|
|
|
|
enable_fifop_interrupt(cc2520, false);
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
instruct_sflushrx(cc2520);
|
|
|
|
instruct_sflushrx(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
enable_fifop_interrupt(cc2520, true);
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
write_reg_excflag0(cc2520, EXCFLAG0_RESET_RX_FLAGS);
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline uint8_t read_rxfifo_length(struct cc2520_context *ctx)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t len;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
if (z_cc2520_access(ctx, true, CC2520_INS_RXBUF, 0, &len, 1)) {
|
2017-09-29 09:33:25 +02:00
|
|
|
return len;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
static inline bool read_rxfifo_content(struct cc2520_context *ctx,
|
2020-05-27 18:26:57 +02:00
|
|
|
struct net_buf *buf, uint8_t len)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2019-03-12 22:15:42 +01:00
|
|
|
if (!z_cc2520_access(ctx, true, CC2520_INS_RXBUF, 0, buf->data, len)) {
|
2016-05-04 11:16:17 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (read_reg_excflag0(ctx) & EXCFLAG0_RX_UNDERFLOW) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("RX underflow!");
|
2016-05-04 11:16:17 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-20 12:06:50 +01:00
|
|
|
net_buf_add(buf, len);
|
2016-05-04 11:16:17 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline void insert_radio_noise_details(struct net_pkt *pkt, uint8_t *buf)
|
2017-10-03 10:07:48 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t lqi;
|
2017-10-03 10:07:48 +02:00
|
|
|
|
|
|
|
net_pkt_set_ieee802154_rssi(pkt, buf[0]);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* CC2520 does not provide an LQI but a correlation factor.
|
|
|
|
* See Section 20.6
|
|
|
|
* Such calculation can be loosely used to transform it to lqi:
|
|
|
|
* corr <= 50 ? lqi = 0
|
|
|
|
* or:
|
|
|
|
* corr >= 110 ? lqi = 255
|
|
|
|
* else:
|
|
|
|
* lqi = (lqi - 50) * 4
|
|
|
|
*/
|
|
|
|
lqi = buf[1] & CC2520_FCS_CORRELATION;
|
2019-03-27 02:57:45 +01:00
|
|
|
if (lqi <= 50U) {
|
2018-11-29 20:12:22 +01:00
|
|
|
lqi = 0U;
|
2019-03-27 02:57:45 +01:00
|
|
|
} else if (lqi >= 110U) {
|
2018-11-29 20:12:22 +01:00
|
|
|
lqi = 255U;
|
2017-10-03 10:07:48 +02:00
|
|
|
} else {
|
2019-03-27 02:57:45 +01:00
|
|
|
lqi = (lqi - 50U) << 2;
|
2017-10-03 10:07:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
net_pkt_set_ieee802154_lqi(pkt, lqi);
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
static inline bool verify_crc(struct cc2520_context *ctx, struct net_pkt *pkt)
|
2016-11-15 15:30:23 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t fcs[2];
|
2017-11-16 11:11:51 +01:00
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
if (!z_cc2520_access(ctx, true, CC2520_INS_RXBUF, 0, &fcs, 2)) {
|
2017-09-29 09:33:25 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-16 11:11:51 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!(fcs[1] & CC2520_FCS_CRC_OK)) {
|
|
|
|
return false;
|
2016-11-15 15:30:23 +01:00
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
insert_radio_noise_details(pkt, fcs);
|
2016-11-15 15:30:23 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
static inline bool verify_rxfifo_validity(struct cc2520_context *ctx,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t pkt_len)
|
2016-05-04 11:16:17 +02:00
|
|
|
{
|
2017-09-29 09:33:25 +02:00
|
|
|
if (pkt_len < 2 || read_reg_rxfifocnt(ctx) != pkt_len) {
|
2016-05-04 11:16:17 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2016-11-09 16:53:16 +01:00
|
|
|
static void cc2520_rx(int arg)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
|
|
|
struct device *dev = INT_TO_POINTER(arg);
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
2017-04-05 08:37:44 +02:00
|
|
|
struct net_pkt *pkt;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t pkt_len;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
while (1) {
|
2017-04-05 08:37:44 +02:00
|
|
|
pkt = NULL;
|
2016-11-04 12:25:00 +01:00
|
|
|
|
2016-11-09 16:53:16 +01:00
|
|
|
k_sem_take(&cc2520->rx_lock, K_FOREVER);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
if (cc2520->overflow) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("RX overflow!");
|
2016-03-18 13:08:40 +01:00
|
|
|
cc2520->overflow = false;
|
2016-06-15 10:46:10 +02:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
goto flush;
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
pkt_len = read_rxfifo_length(cc2520) & 0x7f;
|
|
|
|
if (!verify_rxfifo_validity(cc2520, pkt_len)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Invalid content");
|
2016-03-18 13:08:40 +01:00
|
|
|
goto flush;
|
|
|
|
}
|
|
|
|
|
2019-02-20 12:06:50 +01:00
|
|
|
pkt = net_pkt_alloc_with_buffer(cc2520->iface, pkt_len,
|
|
|
|
AF_UNSPEC, 0, K_NO_WAIT);
|
2017-04-05 08:37:44 +02:00
|
|
|
if (!pkt) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("No pkt available");
|
2016-03-18 13:08:40 +01:00
|
|
|
goto flush;
|
|
|
|
}
|
|
|
|
|
2017-11-16 11:11:51 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_IEEE802154_RAW_MODE)) {
|
2019-03-27 02:57:45 +01:00
|
|
|
pkt_len -= 2U;
|
2016-11-16 15:44:33 +01:00
|
|
|
}
|
|
|
|
|
2019-02-20 12:06:50 +01:00
|
|
|
if (!read_rxfifo_content(cc2520, pkt->buffer, pkt_len)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("No content read");
|
2016-11-04 12:25:00 +01:00
|
|
|
goto flush;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
if (!verify_crc(cc2520, pkt)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Bad packet CRC");
|
2016-06-15 10:46:10 +02:00
|
|
|
goto out;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
if (ieee802154_radio_handle_ack(cc2520->iface, pkt) == NET_OK) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("ACK packet handled");
|
2016-06-15 10:46:10 +02:00
|
|
|
goto out;
|
|
|
|
}
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("Caught a packet (%u)", pkt_len);
|
2016-06-15 10:46:10 +02:00
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
if (net_recv_data(cc2520->iface, pkt) < 0) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("Packet dropped by NET stack");
|
2016-06-15 10:46:10 +02:00
|
|
|
goto out;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2020-03-12 22:18:42 +01:00
|
|
|
log_stack_usage(&cc2520->cc2520_rx_thread);
|
2016-11-04 12:25:00 +01:00
|
|
|
continue;
|
2016-03-18 13:08:40 +01:00
|
|
|
flush:
|
2019-03-12 22:15:42 +01:00
|
|
|
cc2520_print_exceptions(cc2520);
|
|
|
|
cc2520_print_errors(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
flush_rxfifo(cc2520);
|
2016-11-04 12:25:00 +01:00
|
|
|
out:
|
2017-04-05 08:37:44 +02:00
|
|
|
if (pkt) {
|
|
|
|
net_pkt_unref(pkt);
|
2016-11-04 12:25:00 +01:00
|
|
|
}
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/********************
|
|
|
|
* Radio device API *
|
|
|
|
*******************/
|
2017-09-04 15:24:36 +02:00
|
|
|
static enum ieee802154_hw_caps cc2520_get_capabilities(struct device *dev)
|
|
|
|
{
|
2017-09-05 14:09:15 +02:00
|
|
|
/* ToDo: Add support for IEEE802154_HW_PROMISC */
|
|
|
|
return IEEE802154_HW_FCS |
|
|
|
|
IEEE802154_HW_2_4_GHZ |
|
|
|
|
IEEE802154_HW_FILTER;
|
2017-09-04 15:24:36 +02:00
|
|
|
}
|
|
|
|
|
2016-06-15 10:46:10 +02:00
|
|
|
static int cc2520_cca(struct device *dev)
|
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
|
|
|
if (!get_cca(cc2520)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_WRN("Busy");
|
2016-06-15 10:46:10 +02:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static int cc2520_set_channel(struct device *dev, uint16_t channel)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("%u", channel);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
if (channel < 11 || channel > 26) {
|
2016-04-27 14:49:41 +02:00
|
|
|
return -EINVAL;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* See chapter 16 */
|
2019-03-28 21:57:54 +01:00
|
|
|
channel = 11 + (channel - 11) * 5U;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!write_reg_freqctrl(cc2520, FREQCTRL_FREQ(channel))) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Failed");
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
return 0;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:53:29 +01:00
|
|
|
static int cc2520_filter(struct device *dev,
|
|
|
|
bool set,
|
|
|
|
enum ieee802154_filter_type type,
|
|
|
|
const struct ieee802154_filter *filter)
|
2017-09-05 14:09:15 +02:00
|
|
|
{
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("Applying filter %u", type);
|
2017-09-05 14:09:15 +02:00
|
|
|
|
2018-03-19 09:53:29 +01:00
|
|
|
if (!set) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2017-09-05 14:09:15 +02:00
|
|
|
if (type == IEEE802154_FILTER_TYPE_IEEE_ADDR) {
|
2019-03-12 22:15:42 +01:00
|
|
|
return cc2520_set_ieee_addr(dev, filter->ieee_addr);
|
2017-09-05 14:09:15 +02:00
|
|
|
} else if (type == IEEE802154_FILTER_TYPE_SHORT_ADDR) {
|
2019-03-12 22:15:42 +01:00
|
|
|
return cc2520_set_short_addr(dev, filter->short_addr);
|
2017-09-05 14:09:15 +02:00
|
|
|
} else if (type == IEEE802154_FILTER_TYPE_PAN_ID) {
|
2019-03-12 22:15:42 +01:00
|
|
|
return cc2520_set_pan_id(dev, filter->pan_id);
|
2017-09-05 14:09:15 +02:00
|
|
|
}
|
|
|
|
|
2018-03-19 09:53:29 +01:00
|
|
|
return -ENOTSUP;
|
2017-09-05 14:09:15 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static int cc2520_set_txpower(struct device *dev, int16_t dbm)
|
2016-06-15 10:46:10 +02:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t pwr;
|
2016-06-15 10:46:10 +02:00
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("%d", dbm);
|
2016-06-15 10:46:10 +02:00
|
|
|
|
|
|
|
/* See chapter 19 part 8 */
|
|
|
|
switch (dbm) {
|
|
|
|
case 5:
|
|
|
|
pwr = 0xF7;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
pwr = 0xF2;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
pwr = 0xAB;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
pwr = 0x13;
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
pwr = 0x32;
|
|
|
|
break;
|
|
|
|
case -2:
|
|
|
|
pwr = 0x81;
|
|
|
|
break;
|
|
|
|
case -4:
|
|
|
|
pwr = 0x88;
|
|
|
|
break;
|
|
|
|
case -7:
|
|
|
|
pwr = 0x2C;
|
|
|
|
break;
|
|
|
|
case -18:
|
|
|
|
pwr = 0x03;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!write_reg_txpower(cc2520, pwr)) {
|
2016-06-15 10:46:10 +02:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
error:
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Failed");
|
2016-06-15 10:46:10 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
net/ieee802154: Modify radio TX function signature
The cause for this change is TCP. Until now, the radio strategy driver
(ALOHA or CSMA) was providing the actual nbuf, and not the buffer
fragment, counting on the fact that the loop was using
net_buf_frag_del() which made so, iteration after iteration, buffer
framgent to be always buf->frags. The problem with this logic is loosing
the fragments that might be still referenced by TCP, in case the whole
buffer did not make it so TCP can retry later and so on.
Instead, TX now takes the nbuf and the actual frag to send. It could
have been working with just a pointer on the data, and the whole length
of the frame. But it has been avoided due to possible future devices,
that will be smarter and run CSMA directly in the hw, thus it will
require to access the whole buffer list through the nbuf.
Change-Id: I8d77b1e13b648c0ec3645cb2d55d1910d00381ea
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2017-01-26 14:31:30 +01:00
|
|
|
static int cc2520_tx(struct device *dev,
|
net: ieee802154_radio: Allow to specify TX mode
Even though radio driver can report in its capabilities that it does
support CSMA CA, there's no way in the driver to select how the frame
should be transmitted (with CSMA or without). As layers above radio
driver (Thread, Zigbee) can expect that both TX modes are available, we
need to extend the API to allow either of these modes.
This commits extends the API `tx` function with an extra parameter,
`ieee802154_tx_mode`, which informs the driver how the packet should be
transmitted. Currently, the following modes are specified:
* direct (regular tx, no cca, just how it worked so far),
* CCA before transmission,
* CSMA CA before transmission,
* delayed TX,
* delayed TX with CCA
Assume that radios that reported CSMA CA capability transmit in CSMA CA
mode by default, all others will support direct mode.
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2020-02-28 13:57:49 +01:00
|
|
|
enum ieee802154_tx_mode mode,
|
2017-04-05 08:37:44 +02:00
|
|
|
struct net_pkt *pkt,
|
net/ieee802154: Modify radio TX function signature
The cause for this change is TCP. Until now, the radio strategy driver
(ALOHA or CSMA) was providing the actual nbuf, and not the buffer
fragment, counting on the fact that the loop was using
net_buf_frag_del() which made so, iteration after iteration, buffer
framgent to be always buf->frags. The problem with this logic is loosing
the fragments that might be still referenced by TCP, in case the whole
buffer did not make it so TCP can retry later and so on.
Instead, TX now takes the nbuf and the actual frag to send. It could
have been working with just a pointer on the data, and the whole length
of the frame. But it has been avoided due to possible future devices,
that will be smarter and run CSMA directly in the hw, thus it will
require to access the whole buffer list through the nbuf.
Change-Id: I8d77b1e13b648c0ec3645cb2d55d1910d00381ea
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2017-01-26 14:31:30 +01:00
|
|
|
struct net_buf *frag)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *frame = frag->data;
|
|
|
|
uint8_t len = frag->len;
|
2016-03-18 13:08:40 +01:00
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t retry = 2U;
|
2016-03-18 13:08:40 +01:00
|
|
|
bool status;
|
|
|
|
|
net: ieee802154_radio: Allow to specify TX mode
Even though radio driver can report in its capabilities that it does
support CSMA CA, there's no way in the driver to select how the frame
should be transmitted (with CSMA or without). As layers above radio
driver (Thread, Zigbee) can expect that both TX modes are available, we
need to extend the API to allow either of these modes.
This commits extends the API `tx` function with an extra parameter,
`ieee802154_tx_mode`, which informs the driver how the packet should be
transmitted. Currently, the following modes are specified:
* direct (regular tx, no cca, just how it worked so far),
* CCA before transmission,
* CSMA CA before transmission,
* delayed TX,
* delayed TX with CCA
Assume that radios that reported CSMA CA capability transmit in CSMA CA
mode by default, all others will support direct mode.
Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2020-02-28 13:57:49 +01:00
|
|
|
if (mode != IEEE802154_TX_MODE_DIRECT) {
|
|
|
|
NET_ERR("TX mode %d not supported", mode);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("%p (%u)", frag, len);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!write_reg_excflag0(cc2520, EXCFLAG0_RESET_TX_FLAGS) ||
|
|
|
|
!write_txfifo_length(cc2520, len) ||
|
|
|
|
!write_txfifo_content(cc2520, frame, len)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Cannot feed in TX fifo");
|
2016-03-18 13:08:40 +01:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
net/ieee802154: Modify radio TX function signature
The cause for this change is TCP. Until now, the radio strategy driver
(ALOHA or CSMA) was providing the actual nbuf, and not the buffer
fragment, counting on the fact that the loop was using
net_buf_frag_del() which made so, iteration after iteration, buffer
framgent to be always buf->frags. The problem with this logic is loosing
the fragments that might be still referenced by TCP, in case the whole
buffer did not make it so TCP can retry later and so on.
Instead, TX now takes the nbuf and the actual frag to send. It could
have been working with just a pointer on the data, and the whole length
of the frame. But it has been avoided due to possible future devices,
that will be smarter and run CSMA directly in the hw, thus it will
require to access the whole buffer list through the nbuf.
Change-Id: I8d77b1e13b648c0ec3645cb2d55d1910d00381ea
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2017-01-26 14:31:30 +01:00
|
|
|
if (!verify_txfifo_status(cc2520, len)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Did not write properly into TX FIFO");
|
2016-03-18 13:08:40 +01:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-02-22 08:37:51 +01:00
|
|
|
#ifdef CONFIG_IEEE802154_CC2520_CRYPTO
|
|
|
|
k_sem_take(&cc2520->access_lock, K_FOREVER);
|
|
|
|
#endif
|
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
/* 1 retry is allowed here */
|
|
|
|
do {
|
|
|
|
atomic_set(&cc2520->tx, 1);
|
2016-11-09 16:53:16 +01:00
|
|
|
k_sem_init(&cc2520->tx_sync, 0, UINT_MAX);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!instruct_stxoncca(cc2520)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Cannot start transmission");
|
2016-03-18 13:08:40 +01:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2019-10-03 02:26:14 +02:00
|
|
|
k_sem_take(&cc2520->tx_sync, K_MSEC(10));
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
retry--;
|
|
|
|
status = verify_tx_done(cc2520);
|
|
|
|
} while (!status && retry);
|
|
|
|
|
2017-02-22 08:37:51 +01:00
|
|
|
#ifdef CONFIG_IEEE802154_CC2520_CRYPTO
|
|
|
|
k_sem_give(&cc2520->access_lock);
|
|
|
|
#endif
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2017-02-22 08:37:51 +01:00
|
|
|
if (status) {
|
|
|
|
return 0;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
2017-02-22 08:37:51 +01:00
|
|
|
#ifdef CONFIG_IEEE802154_CC2520_CRYPTO
|
|
|
|
k_sem_give(&cc2520->access_lock);
|
|
|
|
#endif
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("No TX_FRM_DONE");
|
2019-03-12 22:15:42 +01:00
|
|
|
cc2520_print_exceptions(cc2520);
|
|
|
|
cc2520_print_errors(cc2520);
|
2017-02-22 08:37:51 +01:00
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
atomic_set(&cc2520->tx, 0);
|
2017-09-29 09:33:25 +02:00
|
|
|
instruct_sflushtx(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2016-06-15 10:46:10 +02:00
|
|
|
static int cc2520_start(struct device *dev)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2016-06-15 10:41:36 +02:00
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!instruct_sxoscon(cc2520) ||
|
|
|
|
!instruct_srxon(cc2520) ||
|
2016-03-18 13:08:40 +01:00
|
|
|
!verify_osc_stabilization(cc2520)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Error starting CC2520");
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
flush_rxfifo(cc2520);
|
|
|
|
|
|
|
|
enable_fifop_interrupt(cc2520, true);
|
|
|
|
enable_sfd_interrupt(cc2520, true);
|
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
return 0;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2016-06-15 10:46:10 +02:00
|
|
|
static int cc2520_stop(struct device *dev)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
2016-06-15 10:41:36 +02:00
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2016-11-16 12:46:06 +01:00
|
|
|
flush_rxfifo(cc2520);
|
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
enable_fifop_interrupt(cc2520, false);
|
|
|
|
enable_sfd_interrupt(cc2520, false);
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!instruct_srfoff(cc2520) ||
|
|
|
|
!instruct_sxoscoff(cc2520)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Error stopping CC2520");
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
return 0;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************
|
|
|
|
* Initialization *
|
|
|
|
*****************/
|
|
|
|
static int power_on_and_setup(struct device *dev)
|
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
|
|
|
/* Switching to LPM2 mode */
|
|
|
|
set_reset(dev, 0);
|
2019-03-12 22:15:42 +01:00
|
|
|
z_usleep(150);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
set_vreg_en(dev, 0);
|
2019-03-12 22:15:42 +01:00
|
|
|
z_usleep(250);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
/* Then to ACTIVE mode */
|
|
|
|
set_vreg_en(dev, 1);
|
2019-03-12 22:15:42 +01:00
|
|
|
z_usleep(250);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
set_reset(dev, 1);
|
2019-03-12 22:15:42 +01:00
|
|
|
z_usleep(150);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
if (!verify_osc_stabilization(cc2520)) {
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Default settings to always write (see chapter 28 part 1) */
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!write_reg_txpower(cc2520, CC2520_TXPOWER_DEFAULT) ||
|
|
|
|
!write_reg_ccactrl0(cc2520, CC2520_CCACTRL0_DEFAULT) ||
|
|
|
|
!write_reg_mdmctrl0(cc2520, CC2520_MDMCTRL0_DEFAULT) ||
|
|
|
|
!write_reg_mdmctrl1(cc2520, CC2520_MDMCTRL1_DEFAULT) ||
|
|
|
|
!write_reg_rxctrl(cc2520, CC2520_RXCTRL_DEFAULT) ||
|
|
|
|
!write_reg_fsctrl(cc2520, CC2520_FSCTRL_DEFAULT) ||
|
|
|
|
!write_reg_fscal1(cc2520, CC2520_FSCAL1_DEFAULT) ||
|
|
|
|
!write_reg_agcctrl1(cc2520, CC2520_AGCCTRL1_DEFAULT) ||
|
|
|
|
!write_reg_adctest0(cc2520, CC2520_ADCTEST0_DEFAULT) ||
|
|
|
|
!write_reg_adctest1(cc2520, CC2520_ADCTEST1_DEFAULT) ||
|
|
|
|
!write_reg_adctest2(cc2520, CC2520_ADCTEST2_DEFAULT)) {
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EXTCLOCK0: Disabling external clock
|
|
|
|
* FRMCTRL0: AUTOACK and AUTOCRC enabled
|
|
|
|
* FRMCTRL1: SET_RXENMASK_ON_TX and IGNORE_TX_UNDERF
|
|
|
|
* FRMFILT0: Frame filtering (setting CC2520_FRAME_FILTERING)
|
|
|
|
* FIFOPCTRL: Set TX threshold (setting CC2520_TX_THRESHOLD)
|
|
|
|
*/
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!write_reg_extclock(cc2520, 0) ||
|
|
|
|
!write_reg_frmctrl0(cc2520, CC2520_AUTOMATISM) ||
|
|
|
|
!write_reg_frmctrl1(cc2520, FRMCTRL1_IGNORE_TX_UNDERF |
|
2016-03-18 13:08:40 +01:00
|
|
|
FRMCTRL1_SET_RXENMASK_ON_TX) ||
|
2017-09-29 09:33:25 +02:00
|
|
|
!write_reg_frmfilt0(cc2520, FRMFILT0_FRAME_FILTER_EN |
|
2016-03-18 13:08:40 +01:00
|
|
|
FRMFILT0_MAX_FRAME_VERSION(3)) ||
|
2017-09-29 09:33:25 +02:00
|
|
|
!write_reg_frmfilt1(cc2520, FRMFILT1_ACCEPT_ALL) ||
|
|
|
|
!write_reg_srcmatch(cc2520, SRCMATCH_DEFAULTS) ||
|
|
|
|
!write_reg_fifopctrl(cc2520,
|
2016-03-18 13:08:40 +01:00
|
|
|
FIFOPCTRL_FIFOP_THR(CC2520_TX_THRESHOLD))) {
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleaning up TX fifo */
|
2017-09-29 09:33:25 +02:00
|
|
|
instruct_sflushtx(cc2520);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
|
|
|
setup_gpio_callbacks(dev);
|
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
cc2520_print_gpio_config(dev);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
return 0;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2020-01-27 15:10:48 +01:00
|
|
|
static struct cc2520_gpio_configuration *configure_gpios(struct device *dev)
|
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
struct device *gpio;
|
|
|
|
|
|
|
|
/* VREG_EN */
|
2020-03-25 17:13:24 +01:00
|
|
|
gpio = device_get_binding(DT_INST_GPIO_LABEL(0, vreg_en_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
if (!gpio) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_VREG_EN].pin = DT_INST_GPIO_PIN(0, vreg_en_gpios);
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_configure(gpio, cc2520->gpios[CC2520_GPIO_IDX_VREG_EN].pin,
|
2020-03-25 17:13:24 +01:00
|
|
|
GPIO_OUTPUT_LOW | DT_INST_GPIO_FLAGS(0, vreg_en_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_VREG_EN].dev = gpio;
|
|
|
|
|
|
|
|
/* RESET */
|
2020-03-25 17:13:24 +01:00
|
|
|
gpio = device_get_binding(DT_INST_GPIO_LABEL(0, reset_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
if (!gpio) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_RESET].pin = DT_INST_GPIO_PIN(0, reset_gpios);
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_configure(gpio, cc2520->gpios[CC2520_GPIO_IDX_RESET].pin,
|
2020-03-25 17:13:24 +01:00
|
|
|
GPIO_OUTPUT_LOW | DT_INST_GPIO_FLAGS(0, reset_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_RESET].dev = gpio;
|
|
|
|
|
|
|
|
/*FIFO */
|
2020-03-25 17:13:24 +01:00
|
|
|
gpio = device_get_binding(DT_INST_GPIO_LABEL(0, fifo_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
if (!gpio) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFO].pin = DT_INST_GPIO_PIN(0, fifo_gpios);
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_configure(gpio, cc2520->gpios[CC2520_GPIO_IDX_FIFO].pin,
|
2020-03-25 17:13:24 +01:00
|
|
|
GPIO_INPUT | DT_INST_GPIO_FLAGS(0, fifo_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFO].dev = gpio;
|
|
|
|
|
|
|
|
/* CCA */
|
2020-03-25 17:13:24 +01:00
|
|
|
gpio = device_get_binding(DT_INST_GPIO_LABEL(0, cca_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
if (!gpio) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_CCA].pin = DT_INST_GPIO_PIN(0, cca_gpios);
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_configure(gpio, cc2520->gpios[CC2520_GPIO_IDX_CCA].pin,
|
2020-03-25 17:13:24 +01:00
|
|
|
GPIO_INPUT | DT_INST_GPIO_FLAGS(0, cca_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_CCA].dev = gpio;
|
|
|
|
|
|
|
|
/* SFD */
|
2020-03-25 17:13:24 +01:00
|
|
|
gpio = device_get_binding(DT_INST_GPIO_LABEL(0, sfd_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
if (!gpio) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_SFD].pin = DT_INST_GPIO_PIN(0, sfd_gpios);
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_configure(gpio, cc2520->gpios[CC2520_GPIO_IDX_SFD].pin,
|
2020-03-25 17:13:24 +01:00
|
|
|
GPIO_INPUT | DT_INST_GPIO_FLAGS(0, sfd_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_SFD].dev = gpio;
|
|
|
|
|
|
|
|
/* FIFOP */
|
2020-03-25 17:13:24 +01:00
|
|
|
gpio = device_get_binding(DT_INST_GPIO_LABEL(0, fifop_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
if (!gpio) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFOP].pin = DT_INST_GPIO_PIN(0, fifop_gpios);
|
2020-01-27 15:10:48 +01:00
|
|
|
gpio_pin_configure(gpio, cc2520->gpios[CC2520_GPIO_IDX_FIFOP].pin,
|
2020-03-25 17:13:24 +01:00
|
|
|
GPIO_INPUT | DT_INST_GPIO_FLAGS(0, sfd_gpios));
|
2020-01-27 15:10:48 +01:00
|
|
|
cc2520->gpios[CC2520_GPIO_IDX_FIFOP].dev = gpio;
|
|
|
|
|
|
|
|
return cc2520->gpios;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-18 13:08:40 +01:00
|
|
|
static inline int configure_spi(struct device *dev)
|
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->spi = device_get_binding(DT_INST_BUS_LABEL(0));
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!cc2520->spi) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Unable to get SPI device");
|
2016-11-23 10:48:08 +01:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2020-05-08 19:04:55 +02:00
|
|
|
#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
|
2017-09-29 09:33:25 +02:00
|
|
|
cs_ctrl.gpio_dev = device_get_binding(
|
2020-03-25 17:13:24 +01:00
|
|
|
DT_INST_SPI_DEV_CS_GPIOS_LABEL(0));
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!cs_ctrl.gpio_dev) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Unable to get GPIO SPI CS device");
|
2017-09-29 09:33:25 +02:00
|
|
|
return -ENODEV;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cs_ctrl.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(0);
|
2020-06-18 10:13:55 +02:00
|
|
|
cs_ctrl.gpio_dt_flags = DT_INST_SPI_DEV_CS_GPIOS_FLAGS(0);
|
2019-03-27 02:57:45 +01:00
|
|
|
cs_ctrl.delay = 0U;
|
2017-09-29 09:33:25 +02:00
|
|
|
|
|
|
|
cc2520->spi_cfg.cs = &cs_ctrl;
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("SPI GPIO CS configured on %s:%u",
|
2020-03-25 17:13:24 +01:00
|
|
|
DT_INST_SPI_DEV_CS_GPIOS_LABEL(0),
|
|
|
|
DT_INST_SPI_DEV_CS_GPIOS_PIN(0));
|
2020-05-08 19:04:55 +02:00
|
|
|
#endif
|
2017-09-29 09:33:25 +02:00
|
|
|
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->spi_cfg.frequency = DT_INST_PROP(0, spi_max_frequency);
|
2017-09-29 09:33:25 +02:00
|
|
|
cc2520->spi_cfg.operation = SPI_WORD_SET(8);
|
2020-03-25 17:13:24 +01:00
|
|
|
cc2520->spi_cfg.slave = DT_INST_REG_ADDR(0);
|
2017-09-29 09:33:25 +02:00
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
return 0;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2016-10-26 06:54:53 +02:00
|
|
|
static int cc2520_init(struct device *dev)
|
2016-03-18 13:08:40 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
|
|
|
|
|
|
|
atomic_set(&cc2520->tx, 0);
|
2016-11-09 16:53:16 +01:00
|
|
|
k_sem_init(&cc2520->rx_lock, 0, UINT_MAX);
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2017-02-22 08:37:51 +01:00
|
|
|
#ifdef CONFIG_IEEE802154_CC2520_CRYPTO
|
|
|
|
k_sem_init(&cc2520->access_lock, 1, 1);
|
|
|
|
#endif
|
|
|
|
|
2020-01-27 15:10:48 +01:00
|
|
|
if (!configure_gpios(dev)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Configuring GPIOS failed");
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
if (configure_spi(dev) != 0) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Configuring SPI failed");
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("GPIO and SPI configured");
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
if (power_on_and_setup(dev) != 0) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Configuring CC2520 failed");
|
2016-04-26 16:43:02 +02:00
|
|
|
return -EIO;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2017-05-09 21:15:00 +02:00
|
|
|
k_thread_create(&cc2520->cc2520_rx_thread, cc2520->cc2520_rx_stack,
|
|
|
|
CONFIG_IEEE802154_CC2520_RX_STACK_SIZE,
|
|
|
|
(k_thread_entry_t)cc2520_rx,
|
2019-09-19 14:16:34 +02:00
|
|
|
dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT);
|
2020-03-12 22:18:42 +01:00
|
|
|
k_thread_name_set(&cc2520->cc2520_rx_thread, "cc2520_rx");
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_INF("CC2520 initialized");
|
2016-12-02 10:49:34 +01:00
|
|
|
|
2016-04-26 16:43:02 +02:00
|
|
|
return 0;
|
2016-03-18 13:08:40 +01:00
|
|
|
}
|
|
|
|
|
2016-06-15 10:46:10 +02:00
|
|
|
static void cc2520_iface_init(struct net_if *iface)
|
|
|
|
{
|
|
|
|
struct device *dev = net_if_get_device(iface);
|
|
|
|
struct cc2520_context *cc2520 = dev->driver_data;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *mac = get_mac(dev);
|
2016-06-15 10:46:10 +02:00
|
|
|
|
2017-02-15 12:20:31 +01:00
|
|
|
net_if_set_link_addr(iface, mac, 8, NET_LINK_IEEE802154);
|
2016-06-15 10:46:10 +02:00
|
|
|
|
|
|
|
cc2520->iface = iface;
|
|
|
|
|
|
|
|
ieee802154_init(iface);
|
|
|
|
}
|
|
|
|
|
2016-10-26 06:54:53 +02:00
|
|
|
static struct cc2520_context cc2520_context_data;
|
2016-03-18 13:08:40 +01:00
|
|
|
|
2016-06-15 10:46:10 +02:00
|
|
|
static struct ieee802154_radio_api cc2520_radio_api = {
|
|
|
|
.iface_api.init = cc2520_iface_init,
|
|
|
|
|
2017-09-04 15:24:36 +02:00
|
|
|
.get_capabilities = cc2520_get_capabilities,
|
|
|
|
.cca = cc2520_cca,
|
|
|
|
.set_channel = cc2520_set_channel,
|
2018-03-19 09:53:29 +01:00
|
|
|
.filter = cc2520_filter,
|
2017-09-04 15:24:36 +02:00
|
|
|
.set_txpower = cc2520_set_txpower,
|
|
|
|
.start = cc2520_start,
|
|
|
|
.stop = cc2520_stop,
|
|
|
|
.tx = cc2520_tx,
|
2016-06-15 10:46:10 +02:00
|
|
|
};
|
|
|
|
|
2017-11-16 11:11:51 +01:00
|
|
|
#if defined(CONFIG_IEEE802154_RAW_MODE)
|
2017-02-06 11:49:16 +01:00
|
|
|
DEVICE_AND_API_INIT(cc2520, CONFIG_IEEE802154_CC2520_DRV_NAME,
|
2016-09-26 11:51:58 +02:00
|
|
|
cc2520_init, &cc2520_context_data, NULL,
|
2017-02-06 11:49:16 +01:00
|
|
|
POST_KERNEL, CONFIG_IEEE802154_CC2520_INIT_PRIO,
|
2016-09-26 11:51:58 +02:00
|
|
|
&cc2520_radio_api);
|
|
|
|
#else
|
2017-02-06 11:49:16 +01:00
|
|
|
NET_DEVICE_INIT(cc2520, CONFIG_IEEE802154_CC2520_DRV_NAME,
|
2020-02-25 10:45:25 +01:00
|
|
|
cc2520_init, device_pm_control_nop,
|
|
|
|
&cc2520_context_data, NULL,
|
2017-02-06 11:49:16 +01:00
|
|
|
CONFIG_IEEE802154_CC2520_INIT_PRIO,
|
2016-06-15 10:46:10 +02:00
|
|
|
&cc2520_radio_api, IEEE802154_L2,
|
2016-11-16 11:48:40 +01:00
|
|
|
NET_L2_GET_CTX_TYPE(IEEE802154_L2), 125);
|
2016-09-26 11:51:58 +02:00
|
|
|
#endif
|
2017-02-22 08:37:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_IEEE802154_CC2520_CRYPTO
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline bool cc2520_read_ram(struct cc2520_context *ctx, uint16_t addr,
|
|
|
|
uint8_t *data_buf, uint8_t len)
|
2017-02-22 08:37:51 +01:00
|
|
|
{
|
2019-03-12 22:15:42 +01:00
|
|
|
return z_cc2520_access(ctx, true, CC2520_INS_MEMRD,
|
2017-09-29 09:33:25 +02:00
|
|
|
addr, data_buf, len);
|
2017-02-22 08:37:51 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline bool cc2520_write_ram(struct cc2520_context *ctx, uint16_t addr,
|
|
|
|
uint8_t *data_buf, uint8_t len)
|
2017-02-22 08:37:51 +01:00
|
|
|
{
|
2019-03-12 22:15:42 +01:00
|
|
|
return z_cc2520_access(ctx, false, CC2520_INS_MEMWR,
|
2017-09-29 09:33:25 +02:00
|
|
|
addr, data_buf, len);
|
2017-02-22 08:37:51 +01:00
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
static inline bool instruct_uccm_ccm(struct cc2520_context *cc2520,
|
|
|
|
bool uccm,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t key_addr,
|
|
|
|
uint8_t auth_crypt,
|
|
|
|
uint8_t nonce_addr,
|
|
|
|
uint16_t input_addr,
|
|
|
|
uint16_t output_addr,
|
|
|
|
uint8_t in_len,
|
|
|
|
uint8_t m)
|
2017-02-22 08:37:51 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t cmd[9];
|
2017-09-29 09:33:25 +02:00
|
|
|
const struct spi_buf buf[1] = {
|
|
|
|
{
|
|
|
|
.buf = cmd,
|
|
|
|
.len = 9,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const struct spi_buf_set tx = {
|
|
|
|
.buffers = buf,
|
|
|
|
.count = 1
|
|
|
|
};
|
|
|
|
|
2017-02-22 08:37:51 +01:00
|
|
|
int ret;
|
|
|
|
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_DBG("%sCCM(P={01} K={%02x} C={%02x} N={%02x}"
|
2017-02-22 08:37:51 +01:00
|
|
|
" A={%03x} E={%03x} F{%02x} M={%02x})",
|
2017-09-29 09:33:25 +02:00
|
|
|
uccm ? "U" : "", key_addr, auth_crypt, nonce_addr,
|
2017-02-22 08:37:51 +01:00
|
|
|
input_addr, output_addr, in_len, m);
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
cmd[0] = uccm ? CC2520_INS_UCCM | 1 : CC2520_INS_CCM | 1;
|
2017-02-22 08:37:51 +01:00
|
|
|
cmd[1] = key_addr;
|
|
|
|
cmd[2] = (auth_crypt & 0x7f);
|
|
|
|
cmd[3] = nonce_addr;
|
2020-05-27 18:26:57 +02:00
|
|
|
cmd[4] = (uint8_t)(((input_addr & 0x0f00) >> 4) |
|
2017-02-22 08:37:51 +01:00
|
|
|
((output_addr & 0x0f00) >> 8));
|
2020-05-27 18:26:57 +02:00
|
|
|
cmd[5] = (uint8_t)(input_addr & 0x00ff);
|
|
|
|
cmd[6] = (uint8_t)(output_addr & 0x00ff);
|
2017-02-22 08:37:51 +01:00
|
|
|
cmd[7] = (in_len & 0x7f);
|
|
|
|
cmd[8] = (m & 0x03);
|
|
|
|
|
|
|
|
k_sem_take(&cc2520->access_lock, K_FOREVER);
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
ret = spi_write(cc2520->spi, &cc2520->spi_cfg, &tx);
|
2017-02-22 08:37:51 +01:00
|
|
|
|
|
|
|
k_sem_give(&cc2520->access_lock);
|
|
|
|
|
|
|
|
if (ret) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("%sCCM Failed", uccm ? "U" : "");
|
2017-02-22 08:37:51 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static inline void generate_nonce(uint8_t *ccm_nonce, uint8_t *nonce,
|
|
|
|
struct cipher_aead_pkt *apkt, uint8_t m)
|
2017-02-22 08:37:51 +01:00
|
|
|
{
|
|
|
|
nonce[0] = 0 | (apkt->ad_len ? 0x40 : 0) | (m << 3) | 1;
|
|
|
|
|
|
|
|
memcpy(&nonce[1], ccm_nonce, 13);
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
nonce[14] = (uint8_t)(apkt->pkt->in_len >> 8);
|
|
|
|
nonce[15] = (uint8_t)(apkt->pkt->in_len);
|
2017-02-22 08:37:51 +01:00
|
|
|
|
|
|
|
/* See section 26.8.1 */
|
|
|
|
sys_mem_swap(nonce, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int insert_crypto_parameters(struct cipher_ctx *ctx,
|
|
|
|
struct cipher_aead_pkt *apkt,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *ccm_nonce, uint8_t *auth_crypt)
|
2017-02-22 08:37:51 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = ctx->device->driver_data;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t data[128];
|
|
|
|
uint8_t *in_buf;
|
|
|
|
uint8_t in_len;
|
|
|
|
uint8_t m = 0U;
|
2017-02-22 08:37:51 +01:00
|
|
|
|
|
|
|
if (!apkt->pkt->out_buf || !apkt->pkt->out_buf_max) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Out buffer needs to be set");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ctx->key.bit_stream || !ctx->keylen) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("No key installed");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ctx->flags & CAP_INPLACE_OPS)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("It supports only in-place operation");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!apkt->ad || !apkt->ad_len) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("CCM needs associated data");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (apkt->pkt->in_buf && apkt->pkt->in_buf - apkt->ad_len != apkt->ad) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("In-place needs ad and input in same memory");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!apkt->pkt->in_buf) {
|
|
|
|
if (!ctx->mode_params.ccm_info.tag_len) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Auth only needs a tag length");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
in_buf = apkt->ad;
|
|
|
|
in_len = apkt->ad_len;
|
|
|
|
|
2018-11-29 20:12:22 +01:00
|
|
|
*auth_crypt = 0U;
|
2017-02-22 08:37:51 +01:00
|
|
|
} else {
|
|
|
|
in_buf = data;
|
|
|
|
|
|
|
|
memcpy(in_buf, apkt->ad, apkt->ad_len);
|
|
|
|
memcpy(in_buf + apkt->ad_len,
|
|
|
|
apkt->pkt->in_buf, apkt->pkt->in_len);
|
|
|
|
in_len = apkt->ad_len + apkt->pkt->in_len;
|
|
|
|
|
|
|
|
*auth_crypt = !apkt->tag ? apkt->pkt->in_len :
|
|
|
|
apkt->pkt->in_len - ctx->mode_params.ccm_info.tag_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->mode_params.ccm_info.tag_len) {
|
|
|
|
if ((ctx->mode_params.ccm_info.tag_len >> 2) > 3) {
|
2018-11-29 20:12:22 +01:00
|
|
|
m = 3U;
|
2017-02-22 08:37:51 +01:00
|
|
|
} else {
|
|
|
|
m = ctx->mode_params.ccm_info.tag_len >> 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Writing the frame in RAM */
|
2019-03-12 22:15:42 +01:00
|
|
|
if (!cc2520_write_ram(cc2520, CC2520_MEM_DATA, in_buf, in_len)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Cannot write the frame in RAM");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See section 26.8.1 */
|
|
|
|
sys_memcpy_swap(data, ctx->key.bit_stream, ctx->keylen);
|
|
|
|
|
|
|
|
/* Writing the key in RAM */
|
2019-03-12 22:15:42 +01:00
|
|
|
if (!cc2520_write_ram(cc2520, CC2520_MEM_KEY, data, 16)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Cannot write the key in RAM");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
generate_nonce(ccm_nonce, data, apkt, m);
|
|
|
|
|
|
|
|
/* Writing the nonce in RAM */
|
2019-03-12 22:15:42 +01:00
|
|
|
if (!cc2520_write_ram(cc2520, CC2520_MEM_NONCE, data, 16)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Cannot write the nonce in RAM");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
static int cc2520_crypto_ccm(struct cipher_ctx *ctx,
|
2017-02-22 08:37:51 +01:00
|
|
|
struct cipher_aead_pkt *apkt,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *ccm_nonce)
|
2017-02-22 08:37:51 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = ctx->device->driver_data;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t auth_crypt;
|
2017-02-22 08:37:51 +01:00
|
|
|
int m;
|
|
|
|
|
|
|
|
if (!apkt || !apkt->pkt) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Invalid crypto packet to operate with");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = insert_crypto_parameters(ctx, apkt, ccm_nonce, &auth_crypt);
|
|
|
|
if (m < 0) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Inserting crypto parameters failed");
|
2017-02-22 08:37:51 +01:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
apkt->pkt->out_len = apkt->pkt->in_len + apkt->ad_len +
|
|
|
|
(m ? ctx->mode_params.ccm_info.tag_len : 0);
|
|
|
|
|
|
|
|
if (apkt->pkt->out_len > apkt->pkt->out_buf_max) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Result will not fit into out buffer %u vs %u",
|
2017-02-22 08:37:51 +01:00
|
|
|
apkt->pkt->out_len, apkt->pkt->out_buf_max);
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!instruct_uccm_ccm(cc2520, false, CC2520_MEM_KEY >> 4, auth_crypt,
|
|
|
|
CC2520_MEM_NONCE >> 4, CC2520_MEM_DATA,
|
|
|
|
0x000, apkt->ad_len, m) ||
|
2019-03-12 22:15:42 +01:00
|
|
|
!cc2520_read_ram(cc2520, CC2520_MEM_DATA,
|
2017-02-22 08:37:51 +01:00
|
|
|
apkt->pkt->out_buf, apkt->pkt->out_len)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("CCM or reading result from RAM failed");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2019-04-02 22:49:06 +02:00
|
|
|
if (apkt->tag) {
|
|
|
|
memcpy(apkt->tag, apkt->pkt->out_buf + apkt->pkt->in_len,
|
|
|
|
ctx->mode_params.ccm_info.tag_len);
|
|
|
|
}
|
2017-02-22 08:37:51 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-12 22:15:42 +01:00
|
|
|
static int cc2520_crypto_uccm(struct cipher_ctx *ctx,
|
2017-02-22 08:37:51 +01:00
|
|
|
struct cipher_aead_pkt *apkt,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *ccm_nonce)
|
2017-02-22 08:37:51 +01:00
|
|
|
{
|
|
|
|
struct cc2520_context *cc2520 = ctx->device->driver_data;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t auth_crypt;
|
2017-02-22 08:37:51 +01:00
|
|
|
int m;
|
|
|
|
|
|
|
|
if (!apkt || !apkt->pkt) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Invalid crypto packet to operate with");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->mode_params.ccm_info.tag_len && !apkt->tag) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("In case of MIC you need to provide a tag");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = insert_crypto_parameters(ctx, apkt, ccm_nonce, &auth_crypt);
|
|
|
|
if (m < 0) {
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
apkt->pkt->out_len = apkt->pkt->in_len + apkt->ad_len;
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (!instruct_uccm_ccm(cc2520, true, CC2520_MEM_KEY >> 4, auth_crypt,
|
|
|
|
CC2520_MEM_NONCE >> 4, CC2520_MEM_DATA,
|
|
|
|
0x000, apkt->ad_len, m) ||
|
2019-03-12 22:15:42 +01:00
|
|
|
!cc2520_read_ram(cc2520, CC2520_MEM_DATA,
|
2017-02-22 08:37:51 +01:00
|
|
|
apkt->pkt->out_buf, apkt->pkt->out_len)) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("UCCM or reading result from RAM failed");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:33:25 +02:00
|
|
|
if (m && (!(read_reg_dpustat(cc2520) & DPUSTAT_AUTHSTAT_H))) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Authentication of the frame failed");
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cc2520_crypto_hw_caps(struct device *dev)
|
|
|
|
{
|
|
|
|
return CAP_RAW_KEY | CAP_INPLACE_OPS | CAP_SYNC_OPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cc2520_crypto_begin_session(struct device *dev,
|
|
|
|
struct cipher_ctx *ctx,
|
|
|
|
enum cipher_algo algo,
|
|
|
|
enum cipher_mode mode,
|
|
|
|
enum cipher_op op_type)
|
|
|
|
{
|
|
|
|
if (algo != CRYPTO_CIPHER_ALGO_AES || mode != CRYPTO_CIPHER_MODE_CCM) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Wrong algo (%u) or mode (%u)", algo, mode);
|
2017-02-22 08:37:51 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-03-27 02:57:45 +01:00
|
|
|
if (ctx->mode_params.ccm_info.nonce_len != 13U) {
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_ERR("Nonce length erroneous (%u)",
|
2017-02-22 08:37:51 +01:00
|
|
|
ctx->mode_params.ccm_info.nonce_len);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (op_type == CRYPTO_CIPHER_OP_ENCRYPT) {
|
2019-03-12 22:15:42 +01:00
|
|
|
ctx->ops.ccm_crypt_hndlr = cc2520_crypto_ccm;
|
2017-02-22 08:37:51 +01:00
|
|
|
} else {
|
2019-03-12 22:15:42 +01:00
|
|
|
ctx->ops.ccm_crypt_hndlr = cc2520_crypto_uccm;
|
2017-02-22 08:37:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx->ops.cipher_mode = mode;
|
|
|
|
ctx->device = dev;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cc2520_crypto_free_session(struct device *dev,
|
|
|
|
struct cipher_ctx *ctx)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
|
|
|
|
ctx->ops.ccm_crypt_hndlr = NULL;
|
|
|
|
ctx->device = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cc2520_crypto_init(struct device *dev)
|
|
|
|
{
|
2018-09-03 16:28:47 +02:00
|
|
|
LOG_INF("CC2520 crypto part initialized");
|
2017-02-22 08:37:51 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct crypto_driver_api cc2520_crypto_api = {
|
|
|
|
.query_hw_caps = cc2520_crypto_hw_caps,
|
|
|
|
.begin_session = cc2520_crypto_begin_session,
|
|
|
|
.free_session = cc2520_crypto_free_session,
|
|
|
|
.crypto_async_callback_set = NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
DEVICE_AND_API_INIT(cc2520_crypto, CONFIG_IEEE802154_CC2520_CRYPTO_DRV_NAME,
|
|
|
|
cc2520_crypto_init, &cc2520_context_data, NULL,
|
|
|
|
POST_KERNEL, CONFIG_IEEE802154_CC2520_CRYPTO_INIT_PRIO,
|
|
|
|
&cc2520_crypto_api);
|
|
|
|
|
|
|
|
#endif /* CONFIG_IEEE802154_CC2520_CRYPTO */
|