#include <linux/math64.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>

#define DEVICE_NAME "dialer"
#define COMPAT      "phone,dialer"
#define PREFIX DEVICE_NAME ": "
#define DEBUG(...) if(debug) pr_info(PREFIX __VA_ARGS__);
#define MAX_PULSES 20

MODULE_LICENSE      ("GPL");
MODULE_AUTHOR       ("Mochi the Dog");
MODULE_DESCRIPTION  ("A trivial input device driver for a cheap rotary phone dialer tied to a GPIO pin.");
MODULE_VERSION      ("1.0");

static int debug = 0;
module_param(debug, int, 0600);

static int              irq;
static struct gpio_desc *data_in;
static struct input_dev *input_dev;
static bool             sampling = false;
static int              button_count = 13;
static int              buttons[] = {
                            0,
                            KEY_1,
                            KEY_2,
                            KEY_3,
                            KEY_4,
                            KEY_5,
                            KEY_6,
                            KEY_7,
                            KEY_8,
                            KEY_9,
                            KEY_0,
                            KEY_KPASTERISK,
                            KEY_R,
                            };

static int read_pulses(struct gpio_desc *data_in, int ms_per_pulse) {
    int i;
    u64 expected_pulses;
    u64 pulse_sum, gap_sum;
    int pulse_count, gap_count;
    u64 avg_pulse, avg_gap;
    u64 pulse_width, gap_width;
    int level;
    int last_level = 0;
    u64 pulse_widths[MAX_PULSES] = {0};
    u64 gap_widths[MAX_PULSES] = {0};
    int pulse_width_i = 0;
    int gap_width_i = 0;
    u64 now;
    u64 sequence_time;
    u64 start_time = ktime_get_ns();
    u64 last_high = start_time;
    u64 last_low = start_time;

    // We'll take one sample per millisecond.
    // Aim for at least 2 samples per pulse (Nyquist rate).
    int samples_per_pulse = 2;
    // We'll never have more than 12 pulses out of a standard rotary dialer.
    // Remember that each pulse has a pause after it.
    // Throw in some healthy padding, though, since our pulse width (ms_per_pulse) is a little thin.
    int max_samples = (12 * 2) * samples_per_pulse * 2;
    // We'll take a subsample every 1 ms.
    int subsamples_per_sample = ms_per_pulse / samples_per_pulse;
    // If a sample is more than half high, the sample is high.
    int enough_highs = subsamples_per_sample / 2;
    // Ulitmately, we're counting edges.  There should be 2 per pulse.
    int edges = 0;

    int highs; // Accumulator for the high subsamples within a sample.
    int sample; // The logical value of the sample.
    int subsample; // Subsample counter.
    int sample_history = 1; // A bitfield representing the sample history.

    while(max_samples--) {
        highs = 0;
        // Take a subsample roughly each ms.
        for(subsample=0; subsample < subsamples_per_sample; subsample++) {
            // Rpi0w: ~300ns for gpiod_get_value.
            level = gpiod_get_value(data_in);
            now = ktime_get_ns();
            if(level == 0) {
                if(last_level == 1) {
                    // Falling edge.  Record width of the last pulse.
                    pulse_width = now - last_low;
                    if(pulse_width > 5000000) {
                        if(pulse_width_i < MAX_PULSES) pulse_widths[pulse_width_i++] = pulse_width;
                        }
                    }
                last_low = now;
                }
            else {
                if(last_level == 0) {
                    // Rising edge. Record the width of the last gap.
                    gap_width = now - last_high;
                    // Don't count a gap if it's under 5ms or longer than 50ms.
                    // This dialer misses some pulses, which results in gaps that are around 80ms (two regular gaps and a pulse).
                    // We need to ignore these, or it throws off our average gap calculation.
                    if(5000000 < gap_width && gap_width < 50000000) {
                        if(gap_width_i < MAX_PULSES) gap_widths[gap_width_i++] = gap_width;
                        }
                    }
                last_high = now;
                }
            highs += level;
            last_level = level;
            // Let the kernel do something else while we wait for the next sample.
            usleep_range(400, 500);
            }
        // This sample is high if half or more of the subsamples were high.
        sample = highs >> 1 >= enough_highs;

        // If this sample is the opposite of the last one (LSB of sample_history), we've crossed an edge.
        if(sample != (sample_history & 1)) edges++;

        // Record the sample history in a bitfield.  LSB is most recent sample.
        sample_history = sample_history << 1 | sample;

        if(sample) last_high = ktime_get_ns();

        // If the last 16 samples were low, go home early.
        if(!(sample_history & 0xffff)) {
            DEBUG("Sampled 16 consecutive lows. Breaking.\n");
            break;
            }
        }
    pulse_count = pulse_width_i;
    gap_count = gap_width_i;
    sequence_time = last_high - start_time;

    // Get an average of pulse widths.
    pulse_sum = 0;
    for(i = 0; i < pulse_width_i; i++) pulse_sum += pulse_widths[i];
    avg_pulse = DIV64_U64_ROUND_CLOSEST(pulse_sum, pulse_count);
    // Get an average of the gap width.
    gap_sum = 0;
    for(i = 0; i < gap_width_i; i++) gap_sum += gap_widths[i];
    avg_gap = DIV64_U64_ROUND_CLOSEST(gap_sum, gap_width_i);

    // Computed expected pulses based on overall sequence length and average pulse and gap width.
    // This should compensate for the occasional pulses that this dialer drops.
    expected_pulses = DIV64_U64_ROUND_CLOSEST(sequence_time + avg_gap, avg_pulse + avg_gap);

    /*
    pr_info(PREFIX "pulses\n");
    for(i = 0; i < pulse_width_i; i++) pr_info(PREFIX "%d: %lld ns.", i, pulse_widths[i]);
    pr_info(PREFIX "gaps\n");
    for(i = 0; i < gap_width_i; i++) pr_info(PREFIX "%d: %lld ns.", i, gap_widths[i]);
    */

    pr_info(PREFIX "Sequence took %lld ns; avg_pulse: %lld ns; avg_gap: %lld ns; counted %d pulses; expected %lld pulses.\n",
        sequence_time + avg_gap,
        avg_pulse,
        avg_gap,
        pulse_count,
        expected_pulses);
    if(expected_pulses != pulse_count) pr_info(PREFIX "DROPPED PULSE.\n");
    return expected_pulses;
    }

