Skip to content

Commit 49e33d3

Browse files
PetervdPerk-NXPkartben
authored andcommitted
drivers: sensor: qdec_tpm: Add QDEC support for NXP TPM
Allows to run the NXP Timer/PWM Module (TPM) in Quadrature Decoder Mode. Signed-off-by: Peter van der Perk <[email protected]>
1 parent 0d73b53 commit 49e33d3

File tree

7 files changed

+237
-0
lines changed

7 files changed

+237
-0
lines changed

drivers/sensor/nxp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_subdirectory_ifdef(CONFIG_NXP_TEMPMON nxp_tempmon)
1010
add_subdirectory_ifdef(CONFIG_P3T1755 p3t1755)
1111
add_subdirectory_ifdef(CONFIG_QDEC_MCUX qdec_mcux)
1212
add_subdirectory_ifdef(CONFIG_QDEC_NXP_S32 qdec_nxp_s32)
13+
add_subdirectory_ifdef(CONFIG_QDEC_TPM qdec_tpm)
1314
add_subdirectory_ifdef(CONFIG_SENSOR_MCUX_ACMP mcux_acmp)
1415
add_subdirectory_ifdef(CONFIG_TEMP_KINETIS nxp_kinetis_temp)
1516
# zephyr-keep-sorted-stop

drivers/sensor/nxp/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ source "drivers/sensor/nxp/nxp_tempmon/Kconfig"
1212
source "drivers/sensor/nxp/p3t1755/Kconfig"
1313
source "drivers/sensor/nxp/qdec_mcux/Kconfig"
1414
source "drivers/sensor/nxp/qdec_nxp_s32/Kconfig"
15+
source "drivers/sensor/nxp/qdec_tpm/Kconfig"
1516
# zephyr-keep-sorted-stop
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
zephyr_library()
5+
6+
zephyr_library_sources(qdec_nxp_tpm.c)

drivers/sensor/nxp/qdec_tpm/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config QDEC_TPM
5+
bool "NXP Quad Decoder TPM driver"
6+
default y
7+
depends on DT_HAS_NXP_TPM_QDEC_ENABLED
8+
select PINCTRL
9+
help
10+
Enable drivers for NXP TPM QUADRATURE DECODER
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT nxp_tpm_qdec
8+
9+
#include <errno.h>
10+
#include <soc.h>
11+
#include <fsl_tpm.h>
12+
13+
#include <zephyr/drivers/clock_control.h>
14+
#include <zephyr/drivers/pinctrl.h>
15+
#include <zephyr/drivers/sensor.h>
16+
#include <zephyr/drivers/sensor/qdec_nxp_tpm.h>
17+
#include <zephyr/logging/log.h>
18+
#include <math.h>
19+
20+
#ifndef M_PI
21+
#define M_PI 3.14159265358979323846
22+
#endif
23+
24+
LOG_MODULE_REGISTER(qdec_tpm, CONFIG_SENSOR_LOG_LEVEL);
25+
26+
struct qdec_tpm_config {
27+
TPM_Type *base;
28+
const struct pinctrl_dev_config *pincfg;
29+
const tpm_phase_params_t phaseParams;
30+
};
31+
32+
struct qdec_tpm_data {
33+
int32_t count;
34+
double micro_ticks_per_rev;
35+
};
36+
37+
static int qdec_tpm_attr_set(const struct device *dev, enum sensor_channel ch,
38+
enum sensor_attribute attr, const struct sensor_value *val)
39+
{
40+
struct qdec_tpm_data *data = dev->data;
41+
42+
if (ch != SENSOR_CHAN_ROTATION) {
43+
return -ENOTSUP;
44+
}
45+
46+
switch ((enum sensor_attribute_qdec_tpm)attr) {
47+
case SENSOR_ATTR_QDEC_MOD_VAL:
48+
data->micro_ticks_per_rev = val->val1 / 1000000.0f;
49+
return 0;
50+
default:
51+
return -ENOTSUP;
52+
}
53+
}
54+
55+
static int qdec_tpm_attr_get(const struct device *dev, enum sensor_channel ch,
56+
enum sensor_attribute attr, struct sensor_value *val)
57+
{
58+
struct qdec_tpm_data *data = dev->data;
59+
60+
if (ch != SENSOR_CHAN_ROTATION) {
61+
return -ENOTSUP;
62+
}
63+
64+
switch ((enum sensor_attribute_qdec_tpm)attr) {
65+
case SENSOR_ATTR_QDEC_MOD_VAL:
66+
val->val1 = data->micro_ticks_per_rev * 1000000;
67+
return 0;
68+
default:
69+
return -ENOTSUP;
70+
}
71+
}
72+
73+
static int qdec_tpm_fetch(const struct device *dev, enum sensor_channel ch)
74+
{
75+
const struct qdec_tpm_config *config = dev->config;
76+
struct qdec_tpm_data *data = dev->data;
77+
78+
if (ch != SENSOR_CHAN_ALL) {
79+
return -ENOTSUP;
80+
}
81+
82+
/* Read count */
83+
data->count = TPM_GetCurrentTimerCount(config->base);
84+
85+
LOG_DBG("pos %d", data->count);
86+
87+
return 0;
88+
}
89+
90+
static int qdec_tpm_ch_get(const struct device *dev, enum sensor_channel ch,
91+
struct sensor_value *val)
92+
{
93+
struct qdec_tpm_data *data = dev->data;
94+
double rotation = (data->count * M_PI) / (data->micro_ticks_per_rev);
95+
96+
switch (ch) {
97+
case SENSOR_CHAN_ROTATION:
98+
sensor_value_from_double(val, rotation);
99+
break;
100+
default:
101+
return -ENOTSUP;
102+
}
103+
104+
return 0;
105+
}
106+
107+
static int qdec_tpm_init(const struct device *dev)
108+
{
109+
const struct qdec_tpm_config *config = dev->config;
110+
tpm_config_t tpm_config;
111+
int err;
112+
113+
err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
114+
if (err) {
115+
return err;
116+
}
117+
118+
TPM_GetDefaultConfig(&tpm_config);
119+
tpm_config.prescale = kTPM_Prescale_Divide_1;
120+
121+
TPM_Init(config->base, &tpm_config);
122+
123+
TPM_SetTimerPeriod(config->base, 0xFFFFFFFF);
124+
125+
TPM_SetupQuadDecode(config->base, &config->phaseParams, &config->phaseParams,
126+
kTPM_QuadPhaseEncode);
127+
128+
TPM_StartTimer(config->base, kTPM_SystemClock);
129+
130+
return 0;
131+
}
132+
133+
static DEVICE_API(sensor, qdec_tpm_api) = {
134+
.attr_set = &qdec_tpm_attr_set,
135+
.attr_get = &qdec_tpm_attr_get,
136+
.sample_fetch = &qdec_tpm_fetch,
137+
.channel_get = &qdec_tpm_ch_get,
138+
};
139+
140+
#define QDEC_MCUX_INIT(n) \
141+
\
142+
static struct qdec_tpm_data qdec_mcux_##n##_data = { \
143+
.micro_ticks_per_rev = \
144+
(double)(DT_INST_PROP(n, micro_ticks_per_rev) / 1000000.0f)}; \
145+
\
146+
PINCTRL_DT_INST_DEFINE(n); \
147+
\
148+
static const struct qdec_tpm_config qdec_mcux_##n##_config = { \
149+
.base = (TPM_Type *)DT_INST_REG_ADDR(n), \
150+
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
151+
.phaseParams = {0, kTPM_QuadPhaseNormal}}; \
152+
\
153+
SENSOR_DEVICE_DT_INST_DEFINE(n, qdec_tpm_init, NULL, &qdec_mcux_##n##_data, \
154+
&qdec_mcux_##n##_config, POST_KERNEL, \
155+
CONFIG_SENSOR_INIT_PRIORITY, &qdec_tpm_api);
156+
157+
DT_INST_FOREACH_STATUS_OKAY(QDEC_MCUX_INIT)

