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 */ +