diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000000000000000000000000000000000000..72604f6ae8bdb65b88f4bef646e249ac4494ba9b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# (Adapted from the Linux kernel sources)
+#
+# clang-format configuration file. Intended for clang-format >= 4.
+#
+# For more information, see:
+#
+#   Documentation/process/clang-format.rst
+#   https://clang.llvm.org/docs/ClangFormat.html
+#   https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+#
+---
+AccessModifierOffset: -4
+AlignAfterOpenBracket: AlwaysBreak
+AlignConsecutiveAssignments: true
+AlignConsecutiveDeclarations: false
+#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+# AllowAllArgumentsOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+  AfterClass: false
+  AfterControlStatement: false
+  AfterEnum: false
+  AfterFunction: true
+  AfterNamespace: true
+  AfterObjCDeclaration: false
+  AfterStruct: false
+  AfterUnion: false
+  #AfterExternBlock: false # Unknown to clang-format-5.0
+  BeforeCatch: false
+  BeforeElse: false
+  IndentBraces: false
+  #SplitEmptyFunction: true # Unknown to clang-format-4.0
+  #SplitEmptyRecord: true # Unknown to clang-format-4.0
+  #SplitEmptyNamespace: true # Unknown to clang-format-4.0
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: false
+#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+#CompactNamespaces: false # Unknown to clang-format-4.0
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+#FixNamespaceComments: false # Unknown to clang-format-4.0
+
+#IncludeBlocks: Preserve # Unknown to clang-format-5.0
+IncludeCategories:
+  - Regex: '.*'
+    Priority: 1
+IncludeIsMainRegex: '(Test)?$'
+IndentCaseLabels: false
+#IndentPPDirectives: None # Unknown to clang-format-5.0
+IndentWidth: 8
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: Inner
+#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
+ObjCBlockIndentWidth: 8
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+
+# Taken from git's rules
+#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
+PenaltyBreakBeforeFirstCallParameter: 30
+PenaltyBreakComment: 10
+PenaltyBreakFirstLessLess: 0
+PenaltyBreakString: 10
+PenaltyExcessCharacter: 100
+PenaltyReturnTypeOnItsOwnLine: 60
+
+PointerAlignment: Right
+ReflowComments: false
+SortIncludes: false
+#SortUsingDeclarations: false # Unknown to clang-format-4.0
+SpaceAfterCStyleCast: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
+#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
+SpaceBeforeParens: ControlStatements
+#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp03
+TabWidth: 8
+UseTab: ForContinuationAndIndentation
+...
diff --git a/tools/code-style.sh b/tools/code-style.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ee1cd11ec42c5874fa4ba84854ffba543e764f3f
--- /dev/null
+++ b/tools/code-style.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+set -e
+
+# Check tools
+if ! command -v clang-format >/dev/null 2>&1; then
+    echo "$0: requires clang-format." >&2
+    exit 127
+fi
+
+if ! command -v python3 >/dev/null 2>&1; then
+    echo "$0: requires python3." >&2
+    exit 127
+fi
+
+script_dir="$(dirname "$0")"
+
+for source_file in "$@"; do
+    echo "Formatting $source_file ..."
+    clang-format -i "$source_file"
+    python3 "$script_dir/fix-multi-decl.py" "$source_file"
+done
diff --git a/tools/fix-multi-decl.py b/tools/fix-multi-decl.py
new file mode 100644
index 0000000000000000000000000000000000000000..960b9b36d4d1b0ff349f3e2df68ce716e67b0a67
--- /dev/null
+++ b/tools/fix-multi-decl.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+#
+# I prefer to have the closing brace of a multi-line declaration or function call on its
+# own line.  This is unfortunately not yet supported by clang-format.  This script is
+# a hack to manually introduce my style.
+#
+# Tracking for this style in clang-format: https://reviews.llvm.org/D33029
+#
+# Example
+# =======
+# This is the style I want:
+#
+#     printf(
+#         "Hello %s %d\n",
+#         "World",
+#         123
+#     );
+import re
+import sys
+
+EXPR = r"""                         # Indentation is saved to <ws>
+^(?P<ws>[ \t]*)(?P<decl>.*\(\n      # Opening line, ending with (\n
+    (?:.*,\n)*                      # Lines with arguments, all ending with ,\n
+    .*)\)(?P<final>[); \t]*)\n      # Last line with closing brace & optional following characters
+(?![ \t]*\).*)                      # Don't match an already expanded decl
+"""
+
+
+def main():
+    with open(sys.argv[1], "r") as f:
+        source = f.read()
+
+    fixed = re.sub(
+        EXPR,
+        r"\g<ws>\g<decl>\n\g<ws>)\g<final>\n",
+        source,
+        flags=re.MULTILINE | re.VERBOSE,
+    )
+
+    # Fix function definitions that can now be pulled into one line
+    fixed = re.sub(
+        r"^\)\n{$",
+        r") {",
+        fixed,
+        flags=re.MULTILINE,
+    )
+
+    with open(sys.argv[1], "w") as f:
+        f.write(fixed)
+
+
+if __name__ == "__main__":
+    main()