diff --git a/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py index 556aec0cccb..403bd2fd94e 100644 --- a/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py +++ b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py @@ -24,6 +24,7 @@ MINIMUM_RAM_SIZE, add_toml_pin_names, _toml_status_pin, + _dynamically_routable, ) @@ -796,3 +797,50 @@ def test_absent_key_is_none(self): def test_unknown_name_raises(self): with pytest.raises(RuntimeError, match="STATUS_NEOPIXEL = 'NOPE' is not a board pin name"): _toml_status_pin({"STATUS_NEOPIXEL": "NOPE"}, self.BOARD_NAMES, "STATUS_NEOPIXEL") + + +class TestDynamicallyRoutable: + """Test suite for _dynamically_routable function.""" + + def _bus(self, group): + dts = f""" +/dts-v1/; + +/ {{ + pinctrl {{ + bus_default: bus_default {{ + group1 {{ + {group} + }}; + }}; + }}; + + bus: bus@1000 {{ + reg = <0x1000 0x100>; + pinctrl-0 = <&bus_default>; + pinctrl-names = "default"; + }}; +}}; +""" + return parse_dts_string(dts).label2node["bus"] + + def test_nrf_all_disconnected(self): + assert _dynamically_routable(self._bus("psels = <0x0b0001ff 0x0c0001ff>;")) + + def test_nrf_connected(self): + assert not _dynamically_routable(self._bus("psels = <0x0b00000a 0x0c0001ff>;")) + + def test_pinmux_without_psels(self): + assert not _dynamically_routable(self._bus("pinmux = <0x1234 0x5678>;")) + + def test_no_pinctrl(self): + dts = """ +/dts-v1/; + +/ { + bus: bus@1000 { + reg = <0x1000 0x100>; + }; +}; +""" + assert not _dynamically_routable(parse_dts_string(dts).label2node["bus"]) diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 660b263262f..ee813ba4883 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -550,6 +550,17 @@ def _pinctrl_default_psels(node): return psels +def _dynamically_routable(node): + """Return True when every nRF psel in the node's default pinctrl state is + disconnected. Pinctrl states on other SoCs have no psels, so their buses + keep the pins the devicetree gives them. + """ + psels = _pinctrl_default_psels(node) + return bool(psels) and all( + (value & NRF_PIN_FIELD_MASK) == NRF_PIN_FIELD_MASK for value in psels + ) + + def _populate_input_key_names(): header = ( pathlib.Path(__file__).parent.parent @@ -1300,11 +1311,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig iobroker_labels = set() for driver in BUSIO_CLASSES: for labels in active_zephyr_devices.get(driver, []): - node = device_tree.label2node[labels[0]] - psels = _pinctrl_default_psels(node) - if psels is not None and all( - (value & NRF_PIN_FIELD_MASK) == NRF_PIN_FIELD_MASK for value in psels - ): + if _dynamically_routable(device_tree.label2node[labels[0]]): iobroker_labels.add(labels[0]) zephyr_binding_headers = []