diff --git a/meson.build b/meson.build
index 748a1b3a..b80f7ee8 100644
--- a/meson.build
+++ b/meson.build
@@ -220,6 +220,7 @@ stm32f405_src = ['platform/mcu/STM32F4xx/boot/startup.cpp',
'platform/drivers/audio/stm32_dac.cpp',
'platform/drivers/audio/stm32_adc.cpp',
'platform/drivers/audio/stm32_pwm.cpp',
+ 'platform/drivers/keyboard/cap1206.c',
'platform/mcu/CMSIS/Device/ST/STM32F4xx/Source/system_stm32f4xx.c']
stm32f405_inc = ['platform/mcu/CMSIS/Include',
diff --git a/platform/drivers/keyboard/cap1206.c b/platform/drivers/keyboard/cap1206.c
new file mode 100644
index 00000000..bd137772
--- /dev/null
+++ b/platform/drivers/keyboard/cap1206.c
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * Copyright (C) 2024 by Morgan Diepart ON4MOD *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include "cap1206.h"
+#include "cap1206_regs.h"
+
+int cap1206_init(const struct i2cDevice *i2c)
+{
+ uint8_t data[2];
+ int ret;
+
+ i2c_acquire(i2c);
+
+ // Config 1 register, enable SMB timeout
+ data[0] = CAP1206_CONFIG_1;
+ data[1] = CAP1206_CONFIG_1_TIMEOUT | CAP1206_CONFIG_1_DIS_DIG_NOISE;
+ ret = i2c_write(i2c, CAP1206_ADDR, data, 2, true);
+ if(ret < 0)
+ {
+ i2c_release(i2c);
+ return ret;
+ }
+
+ // Disable touch repetition
+ data[0] = CAP1206_RPT_EN;
+ data[1] = 0;
+ ret = i2c_write(i2c, CAP1206_ADDR, data, 2, true);
+ if(ret < 0)
+ {
+ i2c_release(i2c);
+ return ret;
+ }
+
+ // Reduce the sensitivity from x32 (default) to x8
+ data[0] = CAP1206_SENS_CTRL;
+ data[1] = CAP1206_SENS_CTRL_dSENSE_x8 | CAP1206_SENS_CTRL_BASE_SHIFT_x256;
+ ret = i2c_write(i2c, CAP1206_ADDR, data, 2, true);
+
+ i2c_release(i2c);
+ return ret;
+}
+
+int cap1206_readkeys(const struct i2cDevice *i2c)
+{
+ uint8_t cmd[2];
+ uint8_t keyStatus;
+ int ret;
+
+ i2c_acquire(i2c);
+
+ cmd[0] = CAP1206_SENSOR_IN_STATUS;
+ ret = i2c_write(i2c, CAP1206_ADDR, cmd, 1, false);
+ if(ret < 0)
+ {
+ i2c_release(i2c);
+ return ret;
+ }
+
+ ret = i2c_read(i2c, CAP1206_ADDR, &keyStatus, 1, true);
+ if(ret < 0)
+ {
+ i2c_release(i2c);
+ return ret;
+ }
+
+ cmd[0] = CAP1206_MAIN_CTRL;
+ cmd[1] = 0x00;
+ ret = i2c_write(i2c, CAP1206_ADDR, cmd, 2, false);
+ i2c_release(i2c);
+
+ if(ret < 0)
+ return ret;
+
+ return keyStatus;
+}
diff --git a/platform/drivers/keyboard/cap1206.h b/platform/drivers/keyboard/cap1206.h
new file mode 100644
index 00000000..06d4c6ae
--- /dev/null
+++ b/platform/drivers/keyboard/cap1206.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2024 by Morgan Diepart ON4MOD *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef CAP1206_H
+#define CAP1206_H
+
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Initialize the CAP1206 device.
+ *
+ * @param i2c: driver managing the I2C bus the chip is connected to.
+ * @return zero on success, a negative error code otherwise.
+ */
+int cap1206_init(const struct i2cDevice *i2c);
+
+/**
+ * Read the status of the touch keys connected to the CAP1206 device.
+ *
+ * @param i2c: driver managing the I2C bus the chip is connected to.
+ * @return a bitmap representing the status of the keys or a negative error code.
+ */
+int cap1206_readkeys(const struct i2cDevice *i2c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAP1206_H */
+
diff --git a/platform/drivers/keyboard/cap1206_regs.h b/platform/drivers/keyboard/cap1206_regs.h
new file mode 100644
index 00000000..ff90d8d7
--- /dev/null
+++ b/platform/drivers/keyboard/cap1206_regs.h
@@ -0,0 +1,258 @@
+/***************************************************************************
+ * Copyright (C) 2024 by Morgan Diepart ON4MOD *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef CAP1206_REGS_H
+#define CAP1206_REGS_H
+
+
+#define CAP1206_ADDR 0x28 /* 7 bits address */
+#define CAP1206_PRODUCT_ID 0xFD
+#define CAP1206_VENDOR_ID 0x5D
+#define CAP1206_REVISION 0xFF
+
+/* Registers */
+#define CAP1206_MAIN_CTRL 0x00
+#define CAP1206_MAIN_CTRL_STBY (1 << 5)
+#define CAP1206_MAIN_CTRL_DSLEEP (1 << 4)
+#define CAP1206_MAIN_CTRL_INT (1 << 0)
+
+#define CAP1206_GEN_STATUS 0x02
+#define CAP1206_GEN_STATUS_BC_OUT (1 << 6)
+#define CAP1206_GEN_STATUS_ACAL_FAIL (1 << 5)
+#define CAP1206_GEN_STATUS_PWR (1 << 4)
+#define CAP1206_GEN_STATUS_MULT (1 << 2)
+#define CAP1206_GEN_STATUS_MTP (1 << 1)
+#define CAP1206_GEN_STATUS_TOUCH (1 << 0)
+
+#define CAP1206_SENSOR_IN_STATUS 0x03
+#define CAP1206_SENSOR_IN_STATUS_CS(x) (1 << (x-1))
+
+#define CAP1206_NOISE_FLAG 0x0A
+#define CAP1206_NOISE_FLAG_CS_NOISE(x) (1 << (x-1))
+
+#define CAP1206_IN_dCNT(x) (0x0F + x)
+
+#define CAP1206_SENS_CTRL 0x1F
+#define CAP1206_SENS_CTRL_dSENSE_x128 (0 << 4)
+#define CAP1206_SENS_CTRL_dSENSE_x64 (1 << 4)
+#define CAP1206_SENS_CTRL_dSENSE_x32 (2 << 4)
+#define CAP1206_SENS_CTRL_dSENSE_x16 (3 << 4)
+#define CAP1206_SENS_CTRL_dSENSE_x8 (4 << 4)
+#define CAP1206_SENS_CTRL_dSENSE_x4 (5 << 4)
+#define CAP1206_SENS_CTRL_dSENSE_x2 (6 << 4)
+#define CAP1206_SENS_CTRL_dSENSE_x1 (7 << 4)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x1 (0 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x2 (1 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x4 (2 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x8 (3 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x16 (4 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x32 (5 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x64 (6 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x128 (7 << 0)
+#define CAP1206_SENS_CTRL_BASE_SHIFT_x256 (8 << 0)
+
+#define CAP1206_CONFIG_1 0x20
+#define CAP1206_CONFIG_1_TIMEOUT (1 << 7)
+#define CAP1206_CONFIG_1_DIS_DIG_NOISE (1 << 5)
+#define CAP1206_CONFIG_1_DIS_ANA_NOISE (1 << 4)
+#define CAP1206_CONFIG_1_MAX_DUR_EN (1 << 3)
+
+#define CAP1206_CONFIG_2 0x44
+#define CAP1206_CONFIG_2_BC_OUT_RECAL (1 << 6)
+#define CAP1206_CONFIG_2_BLK_PWR_CTRL (1 << 5)
+#define CAP1206_CONFIG_2_BC_OUT_INT (1 << 4)
+#define CAP1206_CONFIG_2_SHOW_RF_NOISE (1 << 3)
+#define CAP1206_CONFIG_2_DIS_RF_NOISE (1 << 2)
+#define CAP1206_CONFIG_2_ACAL_FAIL_INT (1 << 1)
+#define CAP1206_CONFIG_2_INT_REL_n (1 << 0)
+
+#define CAP1206_SENS_IN_EN 0x21
+#define CAP1206_SENS_IN_EN_CS_EN(x) (1 << (x-1))
+
+#define CAP1206_SENS_IN_CFG 0x22
+#define CAP1206_SENS_IN_CFG_MAX_DUR_560ms (0 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_840ms (1 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_1120ms (2 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_1400ms (3 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_1680ms (4 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_2240ms (5 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_2800ms (6 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_3360ms (7 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_3920ms (8 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_4480ms (9 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_5600ms (10 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_6720ms (11 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_7840ms (12 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_8906ms (13 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_10080ms (14 << 4)
+#define CAP1206_SENS_IN_CFG_MAX_DUR_11200ms (15 << 4)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_35ms (0 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_70ms (1 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_105ms (2 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_140ms (3 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_175ms (4 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_210ms (5 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_245ms (6 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_280ms (7 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_315ms (8 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_350ms (9 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_385ms (10 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_420ms (11 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_455ms (12 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_490ms (13 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_525ms (14 << 0)
+#define CAP1206_SENS_IN_CFG_RPT_RATE_560ms (15 << 0)
+
+#define CAP1206_SENS_IN_CFG2 0x23
+#define CAP1206_SENS_IN_CFG2_M_PRESS_35ms (0 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_70ms (1 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_105ms (2 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_140ms (3 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_175ms (4 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_210ms (5 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_245ms (6 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_280ms (7 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_315ms (8 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_350ms (9 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_385ms (10 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_420ms (11 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_455ms (12 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_490ms (13 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_525ms (14 << 0)
+#define CAP1206_SENS_IN_CFG2_M_PRESS_560ms (15 << 0)
+
+#define CAP1206_AVG_SAMP_CFG 0x24
+#define CAP1206_AVG_SAMP_CFG_AVG_1 (0 << 4)
+#define CAP1206_AVG_SAMP_CFG_AVG_2 (1 << 4)
+#define CAP1206_AVG_SAMP_CFG_AVG_4 (2 << 4)
+#define CAP1206_AVG_SAMP_CFG_AVG_8 (3 << 4)
+#define CAP1206_AVG_SAMP_CFG_AVG_16 (4 << 4)
+#define CAP1206_AVG_SAMP_CFG_AVG_32 (5 << 4)
+#define CAP1206_AVG_SAMP_CFG_AVG_64 (6 << 4)
+#define CAP1206_AVG_SAMP_CFG_AVG_128 (7 << 4)
+#define CAP1206_AVG_SAMP_CFG_SAMP_TIM_320us (0 << 2)
+#define CAP1206_AVG_SAMP_CFG_SAMP_TIM_640us (1 << 2)
+#define CAP1206_AVG_SAMP_CFG_SAMP_TIM_1ms28 (2 << 2)
+#define CAP1206_AVG_SAMP_CFG_SAMP_TIM_2ms56 (4 << 2)
+#define CAP1206_AVG_SAMP_CFG_CYCL_TIM_35ms (0 << 0)
+#define CAP1206_AVG_SAMP_CFG_CYCL_TIM_70ms (1 << 0)
+#define CAP1206_AVG_SAMP_CFG_CYCL_TIM_105ms (2 << 0)
+#define CAP1206_AVG_SAMP_CFG_CYCL_TIM_140ms (3 << 0)
+
+#define CAP1206_CAL_ACTIVE_STATUS 0x26
+#define CAP1206_CAL_ACTIVE_STATUS_CS_CAL(x) (1 << (x-1))
+
+#define CAP1206_INT_EN 0x27
+#define CAP1206_INT_EN_CS(x) (1 << (x-1))
+
+#define CAP1206_RPT_EN 0x28
+#define CAP1206_RPT_EN_CS(x) (1 << (x-1))
+
+#define CAP1206_MULT_TOUCH_CFG 0x2A
+#define CAP1206_MULT_TOUCH_CFG_MULT_BLK_EN (1 << 7)
+#define CAP1206_MULT_TOUCH_CFG_B_MULT_T_1 (0 << 2)
+#define CAP1206_MULT_TOUCH_CFG_B_MULT_T_2 (1 << 2)
+#define CAP1206_MULT_TOUCH_CFG_B_MULT_T_3 (2 << 2)
+#define CAP1206_MULT_TOUCH_CFG_B_MULT_T_4 (3 << 2)
+
+#define CAP1206_MULT_TOUCH_PTRN 0x2B
+#define CAP1206_MULT_TOUCH_PTRN_MTP_EN (1 << 7)
+#define CAP1206_MULT_TOUCH_PTRN_MTP_TH_12_5 (0 << 2)
+#define CAP1206_MULT_TOUCH_PTRN_MTP_TH_25 (1 << 2)
+#define CAP1206_MULT_TOUCH_PTRN_MTP_TH_37_5 (2 << 2)
+#define CAP1206_MULT_TOUCH_PTRN_MTP_TH_100 (3 << 2)
+#define CAP1206_MULT_TOUCH_PTRN_COMP_PTRN (1 << 1)
+#define CAP1206_MULT_TOUCH_PTRN_MTP_ALERT (1 << 0)
+
+#define CAP1206_BASE_CNT_OUT_OF_LIMIT 0x2E
+#define CAP1206_BASE_CNT_OUT_OF_LIMIT_CS(x) (1 << (x-1))
+
+#define CAP1206_RECALIB_CFG 0x2F
+#define CAP1206_RECALIB_CFG_BUT_LD_TH (1 << 7)
+#define CAP1206_RECALIB_CFG_NO_CLR_INTD (1 << 6)
+#define CAP1206_RECALIB_CFG_NO_CLR_NEG (1 << 5)
+#define CAP1206_RECALIB_CFG_NEG_dCNT_8 (0 << 3)
+#define CAP1206_RECALIB_CFG_NEG_dCNT_16 (1 << 3)
+#define CAP1206_RECALIB_CFG_NEG_dCNT_32 (2 << 3)
+#define CAP1206_RECALIB_CFG_NEG_dCNT_NONE (3 << 3)
+#define CAP1206_RECALIB_CFG_CAL_CFG_16_16 (0 << 0)
+#define CAP1206_RECALIB_CFG_CAL_CFG_32_32 (1 << 0)
+#define CAP1206_RECALIB_CFG_CAL_CFG_64_64 (2 << 0)
+#define CAP1206_RECALIB_CFG_CAL_CFG_128_128 (3 << 0)
+#define CAP1206_RECALIB_CFG_CAL_CFG_256_256 (4 << 0)
+#define CAP1206_RECALIB_CFG_CAL_CFG_256_1024 (5 << 0)
+#define CAP1206_RECALIB_CFG_CAL_CFG_256_2048 (6 << 0)
+#define CAP1206_RECALIB_CFG_CAL_CFG_256_4096 (7 << 0)
+
+#define CAP1206_SENS_IN_TH(x) (0x2F + x)
+
+#define CAP1206_SENS_IN_NOISE_TH 0x38
+#define CAP1206_SENS_IN_NOISE_TH_CS_BN_TH_25 (0 << 0)
+#define CAP1206_SENS_IN_NOISE_TH_CS_BN_TH_37_5 (1 << 0)
+#define CAP1206_SENS_IN_NOISE_TH_CS_BN_TH_50 (2 << 0)
+#define CAP1206_SENS_IN_NOISE_TH_CS_BN_TH_62_5 (3 << 0)
+
+#define CAP1206_STBY_CHAN 0x40
+#define CAP1206_STBY_CHAN_CS(x) (1 << (x-1))
+
+#define CAP1206_STBY_CFG 0x41
+#define CAP1206_STBY_CFG_AVG_SUM (1 << 7)
+#define CAP1206_STBY_CFG_STBY_AVG_1 (0 << 4)
+#define CAP1206_STBY_CFG_STBY_AVG_2 (1 << 4)
+#define CAP1206_STBY_CFG_STBY_AVG_4 (2 << 4)
+#define CAP1206_STBY_CFG_STBY_AVG_8 (3 << 4)
+#define CAP1206_STBY_CFG_STBY_AVG_16 (4 << 4)
+#define CAP1206_STBY_CFG_STBY_AVG_32 (5 << 4)
+#define CAP1206_STBY_CFG_STBY_AVG_64 (6 << 4)
+#define CAP1206_STBY_CFG_STBY_AVG_128 (7 << 4)
+#define CAP1206_STBY_CFG_SAMP_TIM_320u (0 << 2)
+#define CAP1206_STBY_CFG_SAMP_TIM_640u (0 << 2)
+#define CAP1206_STBY_CFG_SAMP_TIM_1_28m (0 << 2)
+#define CAP1206_STBY_CFG_SAMP_TIM_2_56m (0 << 2)
+#define CAP1206_STBY_CFG_CY_TIM_35m (0 << 0)
+#define CAP1206_STBY_CFG_CY_TIM_70m (1 << 0)
+#define CAP1206_STBY_CFG_CY_TIM_105m (2 << 0)
+#define CAP1206_STBY_CFG_CY_TIM_140m (3 << 0)
+
+#define CAP1206_STBY_SENS 0x42
+#define CAP1206_STBY_SENS_STBY_SENS_128 (0 << 0)
+#define CAP1206_STBY_SENS_STBY_SENS_64 (1 << 0)
+#define CAP1206_STBY_SENS_STBY_SENS_32 (2 << 0)
+#define CAP1206_STBY_SENS_STBY_SENS_16 (3 << 0)
+#define CAP1206_STBY_SENS_STBY_SENS_8 (4 << 0)
+#define CAP1206_STBY_SENS_STBY_SENS_4 (5 << 0)
+#define CAP1206_STBY_SENS_STBY_SENS_2 (6 << 0)
+#define CAP1206_STBY_SENS_STBY_SENS_1 (7 << 0)
+
+#define CAP1206_STBY_TH 0x43
+
+#define CAP1206_SENS_IN_BASE_CNT(x) (0x4F + x)
+
+#define CAP1206_PWR_BTN 0x60
+#define CAP1206_PWR_BTN_CS(x) (x-1)
+
+#define CAP1206_PWR_BTN_CFG 0x61
+#define CAP1206_PWR_BTN_CFG_STBY_PWR_EN (1 << 6)
+#define CAP1206_PWR_BTN_CFG_STBY_PWR_TIME_280m (0 << 4)
+#define CAP1206_PWR_BTN_CFG_STBY_PWR_TIME_560m (1 << 4)
+#define CAP1206_PWR_BTN_CFG_STBY_PWR_TIME_1_12s (2 << 4)
+#define CAP1206_PWR_BTN_CFG_STBY_PWR_TIME_2_24s (3 << 4)
+
+#define CAP1206_SENS_IN_CAL(x) (0xB0 + x)
+
+#endif /* CAP1206_REGS_H */
+