xref: /OK3568_Linux_fs/kernel/drivers/misc/echo/fir.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SpanDSP - a series of DSP components for telephony
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * fir.h - General telephony FIR routines
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Written by Steve Underwood <steveu@coppice.org>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Copyright (C) 2002 Steve Underwood
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * All rights reserved.
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #if !defined(_FIR_H_)
15*4882a593Smuzhiyun #define _FIR_H_
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /*
18*4882a593Smuzhiyun    Ideas for improvement:
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun    1/ Rewrite filter for dual MAC inner loop.  The issue here is handling
21*4882a593Smuzhiyun    history sample offsets that are 16 bit aligned - the dual MAC needs
22*4882a593Smuzhiyun    32 bit aligmnent.  There are some good examples in libbfdsp.
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun    2/ Use the hardware circular buffer facility tohalve memory usage.
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun    3/ Consider using internal memory.
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun    Using less memory might also improve speed as cache misses will be
29*4882a593Smuzhiyun    reduced. A drop in MIPs and memory approaching 50% should be
30*4882a593Smuzhiyun    possible.
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun    The foreground and background filters currenlty use a total of
33*4882a593Smuzhiyun    about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo
34*4882a593Smuzhiyun    can.
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun  * 16 bit integer FIR descriptor. This defines the working state for a single
39*4882a593Smuzhiyun  * instance of an FIR filter using 16 bit integer coefficients.
40*4882a593Smuzhiyun  */
41*4882a593Smuzhiyun struct fir16_state_t {
42*4882a593Smuzhiyun 	int taps;
43*4882a593Smuzhiyun 	int curr_pos;
44*4882a593Smuzhiyun 	const int16_t *coeffs;
45*4882a593Smuzhiyun 	int16_t *history;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /*
49*4882a593Smuzhiyun  * 32 bit integer FIR descriptor. This defines the working state for a single
50*4882a593Smuzhiyun  * instance of an FIR filter using 32 bit integer coefficients, and filtering
51*4882a593Smuzhiyun  * 16 bit integer data.
52*4882a593Smuzhiyun  */
53*4882a593Smuzhiyun struct fir32_state_t {
54*4882a593Smuzhiyun 	int taps;
55*4882a593Smuzhiyun 	int curr_pos;
56*4882a593Smuzhiyun 	const int32_t *coeffs;
57*4882a593Smuzhiyun 	int16_t *history;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /*
61*4882a593Smuzhiyun  * Floating point FIR descriptor. This defines the working state for a single
62*4882a593Smuzhiyun  * instance of an FIR filter using floating point coefficients and data.
63*4882a593Smuzhiyun  */
64*4882a593Smuzhiyun struct fir_float_state_t {
65*4882a593Smuzhiyun 	int taps;
66*4882a593Smuzhiyun 	int curr_pos;
67*4882a593Smuzhiyun 	const float *coeffs;
68*4882a593Smuzhiyun 	float *history;
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
fir16_create(struct fir16_state_t * fir,const int16_t * coeffs,int taps)71*4882a593Smuzhiyun static inline const int16_t *fir16_create(struct fir16_state_t *fir,
72*4882a593Smuzhiyun 					      const int16_t *coeffs, int taps)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	fir->taps = taps;
75*4882a593Smuzhiyun 	fir->curr_pos = taps - 1;
76*4882a593Smuzhiyun 	fir->coeffs = coeffs;
77*4882a593Smuzhiyun 	fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
78*4882a593Smuzhiyun 	return fir->history;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
fir16_flush(struct fir16_state_t * fir)81*4882a593Smuzhiyun static inline void fir16_flush(struct fir16_state_t *fir)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	memset(fir->history, 0, fir->taps * sizeof(int16_t));
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
fir16_free(struct fir16_state_t * fir)86*4882a593Smuzhiyun static inline void fir16_free(struct fir16_state_t *fir)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	kfree(fir->history);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
fir16(struct fir16_state_t * fir,int16_t sample)91*4882a593Smuzhiyun static inline int16_t fir16(struct fir16_state_t *fir, int16_t sample)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	int32_t y;
94*4882a593Smuzhiyun 	int i;
95*4882a593Smuzhiyun 	int offset1;
96*4882a593Smuzhiyun 	int offset2;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	fir->history[fir->curr_pos] = sample;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	offset2 = fir->curr_pos;
101*4882a593Smuzhiyun 	offset1 = fir->taps - offset2;
102*4882a593Smuzhiyun 	y = 0;
103*4882a593Smuzhiyun 	for (i = fir->taps - 1; i >= offset1; i--)
104*4882a593Smuzhiyun 		y += fir->coeffs[i] * fir->history[i - offset1];
105*4882a593Smuzhiyun 	for (; i >= 0; i--)
106*4882a593Smuzhiyun 		y += fir->coeffs[i] * fir->history[i + offset2];
107*4882a593Smuzhiyun 	if (fir->curr_pos <= 0)
108*4882a593Smuzhiyun 		fir->curr_pos = fir->taps;
109*4882a593Smuzhiyun 	fir->curr_pos--;
110*4882a593Smuzhiyun 	return (int16_t) (y >> 15);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
fir32_create(struct fir32_state_t * fir,const int32_t * coeffs,int taps)113*4882a593Smuzhiyun static inline const int16_t *fir32_create(struct fir32_state_t *fir,
114*4882a593Smuzhiyun 					      const int32_t *coeffs, int taps)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	fir->taps = taps;
117*4882a593Smuzhiyun 	fir->curr_pos = taps - 1;
118*4882a593Smuzhiyun 	fir->coeffs = coeffs;
119*4882a593Smuzhiyun 	fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
120*4882a593Smuzhiyun 	return fir->history;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
fir32_flush(struct fir32_state_t * fir)123*4882a593Smuzhiyun static inline void fir32_flush(struct fir32_state_t *fir)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	memset(fir->history, 0, fir->taps * sizeof(int16_t));
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
fir32_free(struct fir32_state_t * fir)128*4882a593Smuzhiyun static inline void fir32_free(struct fir32_state_t *fir)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	kfree(fir->history);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
fir32(struct fir32_state_t * fir,int16_t sample)133*4882a593Smuzhiyun static inline int16_t fir32(struct fir32_state_t *fir, int16_t sample)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	int i;
136*4882a593Smuzhiyun 	int32_t y;
137*4882a593Smuzhiyun 	int offset1;
138*4882a593Smuzhiyun 	int offset2;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	fir->history[fir->curr_pos] = sample;
141*4882a593Smuzhiyun 	offset2 = fir->curr_pos;
142*4882a593Smuzhiyun 	offset1 = fir->taps - offset2;
143*4882a593Smuzhiyun 	y = 0;
144*4882a593Smuzhiyun 	for (i = fir->taps - 1; i >= offset1; i--)
145*4882a593Smuzhiyun 		y += fir->coeffs[i] * fir->history[i - offset1];
146*4882a593Smuzhiyun 	for (; i >= 0; i--)
147*4882a593Smuzhiyun 		y += fir->coeffs[i] * fir->history[i + offset2];
148*4882a593Smuzhiyun 	if (fir->curr_pos <= 0)
149*4882a593Smuzhiyun 		fir->curr_pos = fir->taps;
150*4882a593Smuzhiyun 	fir->curr_pos--;
151*4882a593Smuzhiyun 	return (int16_t) (y >> 15);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun #endif
155