xref: /openbmc/linux/lib/math/cordic.c (revision 349d03ff)
1 /*
2  * Copyright (c) 2011 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include <linux/module.h>
17 #include <linux/cordic.h>
18 
19 static const s32 arctan_table[] = {
20 	2949120,
21 	1740967,
22 	919879,
23 	466945,
24 	234379,
25 	117304,
26 	58666,
27 	29335,
28 	14668,
29 	7334,
30 	3667,
31 	1833,
32 	917,
33 	458,
34 	229,
35 	115,
36 	57,
37 	29
38 };
39 
40 /*
41  * cordic_calc_iq() - calculates the i/q coordinate for given angle
42  *
43  * theta: angle in degrees for which i/q coordinate is to be calculated
44  * coord: function output parameter holding the i/q coordinate
45  */
46 struct cordic_iq cordic_calc_iq(s32 theta)
47 {
48 	struct cordic_iq coord;
49 	s32 angle, valtmp;
50 	unsigned iter;
51 	int signx = 1;
52 	int signtheta;
53 
54 	coord.i = CORDIC_ANGLE_GEN;
55 	coord.q = 0;
56 	angle = 0;
57 
58 	theta = CORDIC_FIXED(theta);
59 	signtheta = (theta < 0) ? -1 : 1;
60 	theta = ((theta + CORDIC_FIXED(180) * signtheta) % CORDIC_FIXED(360)) -
61 		CORDIC_FIXED(180) * signtheta;
62 
63 	if (CORDIC_FLOAT(theta) > 90) {
64 		theta -= CORDIC_FIXED(180);
65 		signx = -1;
66 	} else if (CORDIC_FLOAT(theta) < -90) {
67 		theta += CORDIC_FIXED(180);
68 		signx = -1;
69 	}
70 
71 	for (iter = 0; iter < CORDIC_NUM_ITER; iter++) {
72 		if (theta > angle) {
73 			valtmp = coord.i - (coord.q >> iter);
74 			coord.q += (coord.i >> iter);
75 			angle += arctan_table[iter];
76 		} else {
77 			valtmp = coord.i + (coord.q >> iter);
78 			coord.q -= (coord.i >> iter);
79 			angle -= arctan_table[iter];
80 		}
81 		coord.i = valtmp;
82 	}
83 
84 	coord.i *= signx;
85 	coord.q *= signx;
86 	return coord;
87 }
88 EXPORT_SYMBOL(cordic_calc_iq);
89 
90 MODULE_DESCRIPTION("CORDIC algorithm");
91 MODULE_AUTHOR("Broadcom Corporation");
92 MODULE_LICENSE("Dual BSD/GPL");
93