drivers: sensor: Add driver for nRF temperature sensor accessed via nrfs
Add driver, together with the corresponding dts binding and node in the nRF54H20 SoC definiton, for the nRF temperature sensor that cannot be accessed directly but only through nRF Services (nrfs) layer. Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
This commit is contained in:
parent
13aa26eac2
commit
41786a6477
9 changed files with 369 additions and 22 deletions
|
@ -2,7 +2,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# zephyr-keep-sorted-start
|
||||
add_subdirectory(temp)
|
||||
add_subdirectory_ifdef(CONFIG_NPM1300_CHARGER npm1300_charger)
|
||||
add_subdirectory_ifdef(CONFIG_QDEC_NRFX qdec_nrfx)
|
||||
add_subdirectory_ifdef(CONFIG_TEMP_NRF5 nrf5)
|
||||
# zephyr-keep-sorted-stop
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
|
||||
# zephyr-keep-sorted-start
|
||||
source "drivers/sensor/nordic/npm1300_charger/Kconfig"
|
||||
source "drivers/sensor/nordic/nrf5/Kconfig"
|
||||
source "drivers/sensor/nordic/qdec_nrfx/Kconfig"
|
||||
source "drivers/sensor/nordic/temp/Kconfig"
|
||||
# zephyr-keep-sorted-stop
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
# nRF5 temperature sensor configuration options
|
||||
|
||||
# Copyright (c) 2016 ARM Ltd.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config TEMP_NRF5_FORCE_ALT
|
||||
bool
|
||||
depends on SOC_COMPATIBLE_NRF
|
||||
help
|
||||
This option can be enabled to force an alternative implementation
|
||||
of the temperature sensor driver.
|
||||
|
||||
config TEMP_NRF5
|
||||
bool "nRF5 Temperature Sensor"
|
||||
default y
|
||||
depends on DT_HAS_NORDIC_NRF_TEMP_ENABLED
|
||||
depends on HAS_HW_NRF_TEMP
|
||||
depends on MULTITHREADING || TEMP_NRF5_FORCE_ALT
|
||||
help
|
||||
Enable driver for nRF5 temperature sensor.
|
|
@ -3,4 +3,7 @@
|
|||
if(CONFIG_TEMP_NRF5 AND NOT CONFIG_TEMP_NRF5_FORCE_ALT)
|
||||
zephyr_library()
|
||||
zephyr_library_sources(temp_nrf5.c)
|
||||
elseif(CONFIG_TEMP_NRFS)
|
||||
zephyr_library()
|
||||
zephyr_library_sources(temp_nrfs.c)
|
||||
endif()
|
38
drivers/sensor/nordic/temp/Kconfig
Normal file
38
drivers/sensor/nordic/temp/Kconfig
Normal file
|
@ -0,0 +1,38 @@
|
|||
# nRF temperature sensor configuration options
|
||||
|
||||
# Copyright (c) 2016 ARM Ltd.
|
||||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config TEMP_NRF5_FORCE_ALT
|
||||
bool
|
||||
depends on SOC_COMPATIBLE_NRF
|
||||
help
|
||||
This option can be enabled to force an alternative implementation
|
||||
of the temperature sensor driver.
|
||||
|
||||
config TEMP_NRF5
|
||||
bool "nRF5 Temperature Sensor"
|
||||
default y
|
||||
depends on DT_HAS_NORDIC_NRF_TEMP_ENABLED
|
||||
depends on MULTITHREADING || TEMP_NRF5_FORCE_ALT
|
||||
help
|
||||
Enable driver for nRF5 temperature sensor.
|
||||
|
||||
config TEMP_NRFS
|
||||
bool "nRF Temperature Sensor accessed via nrfs"
|
||||
default y
|
||||
depends on DT_HAS_NORDIC_NRF_TEMP_NRFS_ENABLED
|
||||
depends on NRFS
|
||||
help
|
||||
Enable driver for nRF temperature sensor accessed through the nRF
|
||||
Services (nrfs) layer.
|
||||
|
||||
if TEMP_NRFS
|
||||
|
||||
module = TEMP_NRFS
|
||||
thread_priority = 10
|
||||
thread_stack_size = 1024
|
||||
source "drivers/sensor/Kconfig.trigger_template"
|
||||
|
||||
endif # TEMP_NRFS
|
312
drivers/sensor/nordic/temp/temp_nrfs.c
Normal file
312
drivers/sensor/nordic/temp/temp_nrfs.c
Normal file
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nordic_nrf_temp_nrfs
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
#include <nrfs_temp.h>
|
||||
|
||||
LOG_MODULE_REGISTER(temp_nrfs, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
struct temp_nrfs_data {
|
||||
struct k_sem measure_sem;
|
||||
struct k_mutex mutex;
|
||||
int32_t raw_temp;
|
||||
|
||||
#ifdef CONFIG_TEMP_NRFS_TRIGGER
|
||||
struct sensor_trigger trigger;
|
||||
sensor_trigger_handler_t handler;
|
||||
const struct device *dev;
|
||||
struct sensor_value sampling_freq;
|
||||
struct sensor_value up_threshold;
|
||||
struct sensor_value low_threshold;
|
||||
#endif
|
||||
#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
|
||||
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_TEMP_NRFS_THREAD_STACK_SIZE);
|
||||
struct k_thread thread;
|
||||
struct k_sem event_sem;
|
||||
#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
|
||||
struct k_work work;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TEMP_NRFS_TRIGGER
|
||||
|
||||
#define DEFAULT_SAMPLING_FREQ { 1, 0 }
|
||||
#define DEFAULT_UP_THRESHOLD { 25, 0 }
|
||||
#define DEFAULT_LOW_THRESHOLD { 0, 0 }
|
||||
|
||||
static void temp_nrfs_handle_event(const struct device *dev)
|
||||
{
|
||||
struct temp_nrfs_data *data = dev->data;
|
||||
struct sensor_trigger trigger;
|
||||
sensor_trigger_handler_t handler;
|
||||
|
||||
k_mutex_lock(&data->mutex, K_FOREVER);
|
||||
trigger = data->trigger;
|
||||
handler = data->handler;
|
||||
k_mutex_unlock(&data->mutex);
|
||||
|
||||
if (handler) {
|
||||
handler(dev, &trigger);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
|
||||
static void temp_nrfs_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
struct temp_nrfs_data *data = p1;
|
||||
|
||||
while (1) {
|
||||
k_sem_take(&data->event_sem, K_FOREVER);
|
||||
temp_nrfs_handle_event(data->dev);
|
||||
}
|
||||
}
|
||||
#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
|
||||
static void temp_nrfs_work_handler(struct k_work *work)
|
||||
{
|
||||
struct temp_nrfs_data *data =
|
||||
CONTAINER_OF(work, struct temp_nrfs_data, work);
|
||||
|
||||
temp_nrfs_handle_event(data->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint16_t to_measure_rate_ms(const struct sensor_value *freq_val)
|
||||
{
|
||||
uint32_t measure_rate_ms = (MSEC_PER_SEC * 1000) /
|
||||
(uint32_t)sensor_value_to_milli(freq_val);
|
||||
|
||||
return (uint16_t)MIN(measure_rate_ms, UINT16_MAX);
|
||||
}
|
||||
|
||||
static int32_t to_raw_temp(const struct sensor_value *temp_val)
|
||||
{
|
||||
int32_t temp_mul_100 = (int32_t)(sensor_value_to_milli(temp_val) / 10);
|
||||
|
||||
return nrfs_temp_to_raw(temp_mul_100);
|
||||
}
|
||||
|
||||
static int api_sensor_trigger_set(const struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler)
|
||||
{
|
||||
struct temp_nrfs_data *data = dev->data;
|
||||
nrfs_err_t err;
|
||||
|
||||
if (trig->chan != SENSOR_CHAN_ALL &&
|
||||
trig->chan != SENSOR_CHAN_DIE_TEMP) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
switch (trig->type) {
|
||||
case SENSOR_TRIG_THRESHOLD:
|
||||
k_mutex_lock(&data->mutex, K_FOREVER);
|
||||
data->trigger = *trig;
|
||||
data->handler = handler;
|
||||
k_mutex_unlock(&data->mutex);
|
||||
|
||||
if (handler) {
|
||||
err = nrfs_temp_subscribe(
|
||||
to_measure_rate_ms(&data->sampling_freq),
|
||||
to_raw_temp(&data->low_threshold),
|
||||
to_raw_temp(&data->up_threshold),
|
||||
data);
|
||||
} else {
|
||||
err = nrfs_temp_unsubscribe();
|
||||
}
|
||||
|
||||
switch (err) {
|
||||
case NRFS_SUCCESS:
|
||||
break;
|
||||
case NRFS_ERR_INVALID_STATE:
|
||||
return -EAGAIN;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int api_sensor_attr_set(const struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
struct temp_nrfs_data *data = dev->data;
|
||||
|
||||
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
switch (attr) {
|
||||
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
||||
if (sensor_value_to_milli(val) <= 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
data->sampling_freq = *val;
|
||||
break;
|
||||
case SENSOR_ATTR_UPPER_THRESH:
|
||||
data->up_threshold = *val;
|
||||
break;
|
||||
case SENSOR_ATTR_LOWER_THRESH:
|
||||
data->low_threshold = *val;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TEMP_NRFS_TRIGGER */
|
||||
|
||||
static void sensor_handler(nrfs_temp_evt_t const *p_evt, void *context)
|
||||
{
|
||||
ARG_UNUSED(context);
|
||||
|
||||
struct temp_nrfs_data *data = context;
|
||||
|
||||
switch (p_evt->type) {
|
||||
case NRFS_TEMP_EVT_MEASURE_DONE:
|
||||
data->raw_temp = p_evt->raw_temp;
|
||||
k_sem_give(&data->measure_sem);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_TEMP_NRFS_TRIGGER
|
||||
case NRFS_TEMP_EVT_CHANGE:
|
||||
data->raw_temp = p_evt->raw_temp;
|
||||
#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
|
||||
k_sem_give(&data->event_sem);
|
||||
#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
|
||||
k_work_submit(&data->work);
|
||||
#endif
|
||||
break;
|
||||
#endif /* CONFIG_TEMP_NRFS_TRIGGER */
|
||||
|
||||
default:
|
||||
LOG_DBG("Temperature handler - unsupported event: 0x%x",
|
||||
p_evt->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int api_sample_fetch(const struct device *dev,
|
||||
enum sensor_channel chan)
|
||||
{
|
||||
struct temp_nrfs_data *data = dev->data;
|
||||
int nrfs_rc;
|
||||
int rc = 0;
|
||||
|
||||
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
k_mutex_lock(&data->mutex, K_FOREVER);
|
||||
nrfs_rc = nrfs_temp_measure_request(data);
|
||||
switch (nrfs_rc) {
|
||||
case NRFS_SUCCESS:
|
||||
k_sem_take(&data->measure_sem, K_FOREVER);
|
||||
LOG_DBG("Temperature sample: %d", data->raw_temp);
|
||||
break;
|
||||
case NRFS_ERR_INVALID_STATE:
|
||||
LOG_DBG("Backend is not ready, try again.");
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
default:
|
||||
LOG_DBG("Measure request failed: %d", nrfs_rc);
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
k_mutex_unlock(&data->mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int api_channel_get(const struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct temp_nrfs_data *data = dev->data;
|
||||
|
||||
if (chan != SENSOR_CHAN_DIE_TEMP) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
int32_t uval = nrfs_temp_from_raw(data->raw_temp);
|
||||
|
||||
val->val1 = uval / 100;
|
||||
val->val2 = (abs(uval) % 100) * 10000;
|
||||
|
||||
LOG_DBG("Temperature: %d.%02u[C]", uval / 100, abs(uval) % 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int temp_nrfs_init(const struct device *dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = nrfs_temp_init(sensor_handler);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
|
||||
struct temp_nrfs_data *data = dev->data;
|
||||
|
||||
k_thread_create(&data->thread, data->thread_stack,
|
||||
CONFIG_TEMP_NRFS_THREAD_STACK_SIZE,
|
||||
temp_nrfs_thread,
|
||||
data, NULL, NULL,
|
||||
K_PRIO_COOP(CONFIG_TEMP_NRFS_THREAD_PRIORITY),
|
||||
0, K_NO_WAIT);
|
||||
k_thread_name_set(&data->thread, dev->name);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api temp_nrfs_drv_api = {
|
||||
#ifdef CONFIG_TEMP_NRFS_TRIGGER
|
||||
.attr_set = api_sensor_attr_set,
|
||||
.trigger_set = api_sensor_trigger_set,
|
||||
#endif
|
||||
.sample_fetch = api_sample_fetch,
|
||||
.channel_get = api_channel_get
|
||||
};
|
||||
|
||||
static struct temp_nrfs_data temp_nrfs_drv_data = {
|
||||
.mutex = Z_MUTEX_INITIALIZER(temp_nrfs_drv_data.mutex),
|
||||
.measure_sem = Z_SEM_INITIALIZER(temp_nrfs_drv_data.measure_sem, 0, 1),
|
||||
#ifdef CONFIG_TEMP_NRFS_TRIGGER
|
||||
.dev = DEVICE_DT_INST_GET(0),
|
||||
.sampling_freq = DEFAULT_SAMPLING_FREQ,
|
||||
.up_threshold = DEFAULT_UP_THRESHOLD,
|
||||
.low_threshold = DEFAULT_LOW_THRESHOLD,
|
||||
#endif
|
||||
#if defined(CONFIG_TEMP_NRFS_TRIGGER_OWN_THREAD)
|
||||
.event_sem = Z_SEM_INITIALIZER(temp_nrfs_drv_data.event_sem, 0, 1),
|
||||
#elif defined(CONFIG_TEMP_NRFS_TRIGGER_GLOBAL_THREAD)
|
||||
.work = Z_WORK_INITIALIZER(temp_nrfs_work_handler),
|
||||
#endif
|
||||
};
|
||||
|
||||
DEVICE_DT_INST_DEFINE(0, temp_nrfs_init, NULL,
|
||||
&temp_nrfs_drv_data, NULL,
|
||||
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
|
||||
&temp_nrfs_drv_api);
|
9
dts/bindings/sensor/nordic,nrf-temp-nrfs.yaml
Normal file
9
dts/bindings/sensor/nordic,nrf-temp-nrfs.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
Nordic nRF family temperature sensor accessed via nRF Services (nrfs)
|
||||
|
||||
compatible: "nordic,nrf-temp-nrfs"
|
||||
|
||||
include: base.yaml
|
|
@ -1076,4 +1076,9 @@
|
|||
#address-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
temp_nrfs: temp {
|
||||
compatible = "nordic,nrf-temp-nrfs";
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue