Skip to content

Commit 2a4b314

Browse files
maass-hamburgkartben
authored andcommitted
drivers: entropy: add maxq10xx
add maxq10xx entropy device. Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
1 parent 56f7dc4 commit 2a4b314

File tree

11 files changed

+376
-0
lines changed

11 files changed

+376
-0
lines changed

drivers/entropy/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ zephyr_library_sources_ifdef(CONFIG_ENTROPY_SILABS_SIWX91X entropy_silabs_siwx9
3737
zephyr_library_sources_ifdef(CONFIG_ENTROPY_PSA_CRYPTO_RNG entropy_psa_crypto.c)
3838
zephyr_library_sources_ifdef(CONFIG_ENTROPY_NPCX_DRBG entropy_npcx_drbg.c)
3939
zephyr_library_sources_ifdef(CONFIG_ENTROPY_MAX32_TRNG entropy_max32.c)
40+
zephyr_library_sources_ifdef(CONFIG_ENTROPY_MAXQ10XX_RNG entropy_maxq10xx.c)
4041
zephyr_library_sources_ifdef(CONFIG_ENTROPY_RENESAS_RA entropy_renesas_ra.c)
4142
zephyr_library_sources_ifdef(CONFIG_ENTROPY_SY1XX_TRNG entropy_sy1xx_trng.c)
4243

drivers/entropy/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ source "drivers/entropy/Kconfig.bt_hci"
4040
source "drivers/entropy/Kconfig.psa_crypto"
4141
source "drivers/entropy/Kconfig.npcx"
4242
source "drivers/entropy/Kconfig.max32"
43+
source "drivers/entropy/Kconfig.maxq10xx"
4344
source "drivers/entropy/Kconfig.renesas_ra"
4445
source "drivers/entropy/Kconfig.sy1xx"
4546

drivers/entropy/Kconfig.maxq10xx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2025 Vogl Electronic GmbH
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config ENTROPY_MAXQ10XX_RNG
5+
bool "MAXQ10xx entropy number generator driver"
6+
default y
7+
depends on DT_HAS_ADI_MAXQ10XX_TRNG_ENABLED
8+
select ENTROPY_HAS_DRIVER
9+
select SPI
10+
select MFD
11+
select CRC
12+
help
13+
This option enables the entropy number generator driver for the
14+
MAXQ10xx crypto chips.
15+
16+
# Don't use use the MAXQ10XX RNG as a random source since it can be quite slow.
17+
# Instead, use the software-implemented xoshiro PRNG.
18+
choice RNG_GENERATOR_CHOICE
19+
default XOSHIRO_RANDOM_GENERATOR if ENTROPY_MAXQ10XX_RNG
20+
endchoice

drivers/entropy/entropy_maxq10xx.c

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
* Copyright (c) 2025 Vogl Electronic GmbH
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT adi_maxq10xx_trng
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/device.h>
11+
#include <zephyr/drivers/spi.h>
12+
#include <zephyr/drivers/entropy.h>
13+
#include <zephyr/drivers/mfd/mfd_maxq10xx.h>
14+
#include <zephyr/sys/crc.h>
15+
#include <zephyr/sys/byteorder.h>
16+
17+
#include <zephyr/logging/log.h>
18+
LOG_MODULE_REGISTER(entropy_maxq10xx, CONFIG_ENTROPY_LOG_LEVEL);
19+
20+
#define MAXQ10XX_CMD_HEADER 0xAA
21+
#define MAXQ10XX_CMD_GET_RANDOM 0xC9
22+
#define MAXQ10XX_CMD_GET_RANDOM_INPUT_DATA 0x02
23+
#define MAXQ10XX_CMD_READ_READY 0x55
24+
25+
#define MAXQ10XX_CRC16_POLYNOMIAL 0xA001
26+
#define MAXQ10XX_CRC16_INITIAL_VALUE 0x0000
27+
28+
#define MAXQ10XX_WAIT_TIME K_MSEC(1)
29+
30+
struct entropy_maxq10xx_config {
31+
struct spi_dt_spec spi;
32+
const struct device *parent;
33+
};
34+
35+
static int entropy_maxq10xx_send_cmd(const struct device *dev, uint16_t length)
36+
{
37+
const struct entropy_maxq10xx_config *config = dev->config;
38+
39+
uint8_t buffer_tx[9];
40+
uint16_t crc;
41+
int ret;
42+
43+
buffer_tx[0] = MAXQ10XX_CMD_HEADER;
44+
buffer_tx[1] = 0x00;
45+
buffer_tx[2] = MAXQ10XX_CMD_GET_RANDOM;
46+
buffer_tx[3] = 0x00;
47+
buffer_tx[4] = MAXQ10XX_CMD_GET_RANDOM_INPUT_DATA;
48+
49+
sys_put_be16(length, &buffer_tx[5]);
50+
51+
crc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, MAXQ10XX_CRC16_INITIAL_VALUE, buffer_tx, 7);
52+
53+
sys_put_le16(crc, &buffer_tx[7]);
54+
55+
const struct spi_buf tx_buf[] = {{
56+
.buf = buffer_tx,
57+
.len = ARRAY_SIZE(buffer_tx),
58+
}};
59+
const struct spi_buf_set tx = {
60+
.buffers = tx_buf,
61+
.count = ARRAY_SIZE(tx_buf),
62+
};
63+
64+
LOG_HEXDUMP_DBG(buffer_tx, sizeof(buffer_tx), "TX buffer");
65+
66+
ret = spi_write_dt(&config->spi, &tx);
67+
68+
return ret;
69+
}
70+
71+
static int entropy_maxq10xx_wait(const struct device *dev)
72+
{
73+
const struct entropy_maxq10xx_config *config = dev->config;
74+
uint8_t buffer_rx[1];
75+
int ret;
76+
77+
const struct spi_buf rx_buf[] = {{
78+
.buf = buffer_rx,
79+
.len = ARRAY_SIZE(buffer_rx),
80+
}};
81+
const struct spi_buf_set rx = {
82+
.buffers = rx_buf,
83+
.count = ARRAY_SIZE(rx_buf),
84+
};
85+
86+
while (1) {
87+
ret = spi_read_dt(&config->spi, &rx);
88+
if ((ret < 0) || (buffer_rx[0] == MAXQ10XX_CMD_READ_READY)) {
89+
break;
90+
}
91+
92+
k_sleep(MAXQ10XX_WAIT_TIME);
93+
};
94+
95+
return ret;
96+
}
97+
98+
static int entropy_maxq10xx_read(const struct device *dev, uint8_t *buffer, uint16_t length)
99+
{
100+
const struct entropy_maxq10xx_config *config = dev->config;
101+
uint8_t execution_status[2];
102+
uint8_t length_data[2];
103+
uint8_t crc[2];
104+
uint16_t crc_calc;
105+
int ret;
106+
107+
const struct spi_buf rx_buf[] = {
108+
{
109+
.buf = execution_status,
110+
.len = ARRAY_SIZE(execution_status),
111+
},
112+
{
113+
.buf = length_data,
114+
.len = ARRAY_SIZE(length_data),
115+
}
116+
};
117+
const struct spi_buf_set rx = {
118+
.buffers = rx_buf,
119+
.count = ARRAY_SIZE(rx_buf),
120+
};
121+
122+
ret = spi_read_dt(&config->spi, &rx);
123+
if (ret < 0) {
124+
return ret;
125+
}
126+
127+
if (execution_status[0] != 0 || execution_status[1] != 0) {
128+
LOG_ERR("Execution status: 0x%02X 0x%02X", execution_status[0],
129+
execution_status[1]);
130+
return -EIO;
131+
}
132+
133+
if (length != sys_get_be16(length_data)) {
134+
LOG_ERR("Length mismatch: %d != %d", length, sys_get_be16(length_data));
135+
return -EIO;
136+
}
137+
138+
const struct spi_buf rx_data_buf[] = {
139+
{
140+
.buf = buffer,
141+
.len = length,
142+
},
143+
{
144+
.buf = crc,
145+
.len = sizeof(crc),
146+
}
147+
};
148+
149+
const struct spi_buf_set rx_data = {
150+
.buffers = rx_data_buf,
151+
.count = ARRAY_SIZE(rx_data_buf),
152+
};
153+
154+
ret = spi_read_dt(&config->spi, &rx_data);
155+
if (ret < 0) {
156+
return ret;
157+
}
158+
159+
uint8_t header_tx[1] = {MAXQ10XX_CMD_READ_READY};
160+
161+
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, MAXQ10XX_CRC16_INITIAL_VALUE, header_tx,
162+
sizeof(header_tx));
163+
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, execution_status,
164+
sizeof(execution_status));
165+
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, length_data,
166+
sizeof(length_data));
167+
crc_calc = crc16_reflect(MAXQ10XX_CRC16_POLYNOMIAL, crc_calc, buffer, length);
168+
169+
if (crc_calc != sys_get_le16(crc)) {
170+
LOG_ERR("CRC error: 0x%04X != 0x%04X", crc_calc, sys_get_le16(crc));
171+
return -EIO;
172+
}
173+
174+
return ret;
175+
}
176+
177+
static int entropy_maxq10xx_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t length)
178+
{
179+
const struct entropy_maxq10xx_config *config = dev->config;
180+
struct k_sem *sem_lock = mfd_maxq10xx_get_lock(config->parent);
181+
182+
int ret;
183+
184+
if (!spi_is_ready_dt(&config->spi)) {
185+
return -EAGAIN;
186+
}
187+
188+
k_sem_take(sem_lock, K_FOREVER);
189+
190+
ret = entropy_maxq10xx_send_cmd(dev, length);
191+
if (ret < 0) {
192+
LOG_ERR("Failed to send command: %d", ret);
193+
goto exit;
194+
}
195+
196+
ret = entropy_maxq10xx_wait(dev);
197+
if (ret < 0) {
198+
LOG_ERR("Failed to wait for ready: %d", ret);
199+
goto exit;
200+
}
201+
202+
ret = entropy_maxq10xx_read(dev, buffer, length);
203+
if (ret < 0) {
204+
LOG_ERR("Failed to read data: %d", ret);
205+
}
206+
exit:
207+
k_sem_give(sem_lock);
208+
return ret;
209+
}
210+
211+
static DEVICE_API(entropy, entropy_maxq10xx_api) = {
212+
.get_entropy = entropy_maxq10xx_get_entropy
213+
};
214+
215+
#define DEFINE_MAXQ10XX_ENTROPY(_num) \
216+
static const struct entropy_maxq10xx_config entropy_maxq10xx_config##_num = { \
217+
.spi = SPI_DT_SPEC_GET(DT_INST_PARENT(_num), SPI_WORD_SET(8), 0), \
218+
.parent = DEVICE_DT_GET(DT_INST_PARENT(_num)), \
219+
}; \
220+
DEVICE_DT_INST_DEFINE(_num, NULL, NULL, NULL, \
221+
&entropy_maxq10xx_config##_num, POST_KERNEL, \
222+
CONFIG_MFD_MAXQ10XX_INIT_PRIORITY, &entropy_maxq10xx_api);
223+
224+
DT_INST_FOREACH_STATUS_OKAY(DEFINE_MAXQ10XX_ENTROPY);

