blob: d4053719929288eca3ece0e5f432411edee14232 [file] [log] [blame]
/*
* ./kernel_modules/qcom-adc/adc-averaging.c
*
* This file does some basic FIR averaging on a fifo; it is intended to be used
* with the ADS7924 device driver
*
* Author: Cradlepoint Technology, Inc. <source@cradlepoint.com>
* Kyle Swenson <kswenson@cradlepoint.com>
*
* Copyright 2017 Cradlepoint Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
#include "adc-averaging.h"
void free_adc_channel(struct adc_channel *ch)
{
mutex_lock(&ch->lock);
if (ch->samples) {
devm_kfree(ch->parent, ch->samples);
ch->samples = NULL;
}
mutex_unlock(&ch->lock);
mutex_destroy(&ch->lock);
devm_kfree(ch->parent, ch);
}
struct adc_channel *create_adc_channel(struct device * dev, uint16_t fifo_length)
{
struct adc_channel *ch;
if (fifo_length >= MAX_SAMPLE_LENGTH) {
printk(KERN_ALERT "Requested a ADC buffer length (%u) exceedes max (%u)\n", fifo_length, MAX_SAMPLE_LENGTH);
return NULL;
}
ch = devm_kzalloc(dev, sizeof(struct adc_channel), GFP_KERNEL);
if (!ch)
return NULL;
ch->samples = devm_kzalloc(dev, sizeof(uint16_t) * fifo_length, GFP_KERNEL);
if (!ch->samples)
return NULL;
ch->total_length = fifo_length;
ch->index = 0;
mutex_init(&ch->lock);
ch->parent = dev;
return ch;
}
uint16_t compute_average(struct adc_channel *ch)
{
uint32_t sum=0;
uint16_t average;
int i = 0;
mutex_lock(&ch->lock);
for (i = 0; i < ch->total_length; i++) {
sum += ch->samples[i];
}
average = DIV_ROUND_CLOSEST(sum, ch->total_length);
mutex_unlock(&ch->lock);
return average;
}
void add_sample(struct adc_channel *ch, uint16_t sample)
{
mutex_lock(&ch->lock);
ch->samples[ch->index++] = sample;
if (ch->index >= ch->total_length)
ch->index = 0;
mutex_unlock(&ch->lock);
}