summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Troast <ntroast@codeaurora.org>2017-07-06 07:43:13 -0700
committerAbhijeet Dharmapurikar <adharmap@codeaurora.org>2017-07-31 19:28:02 -0700
commit175907d3d24005e8557dbff1808649cabbf9414a (patch)
treeb911fbae56e27d40b58cfb015015ed6b98ea27d3
parent3c21390e3c2f3c526f33ae0226307f4cc579d0fd (diff)
power: fg-util: add median filter for circular buffer
A median filter is useful for filtering out outliers. Add it. Change-Id: I21f97a870c262e5fb3d33b8250a2bf074f519b58 Signed-off-by: Nicholas Troast <ntroast@codeaurora.org> Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
-rw-r--r--drivers/power/supply/qcom/fg-core.h3
-rw-r--r--drivers/power/supply/qcom/fg-util.c34
2 files changed, 36 insertions, 1 deletions
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index e137a373937d..719f09a7c372 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -311,7 +311,7 @@ struct fg_irq_info {
};
struct fg_circ_buf {
- int arr[20];
+ int arr[10];
int size;
int head;
};
@@ -483,5 +483,6 @@ extern bool is_qnovo_en(struct fg_chip *chip);
extern void fg_circ_buf_add(struct fg_circ_buf *, int);
extern void fg_circ_buf_clr(struct fg_circ_buf *);
extern int fg_circ_buf_avg(struct fg_circ_buf *, int *);
+extern int fg_circ_buf_median(struct fg_circ_buf *, int *);
extern int fg_lerp(const struct fg_pt *, size_t, s32, s32 *);
#endif
diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c
index 9635044e02a5..0cb1dea7113b 100644
--- a/drivers/power/supply/qcom/fg-util.c
+++ b/drivers/power/supply/qcom/fg-util.c
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/sort.h>
#include "fg-core.h"
void fg_circ_buf_add(struct fg_circ_buf *buf, int val)
@@ -39,6 +40,39 @@ int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg)
return 0;
}
+static int cmp_int(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
+int fg_circ_buf_median(struct fg_circ_buf *buf, int *median)
+{
+ int *temp;
+
+ if (buf->size == 0)
+ return -ENODATA;
+
+ if (buf->size == 1) {
+ *median = buf->arr[0];
+ return 0;
+ }
+
+ temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+
+ memcpy(temp, buf->arr, buf->size * sizeof(*temp));
+ sort(temp, buf->size, sizeof(*temp), cmp_int, NULL);
+
+ if (buf->size % 2)
+ *median = temp[buf->size / 2];
+ else
+ *median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2;
+
+ kfree(temp);
+ return 0;
+}
+
int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input, s32 *output)
{
int i;