drivers/mfd/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_MFD_AD559X mfd_ad559x.c)
1414
zephyr_library_sources_ifdef(CONFIG_MFD_AD559X_BUS_I2C mfd_ad559x_i2c.c)
1515
zephyr_library_sources_ifdef(CONFIG_MFD_AD559X_BUS_SPI mfd_ad559x_spi.c)
1616
zephyr_library_sources_ifdef(CONFIG_MFD_MAX31790 mfd_max31790.c)
17+
zephyr_library_sources_ifdef(CONFIG_MFD_MAXQ10XX mfd_maxq10xx.c)
1718
zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c)
1819
zephyr_library_sources_ifdef(CONFIG_MFD_BD8LB600FS mfd_bd8lb600fs.c)
1920
zephyr_library_sources_ifdef(CONFIG_MFD_TLE9104 mfd_tle9104.c)

drivers/mfd/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ source "drivers/mfd/Kconfig.ds3231"
2727
source "drivers/mfd/Kconfig.max20335"
2828
source "drivers/mfd/Kconfig.max22017"
2929
source "drivers/mfd/Kconfig.max31790"
30+
source "drivers/mfd/Kconfig.maxq10xx"
3031
source "drivers/mfd/Kconfig.nct38xx"
3132
source "drivers/mfd/Kconfig.npm1300"
3233
source "drivers/mfd/Kconfig.npm2100"

