diff --git a/drivers/sensor/nxp/CMakeLists.txt b/drivers/sensor/nxp/CMakeLists.txt index bca607d819f..80ccb0447db 100644 --- a/drivers/sensor/nxp/CMakeLists.txt +++ b/drivers/sensor/nxp/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory_ifdef(CONFIG_NXP_TEMPMON nxp_tempmon) add_subdirectory_ifdef(CONFIG_P3T1755 p3t1755) add_subdirectory_ifdef(CONFIG_QDEC_MCUX qdec_mcux) add_subdirectory_ifdef(CONFIG_QDEC_NXP_S32 qdec_nxp_s32) +add_subdirectory_ifdef(CONFIG_QDEC_TPM qdec_tpm) add_subdirectory_ifdef(CONFIG_SENSOR_MCUX_ACMP mcux_acmp) add_subdirectory_ifdef(CONFIG_TEMP_KINETIS nxp_kinetis_temp) # zephyr-keep-sorted-stop diff --git a/drivers/sensor/nxp/Kconfig b/drivers/sensor/nxp/Kconfig index e1289d7fdeb..76b58bbba7b 100644 --- a/drivers/sensor/nxp/Kconfig +++ b/drivers/sensor/nxp/Kconfig @@ -12,4 +12,5 @@ source "drivers/sensor/nxp/nxp_tempmon/Kconfig" source "drivers/sensor/nxp/p3t1755/Kconfig" source "drivers/sensor/nxp/qdec_mcux/Kconfig" source "drivers/sensor/nxp/qdec_nxp_s32/Kconfig" +source "drivers/sensor/nxp/qdec_tpm/Kconfig" # zephyr-keep-sorted-stop diff --git a/drivers/sensor/nxp/qdec_tpm/CMakeLists.txt b/drivers/sensor/nxp/qdec_tpm/CMakeLists.txt new file mode 100644 index 00000000000..aa805f48b98 --- /dev/null +++ b/drivers/sensor/nxp/qdec_tpm/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(qdec_nxp_tpm.c) diff --git a/drivers/sensor/nxp/qdec_tpm/Kconfig b/drivers/sensor/nxp/qdec_tpm/Kconfig new file mode 100644 index 00000000000..8e4a96eab31 --- /dev/null +++ b/drivers/sensor/nxp/qdec_tpm/Kconfig @@ -0,0 +1,10 @@ +# Copyright 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +config QDEC_TPM + bool "NXP Quad Decoder TPM driver" + default y + depends on DT_HAS_NXP_TPM_QDEC_ENABLED + select PINCTRL + help + Enable drivers for NXP TPM QUADRATURE DECODER diff --git a/drivers/sensor/nxp/qdec_tpm/qdec_nxp_tpm.c b/drivers/sensor/nxp/qdec_tpm/qdec_nxp_tpm.c new file mode 100644 index 00000000000..2e3f33b4f32 --- /dev/null +++ b/drivers/sensor/nxp/qdec_tpm/qdec_nxp_tpm.c @@ -0,0 +1,157 @@ +/* + * Copyright 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_tpm_qdec + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +LOG_MODULE_REGISTER(qdec_tpm, CONFIG_SENSOR_LOG_LEVEL); + +struct qdec_tpm_config { + TPM_Type *base; + const struct pinctrl_dev_config *pincfg; + const tpm_phase_params_t phaseParams; +}; + +struct qdec_tpm_data { + int32_t count; + double micro_ticks_per_rev; +}; + +static int qdec_tpm_attr_set(const struct device *dev, enum sensor_channel ch, + enum sensor_attribute attr, const struct sensor_value *val) +{ + struct qdec_tpm_data *data = dev->data; + + if (ch != SENSOR_CHAN_ROTATION) { + return -ENOTSUP; + } + + switch ((enum sensor_attribute_qdec_tpm)attr) { + case SENSOR_ATTR_QDEC_MOD_VAL: + data->micro_ticks_per_rev = val->val1 / 1000000.0f; + return 0; + default: + return -ENOTSUP; + } +} + +static int qdec_tpm_attr_get(const struct device *dev, enum sensor_channel ch, + enum sensor_attribute attr, struct sensor_value *val) +{ + struct qdec_tpm_data *data = dev->data; + + if (ch != SENSOR_CHAN_ROTATION) { + return -ENOTSUP; + } + + switch ((enum sensor_attribute_qdec_tpm)attr) { + case SENSOR_ATTR_QDEC_MOD_VAL: + val->val1 = data->micro_ticks_per_rev * 1000000; + return 0; + default: + return -ENOTSUP; + } +} + +static int qdec_tpm_fetch(const struct device *dev, enum sensor_channel ch) +{ + const struct qdec_tpm_config *config = dev->config; + struct qdec_tpm_data *data = dev->data; + + if (ch != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + /* Read count */ + data->count = TPM_GetCurrentTimerCount(config->base); + + LOG_DBG("pos %d", data->count); + + return 0; +} + +static int qdec_tpm_ch_get(const struct device *dev, enum sensor_channel ch, + struct sensor_value *val) +{ + struct qdec_tpm_data *data = dev->data; + double rotation = (data->count * M_PI) / (data->micro_ticks_per_rev); + + switch (ch) { + case SENSOR_CHAN_ROTATION: + sensor_value_from_double(val, rotation); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int qdec_tpm_init(const struct device *dev) +{ + const struct qdec_tpm_config *config = dev->config; + tpm_config_t tpm_config; + int err; + + err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (err) { + return err; + } + + TPM_GetDefaultConfig(&tpm_config); + tpm_config.prescale = kTPM_Prescale_Divide_1; + + TPM_Init(config->base, &tpm_config); + + TPM_SetTimerPeriod(config->base, 0xFFFFFFFF); + + TPM_SetupQuadDecode(config->base, &config->phaseParams, &config->phaseParams, + kTPM_QuadPhaseEncode); + + TPM_StartTimer(config->base, kTPM_SystemClock); + + return 0; +} + +static DEVICE_API(sensor, qdec_tpm_api) = { + .attr_set = &qdec_tpm_attr_set, + .attr_get = &qdec_tpm_attr_get, + .sample_fetch = &qdec_tpm_fetch, + .channel_get = &qdec_tpm_ch_get, +}; + +#define QDEC_MCUX_INIT(n) \ + \ + static struct qdec_tpm_data qdec_mcux_##n##_data = { \ + .micro_ticks_per_rev = \ + (double)(DT_INST_PROP(n, micro_ticks_per_rev) / 1000000.0f)}; \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static const struct qdec_tpm_config qdec_mcux_##n##_config = { \ + .base = (TPM_Type *)DT_INST_REG_ADDR(n), \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .phaseParams = {0, kTPM_QuadPhaseNormal}}; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, qdec_tpm_init, NULL, &qdec_mcux_##n##_data, \ + &qdec_mcux_##n##_config, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &qdec_tpm_api); + +DT_INST_FOREACH_STATUS_OKAY(QDEC_MCUX_INIT) diff --git a/dts/bindings/sensor/nxp,tpm-qdec.yaml b/dts/bindings/sensor/nxp,tpm-qdec.yaml new file mode 100644 index 00000000000..f8ac15fa06d --- /dev/null +++ b/dts/bindings/sensor/nxp,tpm-qdec.yaml @@ -0,0 +1,44 @@ +# Copyright (c) 2025 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: | + NXP Timer/PWM Module (TPM) Quadrature Decoder Mode driver. + This driver uses tpm_chn0 (phase A) and tpm_chn1 (phase B) input signals to control the + TPM counter increment and decrement. The Zephyr Sensor API exposes the rotational position as + SENSOR_CHAN_ROTATION by dividing the counter by counts-per revolution definition. + + To use the NXP TPM module you've to override the compatible string to use the QDEC mode driver + with 'nxp,tpm-qdec' + + &tpm4 { + compatible = "nxp,tpm-qdec"; + status = "okay"; + pinctrl-0 = <&tpm4_pwm2_pwm3>; + pinctrl-names = "default"; + micro-ticks-per-rev = <685440000>; + }; + + When inherting from an existing TPM instance you might want to remove the prescaler property + Since the QDEC mode doesn't use the prescaler, you do this using: + /delete-property/ prescaler; + +compatible: "nxp,tpm-qdec" + +include: [pinctrl-device.yaml, sensor-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + micro-ticks-per-rev: + type: int + required: true + description: | + This is a number that is used to determine how many revolutions * 1000000 + were done based on the current counter's value. + + pinctrl-0: + required: true diff --git a/include/zephyr/drivers/sensor/qdec_nxp_tpm.h b/include/zephyr/drivers/sensor/qdec_nxp_tpm.h new file mode 100644 index 00000000000..4e15645c869 --- /dev/null +++ b/include/zephyr/drivers/sensor/qdec_nxp_tpm.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2022, Prevas A/S + * Copyright (c) 2025 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_QDEC_NXP_TPM_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_QDEC_NXP_TPM_H_ + +#include + +enum sensor_attribute_qdec_tpm { + /* Number of counts per revolution */ + SENSOR_ATTR_QDEC_MOD_VAL = SENSOR_ATTR_PRIV_START, +}; + +#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_QDEC_NXP_TPM_H_ */