diff --git a/utils/tuning/libtuning/modules/ccm/__init__.py b/utils/tuning/libtuning/modules/ccm/__init__.py
new file mode 100644
index 00000000..a06c356c
--- /dev/null
+++ b/utils/tuning/libtuning/modules/ccm/__init__.py
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com>
+
+from libtuning.modules.ccm.ccm import CCM
+from libtuning.modules.ccm.rkisp1 import CTKRkISP1
diff --git a/utils/tuning/libtuning/modules/ccm/ccm.py b/utils/tuning/libtuning/modules/ccm/ccm.py
new file mode 100644
index 00000000..7ddf0a8c
--- /dev/null
+++ b/utils/tuning/libtuning/modules/ccm/ccm.py
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (C) 2019, Raspberry Pi Ltd
+# Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com>
+
+from ..module import Module
+
+import libtuning as lt
+import libtuning.utils as utils
+
+import numpy as np
+
+class CCM(Module):
+    type = 'ccm'
+    hr_name = 'CCM (Base)'
+    out_name = 'GenericCCM'
+
+    def __init__(self, *,
+                 debug: list):
+        super().__init__()
+
+        self.debug = debug
diff --git a/utils/tuning/libtuning/modules/ccm/rkisp1.py b/utils/tuning/libtuning/modules/ccm/rkisp1.py
new file mode 100644
index 00000000..5a6caea8
--- /dev/null
+++ b/utils/tuning/libtuning/modules/ccm/rkisp1.py
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (C) 2019, Raspberry Pi Ltd
+# Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com>
+#
+# rkisp1.py - Ctk module for tuning rkisp1
+
+from .ccm import CCM
+
+import libtuning as lt
+import libtuning.utils as utils
+
+from numbers import Number
+import numpy as np
+
+class CTKRkISP1(CCM):
+    hr_name = 'Crosstalk Correction (RkISP1)'
+    out_name = 'Ctk'
+    # \todo Not sure if this is useful. Probably will remove later.
+    compatible = ['rkisp1']
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+
+    # We don't actually need anything from the config file
+    def validate_config(self, config: dict) -> bool:
+        return True
+
+    def _float_to_fixed_4_7(self, d):
+        mask = 0xf
+        whole = int(d) & mask
+
+        fractional = d % 1
+        frac = 0
+        for i in range(0, 7):
+            fractional *= 2
+            frac <<= 1
+            frac |= int(fractional) & 0x1
+
+        return (whole << 7) | frac
+
+    def _generate_ctms(self) -> dict:
+        ctms = {
+                '2860': [ 2.12089, -0.52461, -0.59629,
+                         -0.85342,  2.80445, -0.95103,
+                         -0.26897, -1.14788,  2.41685 ],
+                '2960': [ 2.26962, -0.54174, -0.72789,
+                         -0.77008,  2.60271, -0.83262,
+                         -0.26036, -1.51254,  2.77289 ],
+                '3603': [ 2.18644, -0.66148, -0.52496,
+                         -0.77828,  2.69474, -0.91645,
+                         -0.25239, -0.83059,  2.08298 ],
+                '4650': [ 2.18174, -0.70887, -0.47287,
+                         -0.70196,  2.76426, -1.06231,
+                         -0.25157, -0.71978,  1.97135 ],
+                '5858': [ 2.32392, -0.88421, -0.43971,
+                         -0.63821,  2.58348, -0.94527,
+                         -0.28541, -0.54112,  1.82653 ],
+                '7580': [ 2.21175, -0.53242, -0.67933,
+                         -0.57875,  3.07922, -1.50047,
+                         -0.27709, -0.73338,  2.01048 ],
+                }
+
+        ret = {}
+        for ct in ctms:
+            ret[ct] = [self._float_to_fixed_4_7(weight) for weight in ctms[ct]]
+        return ret
+
+    def process(self, config: dict, images: list, outputs: dict) -> dict:
+        output = {}
+
+        output['ctms'] = self._generate_ctms()
+        # \todo Debug functionality
+
+        return output
