1#!/usr/bin/python3
2# Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
3# SPDX-License-Identifier: Apache-2.0
4
5import os
6import sys
7import yaml
8import argparse
9from pathlib import Path
10from datetime import datetime
11
12current_year = datetime.now().year
13
14file_out_head = f'''/*
15 * Copyright (c) {current_year} Espressif Systems (Shanghai) Co., Ltd.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 *
19 * NOTE: Autogenerated file using esp_genpinctrl.py
20 */
21
22#ifndef INC_DT_BINDS_PINCTRL_''' + '''{SOC}''' + '''_PINCTRL_HAL_H_
23#define INC_DT_BINDS_PINCTRL_''' + '''{SOC}''' + '''_PINCTRL_HAL_H_
24
25'''
26
27file_out_tail = '''
28#endif /* INC_DT_BINDS_PINCTRL_{SOC}_PINCTRL_HAL_H_ */
29'''
30
31file_out_path = 'include/zephyr/dt-bindings/pinctrl/'
32file_out_temp = '{SOC}-pinctrl-temp.h'
33file_out_name = '{SOC}-pinctrl.h'
34file_tmp_abs = ''
35
36line_comment = ''
37
38
39def err(source, msg):
40    global file_tmp_abs
41    os.remove(file_tmp_abs)
42    sys.exit('ERR(' + source + '):' + msg)
43
44
45def get_pin_ios(pins):
46    ios = []
47    for io in pins:
48        if type(io) is int:
49            ios.append(io)
50        elif type(io) is list and io.__len__() == 2:
51            for io_num in range(io[0], 1 + io[1]):
52                ios.append(io_num)
53        else:
54            err('gpio', 'bad type / wrong list size')
55
56    return ios
57
58
59def get_gpios(pin_info):
60    if 'gpio' in pin_info:
61        return get_pin_ios(pin_info.get('gpio'))
62    else:
63        err('gpio', 'missing property')
64
65
66def get_pin_sigi(pin_info):
67    sigi = 'ESP_'
68    if 'sigi' in pin_info:
69        sigi = sigi + pin_info['sigi'].upper()
70    else:
71        sigi = sigi + 'NOSIG'
72
73    return sigi
74
75
76def get_pin_sigo(pin_info):
77    sigo = 'ESP_'
78    if 'sigo' in pin_info:
79        sigo = sigo + pin_info['sigo'].upper()
80    else:
81        sigo = sigo + 'NOSIG'
82
83    return sigo
84
85
86def get_pinmux(dev_name, pin_name, pin_info, io):
87    sigi = get_pin_sigi(pin_info)
88    sigo = get_pin_sigo(pin_info)
89    global line_comment
90
91    pinmux = dev_name.upper() + '_' + pin_name.upper() + '_GPIO' + str(io)
92    define_str = '#define ' + pinmux
93    macro_str = 'ESP32_PINMUX(' + str(io) + ', ' + sigi + ', ' + sigo + ')'
94
95    if len(define_str + ' ' + macro_str) > 100:
96        # print in two lines
97        pinmux = define_str + ' \\\n\t' + macro_str + '\n\n'
98    else:
99        pinmux = define_str + ' ' + macro_str + '\n\n'
100
101    if bool(line_comment):
102        pinmux = line_comment + pinmux
103        line_comment = ''
104
105    return pinmux
106
107
108def main(pcfg_in):
109    zephyr_base = os.getenv('ZEPHYR_BASE')
110
111    if zephyr_base is None:
112        print("Missing ZEPHYR_BASE environment variable")
113        exit()
114
115    print("Zephyr Base: ", zephyr_base)
116
117    stream = open(pcfg_in, 'r')
118    pcfg_data = yaml.load(stream, Loader=yaml.FullLoader)
119    soc = os.path.basename(pcfg_in).replace('.yml', '')
120
121    file_out_abs = Path(zephyr_base, file_out_path + soc + '-pinctrl.h')
122    global file_tmp_abs
123    file_tmp_abs = Path(zephyr_base, file_out_path + soc + '-pinctrl-temp.h')
124
125    # sorts by dev name, which keeps git
126    # diffs minimal and easily trackable
127    all_data = sorted(pcfg_data.items())
128
129    f = open(file_tmp_abs, 'w')
130    f.write(file_out_head.replace('{SOC}', soc.upper()))
131
132    for (dev_name, dev_info) in all_data:
133
134        # sorts by pin name, which keeps git
135        # diffs minimal and easily trackable
136        dev_info = sorted(dev_info.items())
137
138        for (pin_name, pin_info) in dev_info:
139            global line_comment
140            line_comment = '/* ' + dev_name.upper() + '_' + pin_name.upper() + ' */\n'
141            ios = get_gpios(pin_info)
142            for io in ios:
143                pinmux = get_pinmux(dev_name, pin_name, pin_info, io)
144                f.write(pinmux)
145
146    f.write(file_out_tail.replace('{SOC}', soc.upper()))
147    f.close()
148
149    if os.path.exists(file_out_abs):
150        os.remove(file_out_abs)
151
152    os.rename(file_tmp_abs, file_out_abs)
153
154    print("Output file: ", file_out_abs)
155
156
157if __name__ == '__main__':
158    parser = argparse.ArgumentParser()
159    parser.add_argument(
160        '-p',
161        '--path',
162        type=Path,
163        required=True,
164        help='Path to target file',
165    )
166    args = parser.parse_args()
167
168    main(args.path)
169