diff --git a/drivers/sensor/nordic/qdec_nrfx/qdec_nrfx.c b/drivers/sensor/nordic/qdec_nrfx/qdec_nrfx.c index dc70c27d417..e7f014de0d0 100644 --- a/drivers/sensor/nordic/qdec_nrfx/qdec_nrfx.c +++ b/drivers/sensor/nordic/qdec_nrfx/qdec_nrfx.c @@ -192,81 +192,64 @@ static const struct sensor_driver_api qdec_nrfx_driver_api = { .trigger_set = qdec_nrfx_trigger_set, }; -#ifdef CONFIG_PM_DEVICE -static int qdec_nrfx_pm_action(const struct device *dev, - enum pm_device_action action) +static void qdec_pm_suspend(const struct device *dev) { const struct qdec_nrfx_config *config = dev->config; - int ret = 0; + nrfx_qdec_disable(&config->qdec); + qdec_nrfx_gpio_ctrl(dev, false); + + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); +} + +static void qdec_pm_resume(const struct device *dev) +{ + const struct qdec_nrfx_config *config = dev->config; + + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + qdec_nrfx_gpio_ctrl(dev, true); + nrfx_qdec_enable(&config->qdec); +} + +static int qdec_nrfx_pm_action(const struct device *dev, enum pm_device_action action) +{ switch (action) { case PM_DEVICE_ACTION_RESUME: - ret = pinctrl_apply_state(config->pcfg, - PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; - } - qdec_nrfx_gpio_ctrl(dev, true); - nrfx_qdec_enable(&config->qdec); - break; - - case PM_DEVICE_ACTION_TURN_OFF: - /* device must be uninitialized */ - nrfx_qdec_uninit(&config->qdec); - ret = pinctrl_apply_state(config->pcfg, - PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; - } + qdec_pm_resume(dev); break; case PM_DEVICE_ACTION_SUSPEND: - /* device must be suspended */ - nrfx_qdec_disable(&config->qdec); - qdec_nrfx_gpio_ctrl(dev, false); - ret = pinctrl_apply_state(config->pcfg, - PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; + if (IS_ENABLED(CONFIG_PM_DEVICE)) { + qdec_pm_suspend(dev); } break; default: return -ENOTSUP; + break; } - return ret; + return 0; } -#endif /* CONFIG_PM_DEVICE */ static int qdec_nrfx_init(const struct device *dev) { - const struct qdec_nrfx_config *dev_config = dev->config; - - dev_config->irq_connect(); + const struct qdec_nrfx_config *config = dev->config; + nrfx_err_t nerr; - int err = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT); + config->irq_connect(); - if (err < 0) { - return err; + nerr = nrfx_qdec_init(&config->qdec, &config->config, qdec_nrfx_event_handler, (void *)dev); + if (nerr != NRFX_SUCCESS) { + return (nerr == NRFX_ERROR_INVALID_STATE) ? -EBUSY : -EFAULT; } - nrfx_err_t nerr = nrfx_qdec_init(&dev_config->qdec, - &dev_config->config, - qdec_nrfx_event_handler, - (void *)dev); - - if (nerr == NRFX_ERROR_INVALID_STATE) { - LOG_ERR("qdec already in use"); - return -EBUSY; - } else if (nerr != NRFX_SUCCESS) { - LOG_ERR("failed to initialize qdec"); - return -EFAULT; + /* End up in suspend state. */ + qdec_nrfx_gpio_ctrl(dev, false); + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); } - qdec_nrfx_gpio_ctrl(dev, true); - nrfx_qdec_enable(&dev_config->qdec); - - return 0; + return pm_device_driver_init(dev, qdec_nrfx_pm_action); } #define QDEC(idx) DT_NODELABEL(qdec##idx) @@ -301,7 +284,7 @@ static int qdec_nrfx_init(const struct device *dev) .enable_pin = DT_PROP_OR(QDEC(idx), enable_pin, NRF_QDEC_PIN_NOT_CONNECTED), \ .steps = QDEC_PROP(idx, steps), \ }; \ - PM_DEVICE_DT_DEFINE(QDEC(idx), qdec_nrfx_pm_action); \ + PM_DEVICE_DT_DEFINE(QDEC(idx), qdec_nrfx_pm_action, PM_DEVICE_ISR_SAFE); \ SENSOR_DEVICE_DT_DEFINE(QDEC(idx), \ qdec_nrfx_init, \ PM_DEVICE_DT_GET(QDEC(idx)), \ diff --git a/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay b/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay index 4f8ea8ad31b..f227fb95c38 100644 --- a/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay +++ b/tests/boards/nrf/qdec/boards/nrf52840dk_nrf52840.overlay @@ -31,12 +31,27 @@ ; /* Arduino D2 */ }; }; + + qdec_sleep_pinctrl: qdec_sleep_pinctrl { + group1 { + psels = , /* Ardiuno D0 */ + ; /* Arduino D2 */ + low-power-enable; + }; + }; }; &qdec0 { status = "okay"; pinctrl-0 = <&qdec_pinctrl>; - pinctrl-names = "default"; + pinctrl-1 = <&qdec_sleep_pinctrl>; + pinctrl-names = "default", "sleep"; steps = < 127 >; led-pre = < 500 >; + zephyr,pm-device-runtime-auto; +}; + +/* To prevent enabling console receiver. */ +&uart0 { + disable-rx; }; diff --git a/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay b/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay index 7f4a13f3602..ed6a5587f5b 100644 --- a/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/tests/boards/nrf/qdec/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -30,12 +30,27 @@ ; /* Arduino A2 */ }; }; + + qdec_sleep_pinctrl: qdec_sleep_pinctrl { + group1 { + psels = , + ; + low-power-enable; + }; + }; }; &qdec1 { status = "okay"; pinctrl-0 = <&qdec_pinctrl>; - pinctrl-names = "default"; + pinctrl-1 = <&qdec_sleep_pinctrl>; + pinctrl-names = "default", "sleep"; steps = < 127 >; led-pre = < 500 >; + zephyr,pm-device-runtime-auto; +}; + +/* To prevent enabling console receiver. */ +&uart0 { + disable-rx; }; diff --git a/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 6b0db6ad6a8..0e552906a00 100644 --- a/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/tests/boards/nrf/qdec/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -28,6 +28,14 @@ ; }; }; + + qdec_sleep_pinctrl: qdec_sleep_pinctrl { + group1 { + psels = , + ; + low-power-enable; + }; + }; }; &gpio1 { @@ -41,7 +49,14 @@ &qdec130 { status = "okay"; pinctrl-0 = <&qdec_pinctrl>; - pinctrl-names = "default"; + pinctrl-1 = <&qdec_sleep_pinctrl>; + pinctrl-names = "default", "sleep"; steps = <127>; led-pre = <500>; + zephyr,pm-device-runtime-auto; +}; + +/* To prevent enabling console receiver. */ +&uart136 { + disable-rx; }; diff --git a/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuapp.overlay index 538106b38b1..dc39be6deb3 100644 --- a/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuapp.overlay +++ b/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -3,41 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -/ { - aliases { - qdec0 = &qdec20; - qenca = &phase_a; - qencb = &phase_b; - }; +#include "nrf54l15pdk_nrf54l15_common.dtsi" - encoder-emulate { - compatible = "gpio-leds"; - phase_a: phase_a { - gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; - }; - phase_b: phase_b { - gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; - }; - }; -}; - -&pinctrl { - qdec_pinctrl: qdec_pinctrl { - group1 { - psels = , - ; - }; - }; -}; - -&gpio1 { - status = "okay"; -}; - -&qdec20 { - status = "okay"; - pinctrl-0 = <&qdec_pinctrl>; - pinctrl-names = "default"; - steps = <127>; - led-pre = <500>; +/* To prevent enabling console receiver. */ +&uart20 { + disable-rx; }; diff --git a/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay b/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay index 538106b38b1..059222c801b 100644 --- a/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay +++ b/tests/boards/nrf/qdec/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay @@ -3,41 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -/ { - aliases { - qdec0 = &qdec20; - qenca = &phase_a; - qencb = &phase_b; - }; +#include "nrf54l15pdk_nrf54l15_common.dtsi" - encoder-emulate { - compatible = "gpio-leds"; - phase_a: phase_a { - gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; - }; - phase_b: phase_b { - gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; - }; - }; -}; - -&pinctrl { - qdec_pinctrl: qdec_pinctrl { - group1 { - psels = , - ; - }; - }; -}; - -&gpio1 { - status = "okay"; -}; - -&qdec20 { - status = "okay"; - pinctrl-0 = <&qdec_pinctrl>; - pinctrl-names = "default"; - steps = <127>; - led-pre = <500>; +/* To prevent enabling console receiver. */ +&uart30 { + disable-rx; }; diff --git a/tests/boards/nrf/qdec/boards/nrf54l15pdk_nrf54l15_common.dtsi b/tests/boards/nrf/qdec/boards/nrf54l15pdk_nrf54l15_common.dtsi new file mode 100644 index 00000000000..3fa426569b8 --- /dev/null +++ b/tests/boards/nrf/qdec/boards/nrf54l15pdk_nrf54l15_common.dtsi @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + qdec0 = &qdec20; + qenca = &phase_a; + qencb = &phase_b; + }; + + encoder-emulate { + compatible = "gpio-leds"; + phase_a: phase_a { + gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; + phase_b: phase_b { + gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&pinctrl { + qdec_pinctrl: qdec_pinctrl { + group1 { + psels = , + ; + }; + }; + + qdec_sleep_pinctrl: qdec_sleep_pinctrl { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&gpio1 { + status = "okay"; +}; + +&qdec20 { + status = "okay"; + pinctrl-0 = <&qdec_pinctrl>; + pinctrl-1 = <&qdec_sleep_pinctrl>; + pinctrl-names = "default", "sleep"; + steps = <127>; + led-pre = <500>; + zephyr,pm-device-runtime-auto; +}; diff --git a/tests/boards/nrf/qdec/src/main.c b/tests/boards/nrf/qdec/src/main.c index cccd92c3293..d87feb22f42 100644 --- a/tests/boards/nrf/qdec/src/main.c +++ b/tests/boards/nrf/qdec/src/main.c @@ -9,6 +9,7 @@ #include #include #include +#include static K_SEM_DEFINE(sem, 0, 1); static const struct gpio_dt_spec phase_a = GPIO_DT_SPEC_GET(DT_ALIAS(qenca), gpios); @@ -144,6 +145,10 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_and_disable) { int rc; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + qdec_trigger.type = SENSOR_TRIG_DATA_READY; qdec_trigger.chan = SENSOR_CHAN_ALL; rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); @@ -162,10 +167,18 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_and_disable) /* emulation not working, but there maybe old trigger, ignore */ rc = k_sem_take(&sem, K_MSEC(200)); + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } + /* there should be no triggers now*/ rc = k_sem_take(&sem, K_MSEC(200)); zassert_true(rc == -EAGAIN, "qdec handler should not be triggered (%d)", rc); + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + /* register empty trigger - disable trigger */ rc = sensor_trigger_set(qdec_dev, &qdec_trigger, NULL); zassert_true(rc == 0, "sensor_trigger_set failed: %d", rc); @@ -175,6 +188,10 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_and_disable) /* emulation working, but handler not set, thus should not be called */ rc = k_sem_take(&sem, K_MSEC(200)); zassert_true(rc == -EAGAIN, "qdec handler should not be triggered (%d)", rc); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } /** @@ -188,6 +205,10 @@ ZTEST(qdec_sensor, test_sensor_trigger_set) int rc; struct sensor_value val = {0}; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + qdec_trigger.type = SENSOR_TRIG_DATA_READY; qdec_trigger.chan = SENSOR_CHAN_ROTATION; rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); @@ -209,6 +230,10 @@ ZTEST(qdec_sensor, test_sensor_trigger_set) TC_PRINT("QDEC reading: %d\n", val.val1); zassert_true(val.val1 != 0, "No readings from QDEC"); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } /** @@ -221,6 +246,10 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_negative) { int rc; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); zassume_true(rc != -ENOSYS, "sensor_trigger_set not supported"); @@ -235,6 +264,10 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_negative) rc = sensor_trigger_set(qdec_dev, &qdec_trigger, qdec_trigger_handler); zassume_true(rc < 0, "sensor_trigger_set should fail due to invalid channel"); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } /** @@ -245,11 +278,19 @@ ZTEST(qdec_sensor, test_sensor_trigger_set_negative) */ ZTEST(qdec_sensor, test_qdec_readings) { + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + qenc_emulate_verify_reading(10, 100, true, false); qenc_emulate_verify_reading(2, 500, true, false); qenc_emulate_verify_reading(10, 200, false, false); qenc_emulate_verify_reading(1, 1000, false, true); qenc_emulate_verify_reading(1, 1000, true, true); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } /** @@ -263,6 +304,13 @@ ZTEST(qdec_sensor, test_sensor_channel_get_empty) int rc; struct sensor_value val = {0}; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + + /* wait for potential new readings */ + k_msleep(100); + rc = sensor_sample_fetch(qdec_dev); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); @@ -283,6 +331,10 @@ ZTEST(qdec_sensor, test_sensor_channel_get_empty) zassert_true(rc == 0, "Failed to get sample (%d)", rc); zassert_true(val.val1 == 0, "Expected no readings but got: %d", val.val1); zassert_true(val.val2 == 0, "Expected no readings but got: %d", val.val2); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } /** @@ -297,6 +349,10 @@ ZTEST(qdec_sensor, test_sensor_channel_get) struct sensor_value val_first = {0}; struct sensor_value val_second = {0}; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + qenc_emulate_start(K_MSEC(10), true); /* wait for some readings*/ @@ -328,6 +384,10 @@ ZTEST(qdec_sensor, test_sensor_channel_get) "Expected the same readings: %d vs %d", val_first.val2, val_second.val2); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } /** @@ -341,6 +401,10 @@ ZTEST(qdec_sensor, test_sensor_channel_get_negative) int rc; struct sensor_value val = {0}; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + qenc_emulate_start(K_MSEC(10), true); /* wait for some readings*/ @@ -353,6 +417,10 @@ ZTEST(qdec_sensor, test_sensor_channel_get_negative) zassert_true(rc < 0, "Should failed to get sample (%d)", rc); zassert_true(val.val1 == 0, "Some readings from QDEC: %d", val.val1); zassert_true(val.val2 == 0, "Some readings from QDEC: %d", val.val2); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } /** @@ -365,6 +433,10 @@ ZTEST(qdec_sensor, test_sensor_sample_fetch) { int rc; + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_get(qdec_dev); + } + rc = sensor_sample_fetch(qdec_dev); zassert_true(rc == 0, "Failed to fetch sample (%d)", rc); @@ -373,6 +445,10 @@ ZTEST(qdec_sensor, test_sensor_sample_fetch) rc = sensor_sample_fetch_chan(qdec_dev, SENSOR_CHAN_MAX); zassert_true(rc < 0, "Should fail to fetch sample from invalid channel (%d)", rc); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + pm_device_runtime_put(qdec_dev); + } } static void *setup(void) diff --git a/tests/boards/nrf/qdec/testcase.yaml b/tests/boards/nrf/qdec/testcase.yaml index 4bc634412db..26cfd9901a5 100644 --- a/tests/boards/nrf/qdec/testcase.yaml +++ b/tests/boards/nrf/qdec/testcase.yaml @@ -1,21 +1,31 @@ +common: + platform_allow: + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + - nrf54l15dk/nrf54l15/cpuapp + - nrf54l15dk/nrf54l15/cpuflpr + - nrf54h20dk/nrf54h20/cpuapp + integration_platforms: + - nrf52840dk/nrf52840 + - nrf5340dk/nrf5340/cpuapp + - nrf54l15dk/nrf54l15/cpuapp + - nrf54l15dk/nrf54l15/cpuflpr + - nrf54h20dk/nrf54h20/cpuapp + harness: ztest + harness_config: + fixture: gpio_loopback tests: drivers.sensor.qdec: tags: - drivers - sensors - qdec - platform_allow: - - nrf52840dk/nrf52840 - - nrf5340dk/nrf5340/cpuapp - - nrf54l15dk/nrf54l15/cpuapp - - nrf54l15dk/nrf54l15/cpuflpr - - nrf54h20dk/nrf54h20/cpuapp - integration_platforms: - - nrf52840dk/nrf52840 - - nrf5340dk/nrf5340/cpuapp - - nrf54l15dk/nrf54l15/cpuapp - - nrf54l15dk/nrf54l15/cpuflpr - - nrf54h20dk/nrf54h20/cpuapp - harness: ztest - harness_config: - fixture: gpio_loopback + drivers.sensor.qdec.pm_runtime: + tags: + - drivers + - sensors + - qdec + - pm + extra_configs: + - CONFIG_PM_DEVICE=y + - CONFIG_PM_DEVICE_RUNTIME=y