diff --git a/firmware/SOURCES b/firmware/SOURCES index 34d2db39b2..db3f09ea8e 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1231,10 +1231,10 @@ target/arm/imx233/creative-zenxfi2/powermgmt-zenxfi2.c #endif #ifdef CREATIVE_ZENXFI3 -drivers/mpr121.c #ifndef BOOTLOADER target/arm/imx233/fmradio-imx233.c #endif +target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c target/arm/imx233/creative-zenxfi3/backlight-zenxfi3.c target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c target/arm/imx233/creative-zenxfi3/button-zenxfi3.c diff --git a/firmware/drivers/mpr121.c b/firmware/drivers/mpr121.c deleted file mode 100644 index 7b41208a3a..0000000000 --- a/firmware/drivers/mpr121.c +++ /dev/null @@ -1,350 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2012 Amaury Pouly - * - * 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 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -/** Driver for the Freescale MPR121 Capacitive Proximity Sensor */ -#include "system.h" -#include "mpr121.h" -#include "i2c.h" - -/* Touch status: EL{0,7} */ -#define REG_TOUCH_STATUS 0x00 -#define REG_TOUCH_STATUS__ELE(x) (1 << (x)) -/* Touch status: EL{8-11,prox}, overcurrent */ -#define REG_TOUCH_STATUS2 0x01 -#define REG_TOUCH_STATUS2__ELE(x) (1 << ((x) - 8)) -#define REG_TOUCH_STATUS2__ELEPROX (1 << 4) -#define REG_TOUCH_STATUS2__OVCF (1 << 7) -/* Out of range: EL{0,7} */ -#define REG_OOR_STATUS 0x02 -#define REG_OOR_STATUS__ELE(x) (1 << (x)) -/* Out of range: EL{8-11,prox}, autoconf err */ -#define REG_OOR_STATUS2 0x03 -#define REG_OOR_STATUS2__ELE(x) (1 << (x)) -#define REG_OOR_STATUS2__ELEPROX (1 << 4) -#define REG_OOR_STATUS2__ACFF (1 << 6) -#define REG_OOR_STATUS2__ARFF (1 << 7) -/* Electrode X filtered data LSB */ -#define REG_EFDxLB(x) (0x04 + 0x02 * (x)) -/* Electrode X filtered data MSB */ -#define REG_EFDxHB(x) (0x05 + 0x02 * (x)) -/* Proximity electrode X filtered data LSB */ -#define REG_EFDPROXLB 0x1c -/* Proximity electrode X filtered data MSB */ -#define REG_EFDPROXHB 0x1d -/* Electrode baseline value */ -#define REG_ExBV(x) (0x1e + (x)) -/* Proximity electrode baseline value */ -#define REG_EPROXBV 0x2a -/* Max Half Delta Rising */ -#define REG_MHDR 0x2b -/* Noise Half Delta Rising */ -#define REG_NHDR 0x2c -/* Noise Count Limit Rising */ -#define REG_NCLR 0x2d -/* Filter Delay Limit Rising */ -#define REG_FDLR 0x2e -/* Max Half Delta Falling */ -#define REG_MHDF 0x2f -/* Noise Half Delta Falling */ -#define REG_NHDF 0x30 -/* Noise Count Limit Falling */ -#define REG_NCLF 0x31 -/* Filter Delay Limit Falling */ -#define REG_FDLF 0x32 -/* Noise Half Delta Touched */ -#define REG_NHDT 0x33 -/* Noise Count Limit Touched */ -#define REG_NCLT 0x34 -/* Filter Delay Limit Touched */ -#define REG_FDLT 0x35 -/* Proximity Max Half Delta Rising */ -#define REG_MHDPROXR 0x36 -/* Proximity Noise Half Delta Rising */ -#define REG_NHDPROXR 0x37 -/* Proximity Noise Count Limit Rising */ -#define REG_NCLPROXR 0x38 -/* Proximity Filter Delay Limit Rising */ -#define REG_FDLPROXR 0x39 -/* Proximity Max Half Delta Falling */ -#define REG_MHDPROXF 0x3a -/* Proximity Noise Half Delta Falling */ -#define REG_NHDPROXF 0x3b -/* Proximity Noise Count Limit Falling */ -#define REG_NCLPROXF 0x3c -/* Proximity Filter Delay Limit Falling */ -#define REG_FDLPROXF 0x3d -/* Proximity Noise Half Delta Touched */ -#define REG_NHDPROXT 0x3e -/* Proximity Noise Count Limit Touched */ -#define REG_NCLPROXT 0x3f -/* Proximity Filter Delay Limit Touched */ -#define REG_FDLPROXT 0x40 -/* Eletrode Touch Threshold */ -#define REG_ExTTH(x) (0x41 + 2 * (x)) -/* Eletrode Release Threshold */ -#define REG_ExRTH(x) (0x42 + 2 * (x)) -/* Proximity Eletrode Touch Threshold */ -#define REG_EPROXTTH 0x59 -/* Proximity Eletrode Release Threshold */ -#define REG_EPROXRTH 0x5a -/* Debounce Control */ -#define REG_DEBOUNCE 0x5b -#define REG_DEBOUNCE__DR(dr) ((dr) << 4) -#define REG_DEBOUNCE__DT(dt) (dt) -/* Analog Front End Configuration */ -#define REG_AFE 0x5c -#define REG_AFE__CDC(cdc) (cdc) -#define REG_AFE__FFI(ffi) ((ffi) << 6) -/* Filter Configuration */ -#define REG_FILTER 0x5d -#define REG_FILTER__ESI(esi) (esi) -#define REG_FILTER__SFI(sfi) ((sfi) << 3) -#define REG_FILTER__CDT(cdt) ((cdt) << 5) -/* Electrode Configuration */ -#define REG_ELECTRODE 0x5e -#define REG_ELECTRODE__ELE_EN(en) (en) -#define REG_ELECTRODE__ELEPROX_EN(en) ((en) << 4) -#define REG_ELECTRODE__CL(cl) ((cl) << 6) -/* Electrode X Current */ -#define REG_CDCx(x) (0x5f + (x)) -/* Proximity Eletrode X Current */ -#define REG_CDCPROX 0x6b -/* Electrode X Charge Time */ -#define REG_CDTx(x) (0x6c + (x) / 2) -#define REG_CDTx__CDT0(x) (x) -#define REG_CDTx__CDT1(x) ((x) << 4) -/* Proximity Eletrode X Charge Time */ -#define REG_CDTPROX 0x72 -/* GPIO Control Register: CTL0{4-11} */ -#define REG_GPIO_CTL0 0x73 -#define REG_GPIO_CTL0__CTL0x(x) (1 << ((x) - 4)) -/* GPIO Control Register: CTL1{4-11} */ -#define REG_GPIO_CTL1 0x74 -#define REG_GPIO_CTL1__CTL1x(x) (1 << ((x) - 4)) -/* GPIO Data Register */ -#define REG_GPIO_DATA 0x75 -#define REG_GPIO_DATA__DATx(x) (1 << ((x) - 4)) -/* GPIO Direction Register */ -#define REG_GPIO_DIR 0x76 -#define REG_GPIO_DIR__DIRx(x) (1 << ((x) - 4)) -/* GPIO Enable Register */ -#define REG_GPIO_EN 0x77 -#define REG_GPIO_EN__ENx(x) (1 << ((x) - 4)) -/* GPIO Data Set Register */ -#define REG_GPIO_SET 0x78 -#define REG_GPIO_SET__SETx(x) (1 << ((x) - 4)) -/* GPIO Data Clear Register */ -#define REG_GPIO_CLR 0x79 -#define REG_GPIO_CLR__CLRx(x) (1 << ((x) - 4)) -/* GPIO Data Toggle Register */ -#define REG_GPIO_TOG 0x7a -#define REG_GPIO_TOG__TOGx(x) (1 << ((x) - 4)) -/* Auto-Configuration Control 0 */ -#define REG_AUTO_CONF 0x7b -#define REG_AUTO_CONF__ACE(ace) (ace) -#define REG_AUTO_CONF__ARE(are) ((are) << 1) -#define REG_AUTO_CONF__BVA(bva) ((bva) << 2) -#define REG_AUTO_CONF__RETRY(retry) ((retry) << 4) -#define REG_AUTO_CONF__FFI(ffi) ((ffi) << 6) -/* Auto-Configuration Control 1 */ -#define REG_AUTO_CONF2 0x7c -#define REG_AUTO_CONF2__ACFIE(acfie) (acfie) -#define REG_AUTO_CONF2__ARFIE(arfie) ((arfie) << 1) -#define REG_AUTO_CONF2__OORIE(oorie) ((oorie) << 2) -#define REG_AUTO_CONF2__SCTS(scts) ((scts) << 7) -/* Auto-Configuration Upper-Limit */ -#define REG_USL 0x7d -/* Auto-Configuration Lower-Limit */ -#define REG_LSL 0x7e -/* Auto-Configuration Target Level */ -#define REG_TL 0x7f -/* Soft-Reset */ -#define REG_SOFTRESET 0x80 -#define REG_SOFTRESET__MAGIC 0x63 -/* PWM Control */ -#define REG_PWMx(x) (0x81 + ((x) - 4) / 2) -#define REG_PWMx_IS_PWM0(x) (((x) % 2) == 0) -#define REG_PWMx__PWM0(x) (x) -#define REG_PWMx__PWM0_BM 0xf -#define REG_PWMx__PWM1(x) ((x) << 4) -#define REG_PWMx__PWM1_BM 0xf0 - -static int i2c_addr; - -static inline int mpr121_write_reg(uint8_t reg, uint8_t data) -{ - return i2c_writemem(i2c_addr, reg, &data, 1); -} - -static inline int mpr121_read_reg(uint8_t reg, uint8_t *data) -{ - return i2c_readmem(i2c_addr, reg, data, 1); -} - -int mpr121_init(int dev_i2c_addr) -{ - i2c_addr = dev_i2c_addr; - return 0; -} - -int mpr121_soft_reset(void) -{ - return mpr121_write_reg(REG_SOFTRESET, REG_SOFTRESET__MAGIC); -} -int mpr121_set_config(struct mpr121_config_t *conf) -{ - int ret; -#define safe_write(reg, val) \ - do { ret = mpr121_write_reg(reg, val); \ - if(ret) return ret; } while(0) - /* stop mode */ - safe_write(REG_ELECTRODE, 0); - /* write baseline values */ - for(int i = 0; i < ELECTRODE_COUNT; i++) - safe_write(REG_ExBV(i), conf->ele[i].bv); - /* write eleprox bv */ - safe_write(REG_EPROXBV, conf->eleprox.bv); - /* write global fields */ - safe_write(REG_MHDR, conf->filters.ele.rising.mhd); - safe_write(REG_NHDR, conf->filters.ele.rising.nhd); - safe_write(REG_NCLR, conf->filters.ele.rising.ncl); - safe_write(REG_FDLR, conf->filters.ele.rising.fdl); - safe_write(REG_MHDF, conf->filters.ele.falling.mhd); - safe_write(REG_NHDF, conf->filters.ele.falling.nhd); - safe_write(REG_NCLF, conf->filters.ele.falling.ncl); - safe_write(REG_FDLF, conf->filters.ele.falling.fdl); - safe_write(REG_NHDT, conf->filters.ele.touched.nhd); - safe_write(REG_NCLT, conf->filters.ele.touched.ncl); - safe_write(REG_FDLT, conf->filters.ele.touched.fdl); - safe_write(REG_MHDPROXR, conf->filters.eleprox.rising.mhd); - safe_write(REG_NHDPROXR, conf->filters.eleprox.rising.nhd); - safe_write(REG_NCLPROXR, conf->filters.eleprox.rising.ncl); - safe_write(REG_FDLPROXR, conf->filters.eleprox.rising.fdl); - safe_write(REG_MHDPROXF, conf->filters.eleprox.falling.mhd); - safe_write(REG_NHDPROXF, conf->filters.eleprox.falling.nhd); - safe_write(REG_NCLPROXF, conf->filters.eleprox.falling.ncl); - safe_write(REG_FDLPROXF, conf->filters.eleprox.falling.fdl); - safe_write(REG_NHDPROXT, conf->filters.eleprox.touched.nhd); - safe_write(REG_NCLPROXT, conf->filters.eleprox.touched.ncl); - safe_write(REG_FDLPROXT, conf->filters.eleprox.touched.fdl); - /* touch & release thresholds */ - for(int i = 0; i < ELECTRODE_COUNT; i++) - { - safe_write(REG_ExTTH(i), conf->ele[i].tth); - safe_write(REG_ExRTH(i), conf->ele[i].rth); - } - safe_write(REG_EPROXTTH, conf->eleprox.tth); - safe_write(REG_EPROXRTH, conf->eleprox.rth); - /* debounce */ - safe_write(REG_DEBOUNCE, REG_DEBOUNCE__DR(conf->debounce.dr) | - REG_DEBOUNCE__DT(conf->debounce.dt)); - /* analog-front end and filters */ - safe_write(REG_AFE, REG_AFE__CDC(conf->global.cdc) | - REG_AFE__FFI(conf->global.ffi)); - safe_write(REG_FILTER, REG_FILTER__CDT(conf->global.cdt) | - REG_FILTER__ESI(conf->global.esi) | REG_FILTER__SFI(conf->global.sfi)); - /* electrode charge */ - for(int i = 0; i < ELECTRODE_COUNT; i++) - safe_write(REG_CDCx(i), conf->ele[i].cdc); - safe_write(REG_CDCPROX, conf->eleprox.cdc); - for(int i = 0; i < ELECTRODE_COUNT; i += 2) - { - safe_write(REG_CDTx(i), REG_CDTx__CDT0(conf->ele[i].cdt) | - REG_CDTx__CDT1(conf->ele[i+1].cdt)); - } - safe_write(REG_CDTPROX, conf->eleprox.cdt); - /* Auto-Configuration */ - safe_write(REG_AUTO_CONF, REG_AUTO_CONF__ACE(conf->autoconf.en) | - REG_AUTO_CONF__ARE(conf->autoconf.ren) | - REG_AUTO_CONF__BVA(conf->cal_lock) | - REG_AUTO_CONF__RETRY(conf->autoconf.retry) | - REG_AUTO_CONF__FFI(conf->global.ffi)); - safe_write(REG_AUTO_CONF2, REG_AUTO_CONF2__ACFIE(conf->autoconf.acfie) | - REG_AUTO_CONF2__ARFIE(conf->autoconf.arfie) | - REG_AUTO_CONF2__OORIE(conf->autoconf.oorie) | - REG_AUTO_CONF2__SCTS(conf->autoconf.scts)); - safe_write(REG_USL, conf->autoconf.usl); - safe_write(REG_LSL, conf->autoconf.lsl); - safe_write(REG_TL, conf->autoconf.tl); - /* electrode configuration */ - safe_write(REG_ELECTRODE, REG_ELECTRODE__ELE_EN(conf->ele_en) | - REG_ELECTRODE__ELEPROX_EN(conf->eleprox_en) | - REG_ELECTRODE__CL(conf->cal_lock)); - /* gpio config */ - uint8_t ctl = 0; - for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) - if(ELE_GPIO_CTL0(conf->ele[i].gpio)) - ctl |= REG_GPIO_CTL0__CTL0x(i); - safe_write(REG_GPIO_CTL0, ctl); - ctl = 0; - for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) - if(ELE_GPIO_CTL1(conf->ele[i].gpio)) - ctl |= REG_GPIO_CTL1__CTL1x(i); - safe_write(REG_GPIO_CTL1, ctl); - ctl = 0; - for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) - if(ELE_GPIO_DIR(conf->ele[i].gpio)) - ctl |= REG_GPIO_DIR__DIRx(i); - safe_write(REG_GPIO_DIR, ctl); - ctl = 0; - for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) - if(ELE_GPIO_EN(conf->ele[i].gpio)) - ctl |= REG_GPIO_EN__ENx(i); - safe_write(REG_GPIO_EN, ctl); - - return 0; -} - -int mpr121_set_gpio_output(int ele, int gpio_val) -{ - switch(gpio_val) - { - case ELE_GPIO_SET: - return mpr121_write_reg(REG_GPIO_SET, REG_GPIO_SET__SETx(ele)); - case ELE_GPIO_CLR: - return mpr121_write_reg(REG_GPIO_CLR, REG_GPIO_CLR__CLRx(ele)); - case ELE_GPIO_TOG: - return mpr121_write_reg(REG_GPIO_TOG, REG_GPIO_TOG__TOGx(ele)); - default: - return -1; - } -} - -int mpr121_set_gpio_pwm(int ele, int pwm) -{ - uint8_t reg_val; - int ret = mpr121_read_reg(REG_PWMx(ele), ®_val); - if(ret) return ret; - if(REG_PWMx_IS_PWM0(ele)) - reg_val = (reg_val & ~REG_PWMx__PWM0_BM) | REG_PWMx__PWM0(pwm); - else - reg_val = (reg_val & ~REG_PWMx__PWM1_BM) | REG_PWMx__PWM1(pwm); - return mpr121_write_reg(REG_PWMx(ele), reg_val); -} - -int mpr121_get_touch_status(unsigned *status) -{ - uint8_t buf[2]; - int ret = i2c_readmem(i2c_addr, REG_TOUCH_STATUS, buf, 2); - if(!ret && status) - *status = buf[0] | buf[1]; - return ret; -} diff --git a/firmware/export/mpr121.h b/firmware/export/mpr121.h index 96b83ecc90..50c13a1c7b 100644 --- a/firmware/export/mpr121.h +++ b/firmware/export/mpr121.h @@ -18,153 +18,173 @@ * KIND, either express or implied. * ****************************************************************************/ +#ifndef __MPR121_H__ +#define __MPR121_H__ -/** Driver for the Freescale MPR121 Capacitive Proximity Sensor */ +/** Registers for the Freescale MPR121 Capacitive Proximity Sensor */ #include "system.h" -#define ELECTRODE_COUNT 12 -#define ELE_GPIO_FIRST 4 -#define ELE_GPIO_LAST 11 +/* Touch status: EL{0,7} */ +#define REG_TOUCH_STATUS 0x00 +#define REG_TOUCH_STATUS__ELE(x) (1 << (x)) +/* Touch status: EL{8-11,prox}, overcurrent */ +#define REG_TOUCH_STATUS2 0x01 +#define REG_TOUCH_STATUS2__ELE(x) (1 << ((x) - 8)) +#define REG_TOUCH_STATUS2__ELEPROX (1 << 4) +#define REG_TOUCH_STATUS2__OVCF (1 << 7) +/* Out of range: EL{0,7} */ +#define REG_OOR_STATUS 0x02 +#define REG_OOR_STATUS__ELE(x) (1 << (x)) +/* Out of range: EL{8-11,prox}, autoconf err */ +#define REG_OOR_STATUS2 0x03 +#define REG_OOR_STATUS2__ELE(x) (1 << (x)) +#define REG_OOR_STATUS2__ELEPROX (1 << 4) +#define REG_OOR_STATUS2__ACFF (1 << 6) +#define REG_OOR_STATUS2__ARFF (1 << 7) +/* Electrode X filtered data LSB */ +#define REG_EFDxLB(x) (0x04 + 0x02 * (x)) +/* Electrode X filtered data MSB */ +#define REG_EFDxHB(x) (0x05 + 0x02 * (x)) +/* Proximity electrode X filtered data LSB */ +#define REG_EFDPROXLB 0x1c +/* Proximity electrode X filtered data MSB */ +#define REG_EFDPROXHB 0x1d +/* Electrode baseline value */ +#define REG_ExBV(x) (0x1e + (x)) +/* Proximity electrode baseline value */ +#define REG_EPROXBV 0x2a +/* Max Half Delta Rising */ +#define REG_MHDR 0x2b +/* Noise Half Delta Rising */ +#define REG_NHDR 0x2c +/* Noise Count Limit Rising */ +#define REG_NCLR 0x2d +/* Filter Delay Limit Rising */ +#define REG_FDLR 0x2e +/* Max Half Delta Falling */ +#define REG_MHDF 0x2f +/* Noise Half Delta Falling */ +#define REG_NHDF 0x30 +/* Noise Count Limit Falling */ +#define REG_NCLF 0x31 +/* Filter Delay Limit Falling */ +#define REG_FDLF 0x32 +/* Noise Half Delta Touched */ +#define REG_NHDT 0x33 +/* Noise Count Limit Touched */ +#define REG_NCLT 0x34 +/* Filter Delay Limit Touched */ +#define REG_FDLT 0x35 +/* Proximity Max Half Delta Rising */ +#define REG_MHDPROXR 0x36 +/* Proximity Noise Half Delta Rising */ +#define REG_NHDPROXR 0x37 +/* Proximity Noise Count Limit Rising */ +#define REG_NCLPROXR 0x38 +/* Proximity Filter Delay Limit Rising */ +#define REG_FDLPROXR 0x39 +/* Proximity Max Half Delta Falling */ +#define REG_MHDPROXF 0x3a +/* Proximity Noise Half Delta Falling */ +#define REG_NHDPROXF 0x3b +/* Proximity Noise Count Limit Falling */ +#define REG_NCLPROXF 0x3c +/* Proximity Filter Delay Limit Falling */ +#define REG_FDLPROXF 0x3d +/* Proximity Noise Half Delta Touched */ +#define REG_NHDPROXT 0x3e +/* Proximity Noise Count Limit Touched */ +#define REG_NCLPROXT 0x3f +/* Proximity Filter Delay Limit Touched */ +#define REG_FDLPROXT 0x40 +/* Eletrode Touch Threshold */ +#define REG_ExTTH(x) (0x41 + 2 * (x)) +/* Eletrode Release Threshold */ +#define REG_ExRTH(x) (0x42 + 2 * (x)) +/* Proximity Eletrode Touch Threshold */ +#define REG_EPROXTTH 0x59 +/* Proximity Eletrode Release Threshold */ +#define REG_EPROXRTH 0x5a +/* Debounce Control */ +#define REG_DEBOUNCE 0x5b +#define REG_DEBOUNCE__DR(dr) ((dr) << 4) +#define REG_DEBOUNCE__DT(dt) (dt) +/* Analog Front End Configuration */ +#define REG_AFE 0x5c +#define REG_AFE__CDC(cdc) (cdc) +#define REG_AFE__FFI(ffi) ((ffi) << 6) +/* Filter Configuration */ +#define REG_FILTER 0x5d +#define REG_FILTER__ESI(esi) (esi) +#define REG_FILTER__SFI(sfi) ((sfi) << 3) +#define REG_FILTER__CDT(cdt) ((cdt) << 5) +/* Electrode Configuration */ +#define REG_ELECTRODE 0x5e +#define REG_ELECTRODE__ELE_EN(en) (en) +#define REG_ELECTRODE__ELEPROX_EN(en) ((en) << 4) +#define REG_ELECTRODE__CL(cl) ((cl) << 6) +/* Electrode X Current */ +#define REG_CDCx(x) (0x5f + (x)) +/* Proximity Eletrode X Current */ +#define REG_CDCPROX 0x6b +/* Electrode X Charge Time */ +#define REG_CDTx(x) (0x6c + (x) / 2) +#define REG_CDTx__CDT0(x) (x) +#define REG_CDTx__CDT1(x) ((x) << 4) +/* Proximity Eletrode X Charge Time */ +#define REG_CDTPROX 0x72 +/* GPIO Control Register: CTL0{4-11} */ +#define REG_GPIO_CTL0 0x73 +#define REG_GPIO_CTL0__CTL0x(x) (1 << ((x) - 4)) +/* GPIO Control Register: CTL1{4-11} */ +#define REG_GPIO_CTL1 0x74 +#define REG_GPIO_CTL1__CTL1x(x) (1 << ((x) - 4)) +/* GPIO Data Register */ +#define REG_GPIO_DATA 0x75 +#define REG_GPIO_DATA__DATx(x) (1 << ((x) - 4)) +/* GPIO Direction Register */ +#define REG_GPIO_DIR 0x76 +#define REG_GPIO_DIR__DIRx(x) (1 << ((x) - 4)) +/* GPIO Enable Register */ +#define REG_GPIO_EN 0x77 +#define REG_GPIO_EN__ENx(x) (1 << ((x) - 4)) +/* GPIO Data Set Register */ +#define REG_GPIO_SET 0x78 +#define REG_GPIO_SET__SETx(x) (1 << ((x) - 4)) +/* GPIO Data Clear Register */ +#define REG_GPIO_CLR 0x79 +#define REG_GPIO_CLR__CLRx(x) (1 << ((x) - 4)) +/* GPIO Data Toggle Register */ +#define REG_GPIO_TOG 0x7a +#define REG_GPIO_TOG__TOGx(x) (1 << ((x) - 4)) +/* Auto-Configuration Control 0 */ +#define REG_AUTO_CONF 0x7b +#define REG_AUTO_CONF__ACE(ace) (ace) +#define REG_AUTO_CONF__ARE(are) ((are) << 1) +#define REG_AUTO_CONF__BVA(bva) ((bva) << 2) +#define REG_AUTO_CONF__RETRY(retry) ((retry) << 4) +#define REG_AUTO_CONF__FFI(ffi) ((ffi) << 6) +/* Auto-Configuration Control 1 */ +#define REG_AUTO_CONF2 0x7c +#define REG_AUTO_CONF2__ACFIE(acfie) (acfie) +#define REG_AUTO_CONF2__ARFIE(arfie) ((arfie) << 1) +#define REG_AUTO_CONF2__OORIE(oorie) ((oorie) << 2) +#define REG_AUTO_CONF2__SCTS(scts) ((scts) << 7) +/* Auto-Configuration Upper-Limit */ +#define REG_USL 0x7d +/* Auto-Configuration Lower-Limit */ +#define REG_LSL 0x7e +/* Auto-Configuration Target Level */ +#define REG_TL 0x7f +/* Soft-Reset */ +#define REG_SOFTRESET 0x80 +#define REG_SOFTRESET__MAGIC 0x63 +/* PWM Control */ +#define REG_PWMx(x) (0x81 + ((x) - 4) / 2) +#define REG_PWMx_IS_PWM0(x) (((x) % 2) == 0) +#define REG_PWMx__PWM0(x) (x) +#define REG_PWMx__PWM0_BM 0xf +#define REG_PWMx__PWM1(x) ((x) << 4) +#define REG_PWMx__PWM1_BM 0xf0 -/* gpio config (encoding: [0]=en,[1]=dir,[2]=ctl[1],[3]=ctl[0]) */ -#define ELE_GPIO_DISABLE 0 -#define ELE_GPIO_INPUT 1 -#define ELE_GPIO_INPUT_PULLDOWN 9 /* input with pull-down */ -#define ELE_GPIO_INPUT_PULLUP 13 /* input with pull-up */ -#define ELE_GPIO_OUTPUT 3 -#define ELE_GPIO_OUTPUT_OPEN 11 /* open drain low-side */ -#define ELE_GPIO_OUTPUT_OPEN_LED 15 /* open drain high-side (led driver) */ - -/* internal use */ -#define ELE_GPIO_EN(val) ((val) & 1) -#define ELE_GPIO_DIR(val) (((val) >> 1) & 1) -#define ELE_GPIO_CTL0(val) (((val) >> 3) & 1) -#define ELE_GPIO_CTL1(val) (((val) >> 1) & 1) - -struct mpr121_electrode_config_t -{ - uint8_t bv; /* baseline value */ - uint8_t tth; /* touch threshold */ - uint8_t rth; /* release threshold */ - uint8_t cdc; /* charge current (optional if auto-conf) */ - uint8_t cdt; /* charge time (optional if auto-conf) */ - int gpio; /* gpio config */ -}; - -struct mpr121_baseline_filter_config_t -{ - uint8_t mhd; /* max half delta (except for touched) */ - uint8_t nhd; /* noise half delta */ - uint8_t ncl; /* noise count limit */ - uint8_t fdl; /* filter delay count limit */ -}; - -struct mpr121_baseline_filters_config_t -{ - struct mpr121_baseline_filter_config_t rising; - struct mpr121_baseline_filter_config_t falling; - struct mpr121_baseline_filter_config_t touched; -}; - -struct mpr121_debounce_config_t -{ - uint8_t dt; /* debounce count for touch */ - uint8_t dr; /* debounce count for release */ -}; - -/* first filter iterations */ -#define FFI_6_SAMPLES 0 -#define FFI_10_SAMPLES 1 -#define FFI_18_SAMPLES 2 -#define FFI_34_SAMPLES 3 -/* charge discharge current */ -#define CDC_DISABLE 0 -#define CDC_uA(ua) (ua) -/* charge discharge time */ -#define CDT_DISABLE 0 -#define CDT_log_us(lus) (lus) /* actual value = 2^{us-2} µs */ -/* second filter iterations */ -#define SFI_4_SAMPLES 0 -#define SFI_6_SAMPLES 1 -#define SFI_10_SAMPLES 2 -#define SFI_18_SAMPLES 3 -/* Eletrode sample interval */ -#define ESI_log_ms(lms) (lms) /* actual value = 2^{lms} ms */ - -struct mpr121_global_config_t -{ - uint8_t ffi; /* first filter iterations */ - uint8_t cdc; /* global charge discharge current */ - uint8_t cdt; /* global charge discharge time */ - uint8_t sfi; /* second first iterations */ - uint8_t esi; /* electrode sample interval */ -}; - -#define RETRY_NEVER 0 -#define RETRY_2_TIMES 1 -#define RETRY_4_TIMES 2 -#define RETRY_8_TIMES 3 - -struct mpr121_auto_config_t -{ - bool en; /* auto-conf enable */ - bool ren; /* auto-reconf enable */ - uint8_t retry; /* retry count */ - bool scts; /* skip charge time search */ - uint8_t usl; /* upper-side limit */ - uint8_t lsl; /* lower-side limit */ - uint8_t tl; /* target level */ - bool acfie; /* auto-conf fail interrupt en */ - bool arfie; /* auto-reconf fail interrupt en */ - bool oorie; /* out of range interrupt en */ -}; - -/* electrode mode */ -#define ELE_DISABLE 0 -#define ELE_EN0_x(x) ((x) + 1) -/* eleprox mode */ -#define ELEPROX_DISABLE 0 -#define ELEPROX_EN0_1 1 -#define ELEPROX_EN0_3 2 -#define ELEPROX_EN0_11 3 -/* calibration lock */ -#define CL_SLOW_TRACK 0 -#define CL_DISABLE 1 -#define CL_TRACK 2 -#define CL_FAST_TRACK 3 - -struct mpr121_config_t -{ - struct mpr121_electrode_config_t ele[ELECTRODE_COUNT]; - struct mpr121_electrode_config_t eleprox; - struct - { - struct mpr121_baseline_filters_config_t ele; - struct mpr121_baseline_filters_config_t eleprox; - }filters; - struct mpr121_debounce_config_t debounce; - struct mpr121_global_config_t global; - struct mpr121_auto_config_t autoconf; - uint8_t ele_en; /* eletroce mode */ - uint8_t eleprox_en; /* proximity mode */ - uint8_t cal_lock; /* calibration lock */ -}; - -/* gpio value */ -#define ELE_GPIO_CLR 0 -#define ELE_GPIO_SET 1 -#define ELE_GPIO_TOG 2 -/* pwm value */ -#define ELE_PWM_DISABLE 0 -#define ELE_PWM_DUTY(x) (x) -#define ELE_PWM_MIN_DUTY 1 -#define ELE_PWM_MAX_DUTY 15 - -int mpr121_init(int dev_i2c_addr); -int mpr121_soft_reset(void); -int mpr121_set_config(struct mpr121_config_t *conf); -/* gpios are only implemented for electrode>=4 */ -int mpr121_set_gpio_output(int ele, int gpio_val); -int mpr121_set_gpio_pwm(int ele, int pwm); -/* get electrode status (bitmap) */ -int mpr121_get_touch_status(unsigned *status); +#endif /* __MPR121_H__ */ diff --git a/firmware/target/arm/imx233/creative-zenxfi3/backlight-zenxfi3.c b/firmware/target/arm/imx233/creative-zenxfi3/backlight-zenxfi3.c index 2b77a4d7ac..e3baddea1e 100644 --- a/firmware/target/arm/imx233/creative-zenxfi3/backlight-zenxfi3.c +++ b/firmware/target/arm/imx233/creative-zenxfi3/backlight-zenxfi3.c @@ -25,7 +25,7 @@ #include "backlight.h" #include "backlight-target.h" #include "pwm-imx233.h" -#include "mpr121.h" +#include "mpr121-zenxfi3.h" void backlight_hw_brightness(int brightness) { diff --git a/firmware/target/arm/imx233/creative-zenxfi3/button-zenxfi3.c b/firmware/target/arm/imx233/creative-zenxfi3/button-zenxfi3.c index 756231a042..ed8e769e2d 100644 --- a/firmware/target/arm/imx233/creative-zenxfi3/button-zenxfi3.c +++ b/firmware/target/arm/imx233/creative-zenxfi3/button-zenxfi3.c @@ -18,16 +18,10 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "button-target.h" #include "system.h" -#include "system-target.h" -#include "pinctrl-imx233.h" -#include "power-imx233.h" +#include "tick.h" #include "button-imx233.h" -#include "string.h" -#include "usb.h" -#include "backlight.h" -#include "mpr121.h" +#include "mpr121-zenxfi3.h" #define I_VDDIO 0 /* index in the table */ @@ -42,7 +36,8 @@ struct imx233_button_map_t imx233_button_map[] = IMX233_BUTTON_(END, END(), "") }; -static struct mpr121_config_t config = +/* MPR121 configuration, mostly extracted from OF */ +static struct mpr121_config_t mpr121_config = { .ele = { @@ -73,74 +68,11 @@ static struct mpr121_config_t config = .cal_lock = CL_TRACK }; -#define MPR121_INTERRUPT 1 - -static int touchpad_btns = 0; -static long mpr121_stack[DEFAULT_STACK_SIZE/sizeof(long)]; -static const char mpr121_thread_name[] = "mpr121"; -static struct event_queue mpr121_queue; - -static void mpr121_irq_cb(int bank, int pin, intptr_t user) -{ - (void) bank; - (void) pin; - (void) user; - /* the callback will not be fired until interrupt is enabled back so - * the queue will not overflow or contain multiple MPR121_INTERRUPT events */ - queue_post(&mpr121_queue, MPR121_INTERRUPT, 0); -} - -static void mpr121_thread(void) -{ - struct queue_event ev; - - while(1) - { - queue_wait(&mpr121_queue, &ev); - /* handle usb connect and ignore all messages except rmi interrupts */ - if(ev.id == SYS_USB_CONNECTED) - { - usb_acknowledge(SYS_USB_CONNECTED_ACK); - continue; - } - else if(ev.id != MPR121_INTERRUPT) - continue; - /* clear interrupt and get status */ - unsigned status; - touchpad_btns = 0; - if(!mpr121_get_touch_status(&status)) - { - /* ELE3: up - * ELE4: back - * ELE5: menu - * ELE6: down - * ELE7: play */ - if(status & 0x8) touchpad_btns |= BUTTON_UP; - if(status & 0x10) touchpad_btns |= BUTTON_BACK; - if(status & 0x20) touchpad_btns |= BUTTON_MENU; - if(status & 0x40) touchpad_btns |= BUTTON_DOWN; - if(status & 0x80) touchpad_btns |= BUTTON_PLAY; - } - /* enable interrupt */ - imx233_pinctrl_setup_irq(0, 18, true, true, false, &mpr121_irq_cb, 0); - } -} - /* B0P18 is #IRQ line of the touchpad */ void button_init_device(void) { - mpr121_init(0xb4); - mpr121_soft_reset(); - mpr121_set_config(&config); - - queue_init(&mpr121_queue, true); - create_thread(mpr121_thread, mpr121_stack, sizeof(mpr121_stack), 0, - mpr121_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); - /* enable interrupt */ - imx233_pinctrl_acquire(0, 18, "mpr121_int"); - imx233_pinctrl_set_function(0, 18, PINCTRL_FUNCTION_GPIO); - imx233_pinctrl_enable_gpio(0, 18, false); - imx233_pinctrl_setup_irq(0, 18, true, true, false, &mpr121_irq_cb, 0); + mpr121_init(); + mpr121_set_config(&mpr121_config); /* generic part */ imx233_button_init(); } @@ -151,7 +83,6 @@ int button_read_device(void) * for one second after hold is released */ static int power_ignore_counter = 0; static bool old_hold; - /* light handling */ bool hold = button_hold(); if(hold != old_hold) { @@ -159,6 +90,20 @@ int button_read_device(void) if(!hold) power_ignore_counter = HZ; } + /* interpret touchpad status */ + unsigned status = mpr121_get_touch_status(); + unsigned touchpad_btns = 0; + /* ELE3: up + * ELE4: back + * ELE5: menu + * ELE6: down + * ELE7: play */ + if(status & 0x8) touchpad_btns |= BUTTON_UP; + if(status & 0x10) touchpad_btns |= BUTTON_BACK; + if(status & 0x20) touchpad_btns |= BUTTON_MENU; + if(status & 0x40) touchpad_btns |= BUTTON_DOWN; + if(status & 0x80) touchpad_btns |= BUTTON_PLAY; + /* feed it to generic code */ int res = imx233_button_read(touchpad_btns); if(power_ignore_counter > 0) { diff --git a/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c b/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c new file mode 100644 index 0000000000..23fcc7f0e4 --- /dev/null +++ b/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c @@ -0,0 +1,236 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 Amaury Pouly + * + * 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 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/** Driver for the Freescale MPR121 Capacitive Proximity Sensor */ +#include "system.h" +#include "kernel.h" +#include "usb.h" +#include "mpr121.h" +#include "mpr121-zenxfi3.h" +#include "i2c-imx233.h" +#include "pinctrl-imx233.h" + +#define MPR121_I2C_ADDR 0xb4 + +/* NOTE on the architecture of the driver + * + * All non-time-critical operations (setup, gpio/pwm changes) are done with + * blocking i2c transfers to make the code simpler. Since reading the touch + * status is time critical, it is done asynchronously: when the IRQ pin is + * asserted, it will disable IRQ pin sensing and trigger an asynchronous i2c + * transfer to read touch status. When the transfer finishes, the driver will + * renable IRQ pin sensing. */ + +static unsigned touch_status = 0; /* touch bitmask as reported by mpr121 */ +static struct imx233_i2c_xfer_t read_status_xfer; /* async transfer to read touch status */ +static uint8_t read_status_sel_reg; /* buffer for async transfer operation */ +static uint8_t read_status_buf[2]; /* buffer for async transfer operation */ + +static void mpr121_irq_cb(int bank, int pin, intptr_t user); + +static void touch_status_i2c_cb(struct imx233_i2c_xfer_t *xfer, enum imx233_i2c_error_t status) +{ + (void) xfer; + (void) status; + /* put status in the global variable */ + touch_status = read_status_buf[0] | read_status_buf[1] << 8; + /* start sensing IRQ pin again */ + imx233_pinctrl_setup_irq(0, 18, true, true, false, &mpr121_irq_cb, 0); +} + +void mpr121_irq_cb(int bank, int pin, intptr_t user) +{ + (void) bank; + (void) pin; + (void) user; + /* NOTE the callback will not be fired until interrupt is enabled back. + * + * now setup an asynchronous i2c transfer to read touch status register, + * this is a readmem operation with a first stage to select register + * and a second stage to read status (2 bytes) */ + read_status_sel_reg = REG_TOUCH_STATUS; + + read_status_xfer.next = NULL; + read_status_xfer.fast_mode = true; + read_status_xfer.dev_addr = MPR121_I2C_ADDR; + read_status_xfer.mode = I2C_READ; + read_status_xfer.count[0] = 1; /* set touch status register address */ + read_status_xfer.data[0] = &read_status_sel_reg; + read_status_xfer.count[1] = 2; + read_status_xfer.data[1] = &read_status_buf; + read_status_xfer.tmo_ms = 1000; + read_status_xfer.callback = &touch_status_i2c_cb; + + imx233_i2c_transfer(&read_status_xfer); +} + +static inline int mpr121_write_reg(uint8_t reg, uint8_t data) +{ + return i2c_writemem(MPR121_I2C_ADDR, reg, &data, 1); +} + +static inline int mpr121_read_reg(uint8_t reg, uint8_t *data) +{ + return i2c_readmem(MPR121_I2C_ADDR, reg, data, 1); +} + +void mpr121_init(void) +{ + /* soft reset */ + mpr121_write_reg(REG_SOFTRESET, REG_SOFTRESET__MAGIC); + /* enable interrupt */ + imx233_pinctrl_acquire(0, 18, "mpr121_int"); + imx233_pinctrl_set_function(0, 18, PINCTRL_FUNCTION_GPIO); + imx233_pinctrl_enable_gpio(0, 18, false); + imx233_pinctrl_setup_irq(0, 18, true, true, false, &mpr121_irq_cb, 0); +} + +void mpr121_set_config(struct mpr121_config_t *conf) +{ + /* stop mode */ + mpr121_write_reg(REG_ELECTRODE, 0); + /* write baseline values */ + for(int i = 0; i < ELECTRODE_COUNT; i++) + mpr121_write_reg(REG_ExBV(i), conf->ele[i].bv); + /* write eleprox bv */ + mpr121_write_reg(REG_EPROXBV, conf->eleprox.bv); + /* write global fields */ + mpr121_write_reg(REG_MHDR, conf->filters.ele.rising.mhd); + mpr121_write_reg(REG_NHDR, conf->filters.ele.rising.nhd); + mpr121_write_reg(REG_NCLR, conf->filters.ele.rising.ncl); + mpr121_write_reg(REG_FDLR, conf->filters.ele.rising.fdl); + mpr121_write_reg(REG_MHDF, conf->filters.ele.falling.mhd); + mpr121_write_reg(REG_NHDF, conf->filters.ele.falling.nhd); + mpr121_write_reg(REG_NCLF, conf->filters.ele.falling.ncl); + mpr121_write_reg(REG_FDLF, conf->filters.ele.falling.fdl); + mpr121_write_reg(REG_NHDT, conf->filters.ele.touched.nhd); + mpr121_write_reg(REG_NCLT, conf->filters.ele.touched.ncl); + mpr121_write_reg(REG_FDLT, conf->filters.ele.touched.fdl); + mpr121_write_reg(REG_MHDPROXR, conf->filters.eleprox.rising.mhd); + mpr121_write_reg(REG_NHDPROXR, conf->filters.eleprox.rising.nhd); + mpr121_write_reg(REG_NCLPROXR, conf->filters.eleprox.rising.ncl); + mpr121_write_reg(REG_FDLPROXR, conf->filters.eleprox.rising.fdl); + mpr121_write_reg(REG_MHDPROXF, conf->filters.eleprox.falling.mhd); + mpr121_write_reg(REG_NHDPROXF, conf->filters.eleprox.falling.nhd); + mpr121_write_reg(REG_NCLPROXF, conf->filters.eleprox.falling.ncl); + mpr121_write_reg(REG_FDLPROXF, conf->filters.eleprox.falling.fdl); + mpr121_write_reg(REG_NHDPROXT, conf->filters.eleprox.touched.nhd); + mpr121_write_reg(REG_NCLPROXT, conf->filters.eleprox.touched.ncl); + mpr121_write_reg(REG_FDLPROXT, conf->filters.eleprox.touched.fdl); + /* touch & release thresholds */ + for(int i = 0; i < ELECTRODE_COUNT; i++) + { + mpr121_write_reg(REG_ExTTH(i), conf->ele[i].tth); + mpr121_write_reg(REG_ExRTH(i), conf->ele[i].rth); + } + mpr121_write_reg(REG_EPROXTTH, conf->eleprox.tth); + mpr121_write_reg(REG_EPROXRTH, conf->eleprox.rth); + /* debounce */ + mpr121_write_reg(REG_DEBOUNCE, REG_DEBOUNCE__DR(conf->debounce.dr) | + REG_DEBOUNCE__DT(conf->debounce.dt)); + /* analog-front end and filters */ + mpr121_write_reg(REG_AFE, REG_AFE__CDC(conf->global.cdc) | + REG_AFE__FFI(conf->global.ffi)); + mpr121_write_reg(REG_FILTER, REG_FILTER__CDT(conf->global.cdt) | + REG_FILTER__ESI(conf->global.esi) | REG_FILTER__SFI(conf->global.sfi)); + /* electrode charge */ + for(int i = 0; i < ELECTRODE_COUNT; i++) + mpr121_write_reg(REG_CDCx(i), conf->ele[i].cdc); + mpr121_write_reg(REG_CDCPROX, conf->eleprox.cdc); + for(int i = 0; i < ELECTRODE_COUNT; i += 2) + { + mpr121_write_reg(REG_CDTx(i), REG_CDTx__CDT0(conf->ele[i].cdt) | + REG_CDTx__CDT1(conf->ele[i+1].cdt)); + } + mpr121_write_reg(REG_CDTPROX, conf->eleprox.cdt); + /* Auto-Configuration */ + mpr121_write_reg(REG_AUTO_CONF, REG_AUTO_CONF__ACE(conf->autoconf.en) | + REG_AUTO_CONF__ARE(conf->autoconf.ren) | + REG_AUTO_CONF__BVA(conf->cal_lock) | + REG_AUTO_CONF__RETRY(conf->autoconf.retry) | + REG_AUTO_CONF__FFI(conf->global.ffi)); + mpr121_write_reg(REG_AUTO_CONF2, REG_AUTO_CONF2__ACFIE(conf->autoconf.acfie) | + REG_AUTO_CONF2__ARFIE(conf->autoconf.arfie) | + REG_AUTO_CONF2__OORIE(conf->autoconf.oorie) | + REG_AUTO_CONF2__SCTS(conf->autoconf.scts)); + mpr121_write_reg(REG_USL, conf->autoconf.usl); + mpr121_write_reg(REG_LSL, conf->autoconf.lsl); + mpr121_write_reg(REG_TL, conf->autoconf.tl); + /* electrode configuration */ + mpr121_write_reg(REG_ELECTRODE, REG_ELECTRODE__ELE_EN(conf->ele_en) | + REG_ELECTRODE__ELEPROX_EN(conf->eleprox_en) | + REG_ELECTRODE__CL(conf->cal_lock)); + /* gpio config */ + uint8_t ctl = 0; + for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) + if(ELE_GPIO_CTL0(conf->ele[i].gpio)) + ctl |= REG_GPIO_CTL0__CTL0x(i); + mpr121_write_reg(REG_GPIO_CTL0, ctl); + ctl = 0; + for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) + if(ELE_GPIO_CTL1(conf->ele[i].gpio)) + ctl |= REG_GPIO_CTL1__CTL1x(i); + mpr121_write_reg(REG_GPIO_CTL1, ctl); + ctl = 0; + for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) + if(ELE_GPIO_DIR(conf->ele[i].gpio)) + ctl |= REG_GPIO_DIR__DIRx(i); + mpr121_write_reg(REG_GPIO_DIR, ctl); + ctl = 0; + for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) + if(ELE_GPIO_EN(conf->ele[i].gpio)) + ctl |= REG_GPIO_EN__ENx(i); + mpr121_write_reg(REG_GPIO_EN, ctl); +} + +void mpr121_set_gpio_output(int ele, int gpio_val) +{ + switch(gpio_val) + { + case ELE_GPIO_SET: + mpr121_write_reg(REG_GPIO_SET, REG_GPIO_SET__SETx(ele)); + break; + case ELE_GPIO_CLR: + mpr121_write_reg(REG_GPIO_CLR, REG_GPIO_CLR__CLRx(ele)); + break; + case ELE_GPIO_TOG: + mpr121_write_reg(REG_GPIO_TOG, REG_GPIO_TOG__TOGx(ele)); + break; + default: + break; + } +} + +void mpr121_set_gpio_pwm(int ele, int pwm) +{ + uint8_t reg_val; + mpr121_read_reg(REG_PWMx(ele), ®_val); + if(REG_PWMx_IS_PWM0(ele)) + reg_val = (reg_val & ~REG_PWMx__PWM0_BM) | REG_PWMx__PWM0(pwm); + else + reg_val = (reg_val & ~REG_PWMx__PWM1_BM) | REG_PWMx__PWM1(pwm); + mpr121_write_reg(REG_PWMx(ele), reg_val); +} + +unsigned mpr121_get_touch_status(void) +{ + return touch_status; +} diff --git a/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.h b/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.h new file mode 100644 index 0000000000..eb8b00eeee --- /dev/null +++ b/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.h @@ -0,0 +1,176 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2016 Amaury Pouly + * + * 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 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __MPR121_ZENXFI3_H__ +#define __MPR121_ZENXFI3_H__ + +/** Driver for the Freescale MPR121 Capacitive Proximity Sensor */ +#include "system.h" + +#define ELECTRODE_COUNT 12 +#define ELE_GPIO_FIRST 4 +#define ELE_GPIO_LAST 11 + +/* gpio config (encoding: [0]=en,[1]=dir,[2]=ctl[1],[3]=ctl[0]) */ +#define ELE_GPIO_DISABLE 0 +#define ELE_GPIO_INPUT 1 +#define ELE_GPIO_INPUT_PULLDOWN 9 /* input with pull-down */ +#define ELE_GPIO_INPUT_PULLUP 13 /* input with pull-up */ +#define ELE_GPIO_OUTPUT 3 +#define ELE_GPIO_OUTPUT_OPEN 11 /* open drain low-side */ +#define ELE_GPIO_OUTPUT_OPEN_LED 15 /* open drain high-side (led driver) */ + +/* internal use */ +#define ELE_GPIO_EN(val) ((val) & 1) +#define ELE_GPIO_DIR(val) (((val) >> 1) & 1) +#define ELE_GPIO_CTL0(val) (((val) >> 3) & 1) +#define ELE_GPIO_CTL1(val) (((val) >> 1) & 1) + +struct mpr121_electrode_config_t +{ + uint8_t bv; /* baseline value */ + uint8_t tth; /* touch threshold */ + uint8_t rth; /* release threshold */ + uint8_t cdc; /* charge current (optional if auto-conf) */ + uint8_t cdt; /* charge time (optional if auto-conf) */ + int gpio; /* gpio config */ +}; + +struct mpr121_baseline_filter_config_t +{ + uint8_t mhd; /* max half delta (except for touched) */ + uint8_t nhd; /* noise half delta */ + uint8_t ncl; /* noise count limit */ + uint8_t fdl; /* filter delay count limit */ +}; + +struct mpr121_baseline_filters_config_t +{ + struct mpr121_baseline_filter_config_t rising; + struct mpr121_baseline_filter_config_t falling; + struct mpr121_baseline_filter_config_t touched; +}; + +struct mpr121_debounce_config_t +{ + uint8_t dt; /* debounce count for touch */ + uint8_t dr; /* debounce count for release */ +}; + +/* first filter iterations */ +#define FFI_6_SAMPLES 0 +#define FFI_10_SAMPLES 1 +#define FFI_18_SAMPLES 2 +#define FFI_34_SAMPLES 3 +/* charge discharge current */ +#define CDC_DISABLE 0 +#define CDC_uA(ua) (ua) +/* charge discharge time */ +#define CDT_DISABLE 0 +#define CDT_log_us(lus) (lus) /* actual value = 2^{us-2} µs */ +/* second filter iterations */ +#define SFI_4_SAMPLES 0 +#define SFI_6_SAMPLES 1 +#define SFI_10_SAMPLES 2 +#define SFI_18_SAMPLES 3 +/* Eletrode sample interval */ +#define ESI_log_ms(lms) (lms) /* actual value = 2^{lms} ms */ + +struct mpr121_global_config_t +{ + uint8_t ffi; /* first filter iterations */ + uint8_t cdc; /* global charge discharge current */ + uint8_t cdt; /* global charge discharge time */ + uint8_t sfi; /* second first iterations */ + uint8_t esi; /* electrode sample interval */ +}; + +#define RETRY_NEVER 0 +#define RETRY_2_TIMES 1 +#define RETRY_4_TIMES 2 +#define RETRY_8_TIMES 3 + +struct mpr121_auto_config_t +{ + bool en; /* auto-conf enable */ + bool ren; /* auto-reconf enable */ + uint8_t retry; /* retry count */ + bool scts; /* skip charge time search */ + uint8_t usl; /* upper-side limit */ + uint8_t lsl; /* lower-side limit */ + uint8_t tl; /* target level */ + bool acfie; /* auto-conf fail interrupt en */ + bool arfie; /* auto-reconf fail interrupt en */ + bool oorie; /* out of range interrupt en */ +}; + +/* electrode mode */ +#define ELE_DISABLE 0 +#define ELE_EN0_x(x) ((x) + 1) +/* eleprox mode */ +#define ELEPROX_DISABLE 0 +#define ELEPROX_EN0_1 1 +#define ELEPROX_EN0_3 2 +#define ELEPROX_EN0_11 3 +/* calibration lock */ +#define CL_SLOW_TRACK 0 +#define CL_DISABLE 1 +#define CL_TRACK 2 +#define CL_FAST_TRACK 3 + +struct mpr121_config_t +{ + struct mpr121_electrode_config_t ele[ELECTRODE_COUNT]; + struct mpr121_electrode_config_t eleprox; + struct + { + struct mpr121_baseline_filters_config_t ele; + struct mpr121_baseline_filters_config_t eleprox; + }filters; + struct mpr121_debounce_config_t debounce; + struct mpr121_global_config_t global; + struct mpr121_auto_config_t autoconf; + uint8_t ele_en; /* eletroce mode */ + uint8_t eleprox_en; /* proximity mode */ + uint8_t cal_lock; /* calibration lock */ +}; + +/* gpio value */ +#define ELE_GPIO_CLR 0 +#define ELE_GPIO_SET 1 +#define ELE_GPIO_TOG 2 +/* pwm value */ +#define ELE_PWM_DISABLE 0 +#define ELE_PWM_DUTY(x) (x) +#define ELE_PWM_MIN_DUTY 1 +#define ELE_PWM_MAX_DUTY 15 + +void mpr121_init(void); +void mpr121_set_config(struct mpr121_config_t *conf); +/* gpios are only implemented for electrode>=4, use ELE_GPIO_* for value */ +void mpr121_set_gpio_output(int ele, int gpio_val); +/* pwm value is between 0 and 15, use ELE_PWM_DISABLE or ELE_PWM_DUTY */ +void mpr121_set_gpio_pwm(int ele, int pwm); +/* get electrode status (bitmap) + * NOTE this function merely returns the last electrode status read from the + * device and does not actively ask the device for touch status. */ +unsigned mpr121_get_touch_status(void); + +#endif /* __MPR121_ZENXFI3_H__ */