You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
5.5 KiB
224 lines
5.5 KiB
/* |
|
* Copyright (c) 2025 Vogl Electronic GmbH |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#define DT_DRV_COMPAT adi_maxq10xx_trng |
|
|
|
#include <zephyr/kernel.h> |
|
#include <zephyr/device.h> |
|
#include <zephyr/drivers/spi.h> |
|
#include <zephyr/drivers/entropy.h> |
|
#include <zephyr/drivers/mfd/mfd_maxq10xx.h> |
|
#include <zephyr/sys/crc.h> |
|
#include <zephyr/sys/byteorder.h> |
|
|
|
#include <zephyr/logging/log.h> |
|
LOG_MODULE_REGISTER(entropy_maxq10xx, CONFIG_ENTROPY_LOG_LEVEL); |
|
|
|
#define MAXQ10XX_CMD_HEADER 0xAA |
|
#define MAXQ10XX_CMD_GET_RANDOM 0xC9 |
|
#define MAXQ10XX_CMD_GET_RANDOM_INPUT_DATA 0x02 |
|
#define MAXQ10XX_CMD_READ_READY 0x55 |
|
|
|
#define MAXQ10XX_CRC16_POLYNOMIAL 0xA001 |
|
#define MAXQ10XX_CRC16_INITIAL_VALUE 0x0000 |
|
|
|
#define MAXQ10XX_WAIT_TIME K_MSEC(1) |
|
|
|
struct entropy_maxq10xx_config { |
|
struct spi_dt_spec spi; |
|
const struct device *parent; |
|
}; |
|
|
|
static int entropy_maxq10xx_send_cmd(const struct device *dev, uint16_t length) |
|
{ |
|
const struct entropy_maxq10xx_config *config = dev->config; |
|
|
|
uint8_t buffer_tx[9]; |
|
uint16_t crc; |
|
int ret; |
|
|
|
buffer_tx[0] = MAXQ10XX_CMD_HEADER; |
|
buffer_tx[1] = 0x00; |
|
buffer_tx[2] = MAXQ10XX_CMD_GET_RANDOM; |
|
buffer_tx[3] = 0x00; |
|
buffer_tx[4] = MAXQ10XX_CMD_GET_RANDOM_INPUT_DATA; |
|
|
|
sys_put_be16(length, &buffer_tx[5]); |
|
|
|
crc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, MAXQ10XX_CRC16_INITIAL_VALUE, buffer_tx, 7); |
|
|
|
sys_put_le16(crc, &buffer_tx[7]); |
|
|
|
const struct spi_buf tx_buf[] = {{ |
|
.buf = buffer_tx, |
|
.len = ARRAY_SIZE(buffer_tx), |
|
}}; |
|
const struct spi_buf_set tx = { |
|
.buffers = tx_buf, |
|
.count = ARRAY_SIZE(tx_buf), |
|
}; |
|
|
|
LOG_HEXDUMP_DBG(buffer_tx, sizeof(buffer_tx), "TX buffer"); |
|
|
|
ret = spi_write_dt(&config->spi, &tx); |
|
|
|
return ret; |
|
} |
|
|
|
static int entropy_maxq10xx_wait(const struct device *dev) |
|
{ |
|
const struct entropy_maxq10xx_config *config = dev->config; |
|
uint8_t buffer_rx[1]; |
|
int ret; |
|
|
|
const struct spi_buf rx_buf[] = {{ |
|
.buf = buffer_rx, |
|
.len = ARRAY_SIZE(buffer_rx), |
|
}}; |
|
const struct spi_buf_set rx = { |
|
.buffers = rx_buf, |
|
.count = ARRAY_SIZE(rx_buf), |
|
}; |
|
|
|
while (1) { |
|
ret = spi_read_dt(&config->spi, &rx); |
|
if ((ret < 0) || (buffer_rx[0] == MAXQ10XX_CMD_READ_READY)) { |
|
break; |
|
} |
|
|
|
k_sleep(MAXQ10XX_WAIT_TIME); |
|
}; |
|
|
|
return ret; |
|
} |
|
|
|
static int entropy_maxq10xx_read(const struct device *dev, uint8_t *buffer, uint16_t length) |
|
{ |
|
const struct entropy_maxq10xx_config *config = dev->config; |
|
uint8_t execution_status[2]; |
|
uint8_t length_data[2]; |
|
uint8_t crc[2]; |
|
uint16_t crc_calc; |
|
int ret; |
|
|
|
const struct spi_buf rx_buf[] = { |
|
{ |
|
.buf = execution_status, |
|
.len = ARRAY_SIZE(execution_status), |
|
}, |
|
{ |
|
.buf = length_data, |
|
.len = ARRAY_SIZE(length_data), |
|
} |
|
}; |
|
const struct spi_buf_set rx = { |
|
.buffers = rx_buf, |
|
.count = ARRAY_SIZE(rx_buf), |
|
}; |
|
|
|
ret = spi_read_dt(&config->spi, &rx); |
|
if (ret < 0) { |
|
return ret; |
|
} |
|
|
|
if (execution_status[0] != 0 || execution_status[1] != 0) { |
|
LOG_ERR("Execution status: 0x%02X 0x%02X", execution_status[0], |
|
execution_status[1]); |
|
return -EIO; |
|
} |
|
|
|
if (length != sys_get_be16(length_data)) { |
|
LOG_ERR("Length mismatch: %d != %d", length, sys_get_be16(length_data)); |
|
return -EIO; |
|
} |
|
|
|
const struct spi_buf rx_data_buf[] = { |
|
{ |
|
.buf = buffer, |
|
.len = length, |
|
}, |
|
{ |
|
.buf = crc, |
|
.len = sizeof(crc), |
|
} |
|
}; |
|
|
|
const struct spi_buf_set rx_data = { |
|
.buffers = rx_data_buf, |
|
.count = ARRAY_SIZE(rx_data_buf), |
|
}; |
|
|
|
ret = spi_read_dt(&config->spi, &rx_data); |
|
if (ret < 0) { |
|
return ret; |
|
} |
|
|
|
uint8_t header_tx[1] = {MAXQ10XX_CMD_READ_READY}; |
|
|
|
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, MAXQ10XX_CRC16_INITIAL_VALUE, header_tx, |
|
sizeof(header_tx)); |
|
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, execution_status, |
|
sizeof(execution_status)); |
|
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, length_data, |
|
sizeof(length_data)); |
|
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, buffer, length); |
|
|
|
if (crc_calc != sys_get_le16(crc)) { |
|
LOG_ERR("CRC error: 0x%04X != 0x%04X", crc_calc, sys_get_le16(crc)); |
|
return -EIO; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
static int entropy_maxq10xx_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t length) |
|
{ |
|
const struct entropy_maxq10xx_config *config = dev->config; |
|
struct k_sem *sem_lock = mfd_maxq10xx_get_lock(config->parent); |
|
|
|
int ret; |
|
|
|
if (!spi_is_ready_dt(&config->spi)) { |
|
return -EAGAIN; |
|
} |
|
|
|
k_sem_take(sem_lock, K_FOREVER); |
|
|
|
ret = entropy_maxq10xx_send_cmd(dev, length); |
|
if (ret < 0) { |
|
LOG_ERR("Failed to send command: %d", ret); |
|
goto exit; |
|
} |
|
|
|
ret = entropy_maxq10xx_wait(dev); |
|
if (ret < 0) { |
|
LOG_ERR("Failed to wait for ready: %d", ret); |
|
goto exit; |
|
} |
|
|
|
ret = entropy_maxq10xx_read(dev, buffer, length); |
|
if (ret < 0) { |
|
LOG_ERR("Failed to read data: %d", ret); |
|
} |
|
exit: |
|
k_sem_give(sem_lock); |
|
return ret; |
|
} |
|
|
|
static DEVICE_API(entropy, entropy_maxq10xx_api) = { |
|
.get_entropy = entropy_maxq10xx_get_entropy |
|
}; |
|
|
|
#define DEFINE_MAXQ10XX_ENTROPY(_num) \ |
|
static const struct entropy_maxq10xx_config entropy_maxq10xx_config##_num = { \ |
|
.spi = SPI_DT_SPEC_GET(DT_INST_PARENT(_num), SPI_WORD_SET(8), 0), \ |
|
.parent = DEVICE_DT_GET(DT_INST_PARENT(_num)), \ |
|
}; \ |
|
DEVICE_DT_INST_DEFINE(_num, NULL, NULL, NULL, \ |
|
&entropy_maxq10xx_config##_num, POST_KERNEL, \ |
|
CONFIG_MFD_MAXQ10XX_INIT_PRIORITY, &entropy_maxq10xx_api); |
|
|
|
DT_INST_FOREACH_STATUS_OKAY(DEFINE_MAXQ10XX_ENTROPY);
|
|
|