Skip to content

Commit 8aafb29

Browse files
committed
drivers: sensor: Enable NXP pmc tmpsns driver
This commit introduced NXP pmc temperature sensor (pmc-tmpsns) driver. Signed-off-by: Zhaoxiang Jin <[email protected]>
1 parent 778ee64 commit 8aafb29

File tree

6 files changed

+199
-0
lines changed

6 files changed

+199
-0
lines changed

drivers/sensor/nxp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_subdirectory_ifdef(CONFIG_FXLS8974 fxls8974)
77
add_subdirectory_ifdef(CONFIG_FXOS8700 fxos8700)
88
add_subdirectory_ifdef(CONFIG_LPADC_TEMP40 nxp_lpadc_temp40)
99
add_subdirectory_ifdef(CONFIG_MCUX_LPCMP mcux_lpcmp)
10+
add_subdirectory_ifdef(CONFIG_NXP_PMC_TMPSNS nxp_pmc_tmpsns)
1011
add_subdirectory_ifdef(CONFIG_NXP_TEMPMON nxp_tempmon)
1112
add_subdirectory_ifdef(CONFIG_P3T1755 p3t1755)
1213
add_subdirectory_ifdef(CONFIG_QDEC_MCUX qdec_mcux)

drivers/sensor/nxp/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ source "drivers/sensor/nxp/mcux_acmp/Kconfig"
99
source "drivers/sensor/nxp/mcux_lpcmp/Kconfig"
1010
source "drivers/sensor/nxp/nxp_kinetis_temp/Kconfig"
1111
source "drivers/sensor/nxp/nxp_lpadc_temp40/Kconfig"
12+
source "drivers/sensor/nxp/nxp_pmc_tmpsns/Kconfig"
1213
source "drivers/sensor/nxp/nxp_tempmon/Kconfig"
1314
source "drivers/sensor/nxp/p3t1755/Kconfig"
1415
source "drivers/sensor/nxp/qdec_mcux/Kconfig"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
zephyr_library()
5+
zephyr_library_sources(nxp_pmc_tmpsns.c)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config NXP_PMC_TMPSNS
5+
bool "NXP PMC Temperature Sensor (TMPSNS)"
6+
default y
7+
depends on DT_HAS_NXP_PMC_TMPSNS_ENABLED
8+
select FPU if CPU_HAS_FPU
9+
help
10+
Enable driver for the NXP PMC temperature sensor.
11+
This is used to retrieve on-die operational temperature.
12+
13+
if NXP_PMC_TMPSNS
14+
config NXP_PMC_TMPSNS_CALIBRATION_OTP_FUSE_INDEX
15+
int "OTP FUSE index"
16+
default 77 if SOC_SERIES_IMXRT7XX
17+
help
18+
TSENS_CAL is an 8-bit signed calibration constant
19+
retrieved from non-volatile memory. We need this
20+
index to read the fuse to get TSENS_CAL.
21+
endif
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "fsl_romapi_otp.h"
8+
#include <zephyr/device.h>
9+
#include <zephyr/devicetree.h>
10+
#include <zephyr/drivers/sensor.h>
11+
#include <zephyr/drivers/adc.h>
12+
#include <zephyr/logging/log.h>
13+
14+
LOG_MODULE_REGISTER(nxp_pmc_tmpsns, CONFIG_SENSOR_LOG_LEVEL);
15+
16+
#define DT_DRV_COMPAT nxp_pmc_tmpsns
17+
18+
struct nxp_pmc_tmpsns_config {
19+
const struct device *adc;
20+
struct adc_sequence adc_seq;
21+
struct adc_channel_cfg ch_cfg;
22+
};
23+
24+
struct nxp_pmc_tmpsns_data {
25+
uint16_t buffer;
26+
uint32_t pmc_tmpsns_calibration;
27+
float pmc_tmpsns_value;
28+
};
29+
30+
static int nxp_pmc_tmpsns_sample_fetch(const struct device *dev, enum sensor_channel chan)
31+
{
32+
uint8_t pmc_tmpsns_select[15] = {0, 1, 3, 2, 6, 7, 5, 4, 5, 7, 6, 2, 3, 1, 0};
33+
const struct nxp_pmc_tmpsns_config *config = dev->config;
34+
struct nxp_pmc_tmpsns_data *data = dev->data;
35+
uint16_t pmc_tmpsns_value[15] = {0};
36+
float cm_vref, cm_ctat, cm_temp;
37+
int8_t calibration = 0;
38+
int ret;
39+
40+
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
41+
return -ENOTSUP;
42+
}
43+
44+
for (uint8_t index = 0; index < 15; ++index) {
45+
PMC0->TSENSOR = PMC_TSENSOR_TSENSM(pmc_tmpsns_select[index]);
46+
47+
ret = adc_read(config->adc, &config->adc_seq);
48+
if (ret) {
49+
LOG_ERR("Failed to read ADC channels with code %d", ret);
50+
return ret;
51+
}
52+
pmc_tmpsns_value[index] = data->buffer;
53+
}
54+
55+
ret = adc_read(config->adc, &config->adc_seq);
56+
if (ret) {
57+
LOG_ERR("Failed to read ADC channels with code %d", ret);
58+
return ret;
59+
}
60+
61+
ret = adc_read(config->adc, &config->adc_seq);
62+
if (ret) {
63+
LOG_ERR("Failed to read ADC channels with code %d", ret);
64+
return ret;
65+
}
66+
67+
cm_ctat = (float)(2 * pmc_tmpsns_value[1] - pmc_tmpsns_value[2] +
68+
2 * pmc_tmpsns_value[13] - pmc_tmpsns_value[12] +
69+
2 * pmc_tmpsns_value[6] - pmc_tmpsns_value[5] +
70+
2 * pmc_tmpsns_value[8] - pmc_tmpsns_value[9]) / 4.0f;
71+
72+
cm_temp = (float)(2 * pmc_tmpsns_value[0] - pmc_tmpsns_value[3] +
73+
2 * pmc_tmpsns_value[14] - pmc_tmpsns_value[11] +
74+
4 * pmc_tmpsns_value[7] - pmc_tmpsns_value[4] -
75+
pmc_tmpsns_value[10]) / 4.0f;
76+
77+
calibration = (int8_t)(data->pmc_tmpsns_calibration & 0xFF);
78+
79+
cm_vref = cm_ctat + (953.36f + calibration) * cm_temp / 2048;
80+
81+
data->pmc_tmpsns_value = 370.98f * (cm_temp / cm_vref) - 273.15f;
82+
83+
return 0;
84+
}
85+
86+
static int nxp_pmc_tmpsns_channel_get(const struct device *dev,
87+
enum sensor_channel chan,
88+
struct sensor_value *val)
89+
{
90+
const struct nxp_pmc_tmpsns_data *data = dev->data;
91+
92+
if (chan != SENSOR_CHAN_DIE_TEMP) {
93+
return -ENOTSUP;
94+
}
95+
96+
return sensor_value_from_double(val, data->pmc_tmpsns_value);
97+
}
98+
99+
static int nxp_pmc_tmpsns_init(const struct device *dev)
100+
{
101+
const struct nxp_pmc_tmpsns_config *config = dev->config;
102+
struct nxp_pmc_tmpsns_data *data = dev->data;
103+
int ret;
104+
105+
if (!device_is_ready(config->adc)) {
106+
LOG_ERR("ADC device not ready");
107+
return -ENODEV;
108+
}
109+
110+
ret = adc_channel_setup(config->adc, &config->ch_cfg);
111+
if (ret) {
112+
LOG_ERR("Failed to setup ADC channel with code %d", ret);
113+
return ret;
114+
}
115+
116+
ret = otp_fuse_read(CONFIG_NXP_PMC_TMPSNS_CALIBRATION_OTP_FUSE_INDEX,
117+
&(data->pmc_tmpsns_calibration));
118+
if (ret) {
119+
LOG_ERR("Failed to get calibration value form FUSE.");
120+
return -ENOTSUP;
121+
}
122+
123+
return 0;
124+
}
125+
126+
static DEVICE_API(sensor, nxp_pmc_tmpsns_api) = {
127+
.sample_fetch = nxp_pmc_tmpsns_sample_fetch,
128+
.channel_get = nxp_pmc_tmpsns_channel_get,
129+
};
130+
131+
#define NXP_PMC_TMPSNS_INIT(inst) \
132+
static struct nxp_pmc_tmpsns_data _CONCAT(data, inst) = { \
133+
.buffer = 0, \
134+
.pmc_tmpsns_calibration = 0, \
135+
.pmc_tmpsns_value = 0, \
136+
}; \
137+
\
138+
static const struct nxp_pmc_tmpsns_config _CONCAT(config, inst) = { \
139+
.adc = DEVICE_DT_GET(DT_INST_IO_CHANNELS_CTLR(inst)), \
140+
.adc_seq = { \
141+
.channels = BIT(DT_INST_IO_CHANNELS_INPUT(inst)), \
142+
.buffer = &_CONCAT(data, inst).buffer, \
143+
.buffer_size = sizeof(_CONCAT(data, inst)), \
144+
.resolution = 16, \
145+
.oversampling = 7, \
146+
}, \
147+
.ch_cfg = ADC_CHANNEL_CFG_DT(DT_CHILD(DT_INST_IO_CHANNELS_CTLR(inst), \
148+
UTIL_CAT(channel_, DT_INST_IO_CHANNELS_INPUT(inst)))), \
149+
}; \
150+
\
151+
SENSOR_DEVICE_DT_INST_DEFINE(inst, nxp_pmc_tmpsns_init, NULL, \
152+
&_CONCAT(data, inst), &_CONCAT(config, inst), \
153+
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
154+
&nxp_pmc_tmpsns_api);
155+
156+
DT_INST_FOREACH_STATUS_OKAY(NXP_PMC_TMPSNS_INIT)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright NXP 2025
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: NXP PMC temperature sensor (PMC-TMPSNS)
5+
6+
compatible: "nxp,pmc-tmpsns"
7+
8+
include: sensor-device.yaml
9+
10+
properties:
11+
io-channels:
12+
required: true
13+
description: |
14+
This should point to an ADC channel (e.g., <&adc0 0>)
15+
to read from the PMC internal temperature sensor.

0 commit comments

Comments
 (0)