1#!/usr/bin/env python3 2# 3# Copyright (c) 2022 Kumar Gala <galak@kernel.org> 4# Copyright (c) 2025 Nordic Semiconductor ASA 5# 6# SPDX-License-Identifier: Apache-2.0 7 8import argparse 9import os 10 11import yaml 12try: 13 # Use the C LibYAML parser if available, rather than the Python parser. 14 from yaml import CSafeLoader as SafeLoader 15except ImportError: 16 from yaml import SafeLoader # type: ignore 17 18 19HEADER = """\ 20# Generated devicetree Kconfig 21# 22# SPDX-License-Identifier: Apache-2.0""" 23 24 25KCONFIG_TEMPLATE = """ 26DT_COMPAT_{COMPAT} := {compat} 27 28config DT_HAS_{COMPAT}_ENABLED 29\tdef_bool $(dt_compat_enabled,$(DT_COMPAT_{COMPAT}))""" 30 31 32# Character translation table used to derive Kconfig symbol names 33TO_UNDERSCORES = str.maketrans("-,.@/+", "______") 34 35 36def binding_paths(bindings_dirs): 37 # Yields paths to all bindings (.yaml files) in 'bindings_dirs' 38 39 for bindings_dir in bindings_dirs: 40 for root, _, filenames in os.walk(bindings_dir): 41 for filename in filenames: 42 if filename.endswith((".yaml", ".yml")): 43 yield os.path.join(root, filename) 44 45 46def parse_args(): 47 # Returns parsed command-line arguments 48 49 parser = argparse.ArgumentParser(allow_abbrev=False) 50 parser.add_argument("--kconfig-out", required=True, 51 help="path to write the Kconfig file") 52 parser.add_argument("--bindings-dirs", nargs='+', required=True, 53 help="directory with bindings in YAML format, " 54 "we allow multiple") 55 56 return parser.parse_args() 57 58 59def main(): 60 args = parse_args() 61 62 compats = set() 63 64 for binding_path in binding_paths(args.bindings_dirs): 65 with open(binding_path, encoding="utf-8") as f: 66 try: 67 # Parsed PyYAML representation graph. For our purpose, 68 # we don't need the whole file converted into a dict. 69 root = yaml.compose(f, Loader=SafeLoader) 70 except yaml.YAMLError as e: 71 print(f"WARNING: '{binding_path}' appears in binding " 72 f"directories but isn't valid YAML: {e}") 73 continue 74 75 if not isinstance(root, yaml.MappingNode): 76 continue 77 for key, node in root.value: 78 if key.value == "compatible" and isinstance(node, yaml.ScalarNode): 79 compats.add(node.value) 80 break 81 82 with open(args.kconfig_out, "w", encoding="utf-8") as kconfig_file: 83 print(HEADER, file=kconfig_file) 84 85 for c in sorted(compats): 86 out = KCONFIG_TEMPLATE.format( 87 compat=c, COMPAT=c.upper().translate(TO_UNDERSCORES) 88 ) 89 print(out, file=kconfig_file) 90 91 92if __name__ == "__main__": 93 main() 94