1# Copyright (c) 2022 Gerson Fernando Budke <nandojve@gmail.com> 2# Copyright (c) 2024 Microchip 3# SPDX-License-Identifier: Apache-2.0 4 5""" 6Utility to autogenerate pinctrl definitions. 7 8Usage:: 9 python3 pic32pinctrl.py [-i /path/to/configs] [-o /path/to/include] 10 11 python pic32pinctrl.py -i ../pinconfig -o ../include 12 13 py pic32pinctrl.py -i ../pinconfig -o ../include 14""" 15 16import argparse 17from collections import OrderedDict 18from pathlib import Path 19import re 20 21from natsort import natsorted 22import yaml 23 24 25REPO_ROOT = Path(__file__).absolute().parents[1] 26"""Repository root.""" 27 28HEADER = """/* 29 * Autogenerated file 30 * 31 * SPDX-License-Identifier: Apache-2.0 32 */ 33""" 34"""Header for the generated files.""" 35 36EXCEPTION = """ 37/* 38 * WARNING: this variant has package exception. 39 * 40 * Read datasheet topics related to I/O Multiplexing and Considerations or 41 * Peripheral Signal Multiplexing on I/O Lines for more information. 42 */ 43""" 44 45 46def get_header_fname(serie, variant, revision): 47 """Get header file name. 48 49 Args: 50 family: Microchip PIC32cxsg family. 51 serie: Series. 52 variant: Variant information. 53 54 Returns: 55 Header file name. 56 """ 57 58 sufix = "" 59 if revision: 60 sufix = f"X{revision}" 61 62 return f"pic32{serie}{variant}{sufix}-pinctrl.h" 63 64 65def get_port_pin(pin_name): 66 """Obtain port and pin number from a pin name 67 68 Args: 69 pin_name: Pin name, e.g. PA0 70 71 Returns: 72 Port and pin, e.g. A, 0. 73 """ 74 75 m = re.match(r"P([A-Z])(\d+)", pin_name.upper()) 76 if not m: 77 raise ValueError(f"Unexpected pin name: {pin_name}") 78 79 return m.group(1), str(int(m.group(2))) 80 81 82def write_gpio_function(f, port, pin_num, fmap, function): 83 f.write(f"\n/* p{port.lower()}{pin_num}_{function.lower()} */\n") 84 define = f"#define P{port.upper()}{pin_num.upper()}_{function.upper()}" 85 define_val = f"{fmap}({port.lower()}, {pin_num}, {function.lower()}, " \ 86 f"{function.lower()})" 87 f.write(f"{define} \\\n\t{define_val}\n") 88 89 90def write_wakeup_function(f, port, pin_num, pinmux, periph, 91 signal, fmap, function): 92 f.write(f"\n/* p{port.lower()}{pin_num}{pinmux}_{periph}_{signal} " 93 f"*/\n") 94 define = f"#define P{port.upper()}{pin_num.upper()}" \ 95 f"{pinmux.upper()}_{periph.upper()}_{signal.upper()}" 96 define_val = f"{fmap}({port.lower()}, {pin_num}, " \ 97 f"{signal.lower()}, {function.lower()})" 98 f.write(f"{define} \\\n\t{define_val}\n") 99 100 101def write_periph_function(f, port, pin_num, pinmux, periph, 102 signal, fmap, function): 103 f.write(f"\n/* p{port.lower()}{pin_num}{pinmux}_{periph}_{signal} " 104 f"*/\n") 105 define = f"#define P{port.upper()}{pin_num.upper()}" \ 106 f"{pinmux.upper()}_{periph.upper()}_{signal.upper()}" 107 define_val = f"{fmap}({port.lower()}, {pin_num}, " \ 108 f"{pinmux.lower()}, {function.lower()})" 109 f.write(f"{define} \\\n\t{define_val}\n") 110 111 112def generate_microchip_pic32_header(outdir, family, fmap, serie, 113 variant, pin_cfgs, revision): 114 """Generate Microchip PIC32 header with pin configurations. 115 116 Args: 117 outdir: Output base directory. 118 family: Microchip PIC32 family. 119 fmap: Function to map pinctrl. 120 series: MCU Series. 121 variant: Variant information. 122 pin_cfgs: Pin configurations. 123 """ 124 125 ofname = outdir / get_header_fname(serie, variant["pincode"], revision) 126 with open(ofname, "w") as f: 127 f.write(HEADER) 128 f.write(f'\n{"#include <dt-bindings/pinctrl/microchip_pic32cxsg_pinctrl.h>"}\n') 129 130 if len(variant) > 2: 131 if variant["exception"]: 132 f.write(EXCEPTION) 133 134 for port, pin_num, pinmux, periph, signal, function in pin_cfgs: 135 if function in ["gpio", "lpm"]: 136 write_gpio_function(f, port, pin_num, fmap, function) 137 continue 138 139 if function in ["wakeup"]: 140 write_wakeup_function(f, port, pin_num, pinmux, periph, 141 signal, fmap, function) 142 continue 143 144 write_periph_function(f, port, pin_num, pinmux, periph, 145 signal, fmap, function) 146 147 148def build_microchip_pic32_gpio_sets(pin_cfgs, pin): 149 """Build Microchip PIC32 pin configurations sets. 150 151 Args: 152 pins: Pins description. 153 154 Returns: 155 Dictionary with pins configuration. 156 """ 157 158 port, pin_num = get_port_pin(pin) 159 new_item = (port, pin_num, "a", "gpio", "gpio", "gpio") 160 161 if new_item not in pin_cfgs: 162 pin_cfgs.append(new_item) 163 164 165def build_microchip_pic32_sets(pin_cfgs, pin, pin_lst, serie, variant, function): 166 """Build Microchip PIC32 pin configurations sets. 167 168 Args: 169 serie: MCU Serie. 170 variant: Variant information. 171 pins: Pins description. 172 173 Returns: 174 Dictionary with pins configuration. 175 """ 176 177 if len(pin_lst[0]) > 0: 178 for pinmux, periph, signal, *excludes in pin_lst: 179 if len(excludes) > 0: 180 if serie in excludes[0]: 181 continue 182 if variant["pincode"] in excludes[0]: 183 continue 184 185 port, pin_num = get_port_pin(pin) 186 187 pin_cfgs.append((port, pin_num, pinmux, periph, signal, function)) 188 189 190def build_microchip_pic32_pin_cfgs(serie, variant, pins): 191 """Build Microchip PIC32 pin configurations. 192 193 Args: 194 serie: MCU Serie. 195 variant: Variant information. 196 pins: Pins description. 197 198 Returns: 199 Dictionary with pins configuration. 200 """ 201 202 pin_cfgs = [] 203 204 pins = OrderedDict(natsorted(pins.items(), key=lambda kv: kv[0])) 205 206 for pin, pin_cfg in pins.items(): 207 if variant["pincode"] not in pin_cfg["pincodes"]: 208 continue 209 210 build_microchip_pic32_gpio_sets(pin_cfgs, pin) 211 212 if "periph" in pin_cfg.keys(): 213 build_microchip_pic32_sets(pin_cfgs, pin, pin_cfg["periph"], 214 serie, variant, "periph") 215 if "extra" in pin_cfg.keys(): 216 build_microchip_pic32_sets(pin_cfgs, pin, pin_cfg["extra"], 217 serie, variant, "extra") 218 if "system" in pin_cfg.keys(): 219 build_microchip_pic32_sets(pin_cfgs, pin, pin_cfg["system"], 220 serie, variant, "system") 221 if "lpm" in pin_cfg.keys(): 222 build_microchip_pic32_sets(pin_cfgs, pin, pin_cfg["lpm"], 223 serie, variant, "lpm") 224 if "wakeup" in pin_cfg.keys(): 225 build_microchip_pic32_sets(pin_cfgs, pin, pin_cfg["wakeup"], 226 serie, variant, "wakeup") 227 228 return pin_cfgs 229 230 231def main(indir, outdir) -> None: 232 """Entry point. 233 234 Args: 235 indir: Directory with pin configuration files. 236 outdir: Output directory 237 """ 238 239 if outdir.exists(): 240 for entry in outdir.glob("pic32*-pinctrl.h"): 241 entry.unlink() 242 else: 243 outdir.mkdir() 244 245 for entry in indir.iterdir(): 246 if not entry.is_file() or entry.suffix not in (".yml", ".yaml"): 247 continue 248 249 config = yaml.load(open(entry), Loader=yaml.Loader) 250 251 model = config["model"] 252 family = config["family"] 253 fmap = config["map"] 254 series = config["series"] 255 variants = config["variants"] 256 has_rev = "revisions" in config.keys() 257 pins = config["pins"] 258 259 if model == "microchip,pic32": 260 for serie in series: 261 for variant in [v for v in variants if serie in v["series"]]: 262 pin_cfgs = build_microchip_pic32_pin_cfgs(serie, variant, pins) 263 rev = config["revisions"].get(serie) if has_rev else None 264 generate_microchip_pic32_header(outdir, family, fmap, serie, 265 variant, pin_cfgs, rev) 266 else: 267 raise ValueError(f"Unexpected model: {model}") 268 269 270if __name__ == "__main__": 271 parser = argparse.ArgumentParser() 272 parser.add_argument( 273 "-i", 274 "--indir", 275 type=Path, 276 default=REPO_ROOT / "pinconfigs", 277 help="Directory with pin configuration files", 278 ) 279 parser.add_argument( 280 "-o", 281 "--outdir", 282 type=Path, 283 default=REPO_ROOT / "include" / "dt-bindings" / "pinctrl", 284 help="Output directory", 285 ) 286 args = parser.parse_args() 287 288 main(args.indir, args.outdir) 289