/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 *
 * 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__ */