drivers/mfd/Kconfig.maxq10xx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) 2025 Vogl Electronic GmbH
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config MFD_MAXQ10XX
5+
bool "MAXQ10xx mfd driver"
6+
default y
7+
depends on DT_HAS_ADI_MAXQ10XX_ENABLED
8+
# using select SPI at this point introduces a cyclic dependency
9+
depends on SPI
10+
help
11+
This option enables the mfd driver for the
12+
MAXQ10xx crypto chips.
13+
14+
if MFD_MAXQ10XX
15+
16+
config MFD_MAXQ10XX_INIT_PRIORITY
17+
int "MAXQ10xx init priority"
18+
default 51
19+
help
20+
Device driver initialization priority.
21+
Device is connected to SPI bus, it has to
22+
be initialized after SPI driver.
23+
24+
endif # MFD_MAXQ10XX

drivers/mfd/mfd_maxq10xx.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2025 Vogl Electronic GmbH
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT adi_maxq10xx
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/device.h>
11+
#include <zephyr/drivers/spi.h>
12+
#include <zephyr/drivers/mfd/mfd_maxq10xx.h>
13+
14+
#include <zephyr/logging/log.h>
15+
LOG_MODULE_REGISTER(mfd_maxq10xx, CONFIG_MFD_LOG_LEVEL);
16+
17+
struct mfd_maxq10xx_config {
18+
struct spi_dt_spec spi;
19+
};
20+
21+
struct mfd_maxq10xx_data {
22+
struct k_sem sem_lock;
23+
};
24+
25+
struct k_sem *mfd_maxq10xx_get_lock(const struct device *dev)
26+
{
27+
struct mfd_maxq10xx_data *data = dev->data;
28+
29+
return &data->sem_lock;
30+
}
31+
32+
static int mfd_maxq10xx_init(const struct device *dev)
33+
{
34+
const struct mfd_maxq10xx_config *config = dev->config;
35+
36+
if (!spi_is_ready_dt(&config->spi)) {
37+
return -ENODEV;
38+
}
39+
40+
return 0;
41+
}
42+
43+
BUILD_ASSERT(CONFIG_SPI_INIT_PRIORITY < CONFIG_MFD_MAXQ10XX_INIT_PRIORITY,
44+
"SPI driver must be initialized before maxq10xx mfd driver");
45+
46+
#define DEFINE_MAXQ10XX_MFD(_num) \
47+
static const struct mfd_maxq10xx_config mfd_maxq10xx_config##_num = { \
48+
.spi = SPI_DT_SPEC_INST_GET(_num, SPI_WORD_SET(8), 0), \
49+
}; \
50+
static struct mfd_maxq10xx_data mfd_maxq10xx_data##_num = { \
51+
.sem_lock = Z_SEM_INITIALIZER(mfd_maxq10xx_data##_num.sem_lock, 1, 1), \
52+
}; \
53+
DEVICE_DT_INST_DEFINE(_num, mfd_maxq10xx_init, NULL, &mfd_maxq10xx_data##_num, \
54+
&mfd_maxq10xx_config##_num, POST_KERNEL, \
55+
CONFIG_MFD_MAXQ10XX_INIT_PRIORITY, NULL);
56+
57+
DT_INST_FOREACH_STATUS_OKAY(DEFINE_MAXQ10XX_MFD);

dts/bindings/mfd/adi,maxq10xx.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2025 Vogl Electronic GmbH
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ADI MAXQ10XX
5+
6+
compatible: "adi,maxq10xx"
7+
8+
include: spi-device.yaml
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2024 Vogl Electronic GmbH
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ADI MAXQ10XX RNG
5+
6+
compatible: "adi,maxq10xx-trng"
7+
8+
include: base.yaml

0 commit comments

Comments
 (0)