blob: 7c0c6f6a20723af3b46409bf58df3b5f28c267d3 [file] [log] [blame]
Kyle Swensoncc33c242022-05-16 10:38:04 -06001/*
2 * ./kernel_modules/qcom-adc/adc-averaging.c
3 *
4 * This file does some basic FIR averaging on a fifo; it is intended to be used
5 * with the ADS7924 device driver
6 *
7 * Author: Cradlepoint Technology, Inc. <source@cradlepoint.com>
8 * Kyle Swenson <kswenson@cradlepoint.com>
9 *
10 * Copyright 2017 Cradlepoint Technology, Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 */
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/slab.h>
26#include "adc-averaging.h"
27
28
29void free_adc_channel(struct adc_channel *ch)
30{
31 if (ch->samples) {
32 kfree(ch->samples);
33 }
34 kfree(ch);
35}
36
37struct adc_channel *create_adc_channel(uint16_t fifo_length)
38{
39 struct adc_channel *ch;
40 if (fifo_length >= MAX_SAMPLE_LENGTH) {
41 printk(KERN_ALERT "Requested a ADC buffer length (%u) exceedes max (%u)\n", fifo_length, MAX_SAMPLE_LENGTH);
42 return NULL;
43
44 }
45 ch = (struct adc_channel *) kzalloc(sizeof(struct adc_channel), GFP_KERNEL);
46 if (!ch) {
47 printk(KERN_ALERT "Failed to allocate new ADC channel\n");
48 return NULL;
49 }
50 ch->samples = (uint16_t *) kzalloc(sizeof(uint16_t) * fifo_length, GFP_KERNEL);
51 if (!ch->samples) {
52 kfree(ch);
53 printk(KERN_ALERT "Failled to allocate new ADC channel buffer\n");
54 return NULL;
55 }
56 ch->total_length = fifo_length;
57 ch->index = 0;
58 mutex_init(&ch->lock);
59 return ch;
60}
61
62uint16_t compute_average(struct adc_channel *ch)
63{
64 uint32_t sum=0;
65 uint16_t average;
66 int i = 0;
67 mutex_lock(&ch->lock);
68 for (i = 0; i < ch->total_length; i++) {
69 sum += ch->samples[i];
70 }
71 average = DIV_ROUND_CLOSEST(sum, ch->total_length);
72 mutex_unlock(&ch->lock);
73 return average;
74}
75
76void add_sample(struct adc_channel *ch, uint16_t sample)
77{
78 mutex_lock(&ch->lock);
79 ch->samples[ch->index++] = sample;
80 if (ch->index >= ch->total_length)
81 ch->index = 0;
82 mutex_unlock(&ch->lock);
83}