static irqreturn_t irq_handler(int irq, void *dev) {
    return sampling ? IRQ_HANDLED : IRQ_WAKE_THREAD;
    }

static irqreturn_t irq_thread(int irq, void *dev) {
    int pulses;
    sampling = true;
    pulses = read_pulses(data_in, 25);
    pr_info(PREFIX "Counted %d pulses.\n", pulses);
    if(pulses && pulses < button_count) {
        input_report_key(input_dev, buttons[pulses], 1);
        input_report_key(input_dev, buttons[pulses], 0);
        input_sync(input_dev);
        }
    sampling = false;
    return IRQ_HANDLED;
    }

static int dialer_probe(struct platform_device *pdev) {
    int i;
    int button;
    int err;
    input_dev = input_allocate_device();
    if(IS_ERR(input_dev)) {
        pr_err(PREFIX "Can't allocate input device: %pe\n", input_dev);
        return -1;
        }
    input_dev->name = DEVICE_NAME;
    input_dev->evbit[0] |= BIT_MASK(EV_KEY);
    for(i=0; i<button_count; i++) {
        button = buttons[i];
        input_dev->keybit[BIT_WORD(button)] |= BIT_MASK(button);
        }

    err = input_register_device(input_dev);
    if(err) {
        pr_err(PREFIX "Unable to register input device: %d\n", err);
        return -1;
        }
    data_in = gpiod_get(&pdev->dev, "din", GPIOD_IN);
    if(IS_ERR(data_in)) {
        pr_err(PREFIX "Unable to obtain GPIO data_in: %pe\n", data_in);
        return -1;
        }
    DEBUG("Using GPIO %d.\n", desc_to_gpio(data_in));
    irq = gpiod_to_irq(data_in);
    DEBUG("Assigned IRQ %d.\n", irq);
    err = request_threaded_irq(irq, (void*)irq_handler, (void*)irq_thread, IRQF_TRIGGER_RISING, DEVICE_NAME, (void*)pdev);
    if(err) {
        pr_err(PREFIX "Unable to request IRQ: %d\n", err);
        return err;
        }
    return 0;
    }

static int dialer_remove(struct platform_device *pdev) {
    DEBUG("Removing device.\n");
    free_irq(irq, (void*)pdev);
    gpiod_put(data_in);
    input_unregister_device(input_dev);
    return 0;
    }

static const struct of_device_id of_dialer_match[] = {
    { .compatible = COMPAT, },
    {},
    };
MODULE_DEVICE_TABLE(of, of_dialer_match);

static struct platform_driver dialer_driver = {
    .probe      = dialer_probe,
    .remove     = dialer_remove,
    .driver     = {
        .name = DEVICE_NAME,
        .of_match_table = of_dialer_match,
        },
    };

module_platform_driver(dialer_driver);