dts/bindings/sensor/nxp,tpm-qdec.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright (c) 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
NXP Timer/PWM Module (TPM) Quadrature Decoder Mode driver.
6+
This driver uses tpm_chn0 (phase A) and tpm_chn1 (phase B) input signals to control the
7+
TPM counter increment and decrement. The Zephyr Sensor API exposes the rotational position as
8+
SENSOR_CHAN_ROTATION by dividing the counter by counts-per revolution definition.
9+
10+
To use the NXP TPM module you've to override the compatible string to use the QDEC mode driver
11+
with 'nxp,tpm-qdec'
12+
13+
&tpm4 {
14+
compatible = "nxp,tpm-qdec";
15+
status = "okay";
16+
pinctrl-0 = <&tpm4_pwm2_pwm3>;
17+
pinctrl-names = "default";
18+
micro-ticks-per-rev = <685440000>;
19+
};
20+
21+
When inherting from an existing TPM instance you might want to remove the prescaler property
22+
Since the QDEC mode doesn't use the prescaler, you do this using:
23+
/delete-property/ prescaler;
24+
25+
compatible: "nxp,tpm-qdec"
26+
27+
include: [pinctrl-device.yaml, sensor-device.yaml]
28+
29+
properties:
30+
reg:
31+
required: true
32+
33+
interrupts:
34+
required: true
35+
36+
micro-ticks-per-rev:
37+
type: int
38+
required: true
39+
description: |
40+
This is a number that is used to determine how many revolutions * 1000000
41+
were done based on the current counter's value.
42+
43+
pinctrl-0:
44+
required: true
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) 2022, Prevas A/S
3+
* Copyright (c) 2025 NXP
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_QDEC_NXP_TPM_H_
9+
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_QDEC_NXP_TPM_H_
10+
11+
#include <zephyr/drivers/sensor.h>
12+
13+
enum sensor_attribute_qdec_tpm {
14+
/* Number of counts per revolution */
15+
SENSOR_ATTR_QDEC_MOD_VAL = SENSOR_ATTR_PRIV_START,
16+
};
17+
18+
#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_QDEC_NXP_TPM_H_ */

0 commit comments

Comments
 (0)