Initial excelsior-tools package and pinout util

- Debian metadata for the excelsior-tools package
- pinout tool, ported from the IMX platform with updated pin definitions
for Excelsior.

Change-Id: I5bb0a6a1846532e0bc46f45f4b63d70ba61955a3
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..c829e7f
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,6 @@
+excelsior-tools (1-1) mendel-eagle; urgency=medium
+
+  * Initial release.
+  * pinout tool.
+
+ -- Coral Team <coral-support@google.com>  Tue, 25 Aug 2020 11:07:10 -0700
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..2ca97ad
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,15 @@
+Source: excelsior-tools
+Section: misc
+Priority: optional
+Maintainer: Coral Team <coral-support@google.com>
+Build-Depends: debhelper (>=10)
+Standards-Version: 3.9.8
+Homepage: https://coral.ai
+
+Package: excelsior-tools
+Architecture: any
+Depends: python3,
+         ${misc:Depends}
+Description: Miscellaneous tools for Excelsior
+ General scripts for use and management of
+ Coral MT8516 (Excelsior)
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..dacc16a
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,7 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: excelsior-bootloader
+Source: https://excelsior.googlesource.com/excelsior-bootloader
+
+Files: *
+Copyright: Copyright 2020 Google, LLC <coral-support@google.com>
+License: Apache-2.0
diff --git a/debian/excelsior-tools.install b/debian/excelsior-tools.install
new file mode 100644
index 0000000..6422483
--- /dev/null
+++ b/debian/excelsior-tools.install
@@ -0,0 +1 @@
+pinout /usr/bin
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..ebc65f0
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,10 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+#
+# output every command that modifies files on the build system.
+# export DH_VERBOSE = 1
+PACKAGENAME=excelsior-tools
+DESTDIR=$(shell pwd)/debian/$(PACKAGENAME)
+
+%:
+	dh $@
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/pinout b/pinout
new file mode 100755
index 0000000..c21ce74
--- /dev/null
+++ b/pinout
@@ -0,0 +1,126 @@
+#!/usr/bin/env python3
+
+# Copyright 2018-2020 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+
+class Style:
+    BOLD      = 1
+    DEFAULT   = 39
+    RED       = 31
+    GREEN     = 32
+    YELLOW    = 33
+    BLUE      = 34
+    MAGENTA   = 35
+    CYAN      = 36
+    DARK_GRAY = 90
+
+class Kind:
+    GND, POWER, I2C, UART, GPIO, SAI, SPI, PWM = range(8)
+
+KINDS = {
+    Kind.GND:   (Style.DARK_GRAY, 'GND',   'Ground'),
+    Kind.POWER: (Style.RED,       'POWER', 'Power: +5V or +3.3V'),
+    Kind.I2C:   (Style.GREEN,     'I2C',   'Inter-Integrated Circuit [/dev/i2c-N]'),
+    Kind.UART:  (Style.MAGENTA,   'UART',  'Serial Port [/dev/ttySN]'),
+    Kind.GPIO:  (Style.DEFAULT,   'GPIO',  'General Purpose Input Output [/sys/class/gpio/gpioN]'),
+    Kind.SAI:   (Style.CYAN,      'SAI',   'Synchronous Audio Interface'),
+    Kind.SPI:   (Style.BLUE,      'SPI',   'Serial Peripheral Interface [/dev/spidevN.N]'),
+    Kind.PWM:   (Style.YELLOW,    'PWM',   'Pulse Width Modulation [/sys/class/pwm/pwmchipN/pwm0]'),
+}
+
+PINS = {
+    1:  ('3.3.V',                     Kind.POWER), 2:  ('5V',                       Kind.POWER),
+    3:  ('I2C1_SDA (i2c-2)',          Kind.I2C),   4:  ('5V',                       Kind.POWER),
+    5:  ('I2C1_SCL (i2c-2)',          Kind.I2C),   6:  ('GND',                      Kind.GND),
+    7:  ('GPIO (gpio409)',            Kind.GPIO),  8:  ('UART0_TX (ttyS0)',         Kind.UART),
+    9:  ('GND',                       Kind.GND),   10: ('UART0_RX (ttyS0)',         Kind.UART),
+    11: ('GPIO (gpio396)',            Kind.GPIO),  12: ('GPIO (gpio423) / I2S_BCK', Kind.SAI),
+    13: ('GPIO (gpio397)',            Kind.GPIO),  14: ('GND',                      Kind.GND),
+    15: ('PWM (pwmchip0.2)',          Kind.PWM),   16: ('GPIO (gpio387)',           Kind.GPIO),
+    17: ('3.3V',                      Kind.POWER), 18: ('GPIO (gpio399)',           Kind.GPIO),
+    19: ('SPI_MOSI (spidev0)',        Kind.SPI),   20: ('GND',                      Kind.GND),
+    21: ('SPI_MISO (spidev0)',        Kind.SPI),   22: ('GPIO (gpio394)',           Kind.GPIO),
+    23: ('SPI_SCLK (spidev0)',        Kind.SPI),   24: ('SPI_CSB (spidev0.0)',      Kind.SPI),
+    25: ('GND',                       Kind.GND),   26: ('GPIO (gpio395)',           Kind.GPIO),
+    27: ('I2C2_SDA (i2c-3)',          Kind.I2C),   28: ('I2C2_SCL (i2c-3)',         Kind.I2C),
+    29: ('UART1_TX (ttyS1)',          Kind.UART),  30: ('GND',                      Kind.GND),
+    31: ('UART1_RX (ttyS1)',          Kind.UART),  32: ('PWM (pwmchip0.0)',         Kind.PWM),
+    33: ('PWM (pwmchip0.1)',          Kind.PWM),   34: ('GND',                      Kind.GND),
+    35: ('GPIO (gpio424) / I2S_LRCK', Kind.SAI),   36: ('GPIO (gpio400)',           Kind.GPIO),
+    37: ('GPIO (gpio432)',            Kind.GPIO),  38: ('GPIO (gpio425) / I2S_DO',  Kind.SAI),
+    39: ('GND',                       Kind.GND),   40: ('GPIO (gpio426) / I2S_MCK', Kind.SAI)
+}
+
+assert(len(PINS) % 2 == 0)
+assert(set(PINS.keys()) == set(range(1, len(PINS) + 1)))
+
+def pins():
+    for i in range(len(PINS) // 2):
+        yield (2 * i + 1, 2 * i + 2)
+
+def pin_desc(pin):
+    text, _ = PINS[pin]
+    return text
+
+def pin_kind(pin):
+    _, kind = PINS[pin]
+    return kind
+
+def stylize(text, style, esc='\033['):
+    return '%s%dm%s%s0m' % (esc, style, text, esc)
+
+def stylize_pin(text, pin):
+    style, _, _ = KINDS[pin_kind(pin)]
+    return stylize(text, style)
+
+def print_pinout(color):
+    max_len = max(len(pin_desc(l)) for l, _ in pins())
+
+    for l, r in pins():
+        l_pin, r_pin = str(l).ljust(2), str(r).rjust(2)
+        l_txt, r_txt = pin_desc(l).rjust(max_len), pin_desc(r)
+
+        if color:
+            l_pin = stylize(l_pin, Style.BOLD)
+            r_pin = stylize(r_pin, Style.BOLD)
+            l_txt, r_txt = stylize_pin(l_txt, l), stylize_pin(r_txt, r)
+
+        print('%s -> %s  %s <- %s' % (l_txt, l_pin, r_pin, r_txt))
+
+def print_legend(color):
+    max_len = max(len(name) for _, (_, name, _) in KINDS.items())
+
+    for kind, (style, name, desc) in KINDS.items():
+        txt = name.ljust(max_len)
+        if color:
+            txt = stylize(txt, style)
+        print('%s - %s' % (txt, desc))
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--nocolor', dest='color', action='store_false',
+                        default=True, help='Do not output in color.')
+    parser.add_argument('--nolegend', dest='legend', action='store_false',
+                        default=True, help='Do not output legend.')
+    args = parser.parse_args()
+
+    print_pinout(args.color)
+    if args.legend:
+        print()
+        print_legend(args.color)
+
+if __name__ == '__main__':
+    main()