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 #define CORDIC_ANGLE_GEN	39797
20 #define CORDIC_PRECISION_SHIFT	16
21 #define	CORDIC_NUM_ITER		(CORDIC_PRECISION_SHIFT + 2)
22 
23 #define	FIXED(X)	((s32)((X) << CORDIC_PRECISION_SHIFT))
24 #define	FLOAT(X)	(((X) >= 0) \
25 		? ((((X) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1) \
26 		: -((((-(X)) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1))
27 
28 static const s32 arctan_table[] = {
29 	2949120,
30 	1740967,
31 	919879,
32 	466945,
33 	234379,
34 	117304,
35 	58666,
36 	29335,
37 	14668,
38 	7334,
39 	3667,
40 	1833,
41 	917,
42 	458,
43 	229,
44 	115,
45 	57,
46 	29
47 };
48 
49 /*
50  * cordic_calc_iq() - calculates the i/q coordinate for given angle
51  *
52  * theta: angle in degrees for which i/q coordinate is to be calculated
53  * coord: function output parameter holding the i/q coordinate
54  */
cordic_calc_iq(s32 theta)55 struct cordic_iq cordic_calc_iq(s32 theta)
56 {
57 	struct cordic_iq coord;
58 	s32 angle, valtmp;
59 	unsigned iter;
60 	int signx = 1;
61 	int signtheta;
62 
63 	coord.i = CORDIC_ANGLE_GEN;
64 	coord.q = 0;
65 	angle = 0;
66 
67 	theta = FIXED(theta);
68 	signtheta = (theta < 0) ? -1 : 1;
69 	theta = ((theta + FIXED(180) * signtheta) % FIXED(360)) -
70 		FIXED(180) * signtheta;
71 
72 	if (FLOAT(theta) > 90) {
73 		theta -= FIXED(180);
74 		signx = -1;
75 	} else if (FLOAT(theta) < -90) {
76 		theta += FIXED(180);
77 		signx = -1;
78 	}
79 
80 	for (iter = 0; iter < CORDIC_NUM_ITER; iter++) {
81 		if (theta > angle) {
82 			valtmp = coord.i - (coord.q >> iter);
83 			coord.q += (coord.i >> iter);
84 			angle += arctan_table[iter];
85 		} else {
86 			valtmp = coord.i + (coord.q >> iter);
87 			coord.q -= (coord.i >> iter);
88 			angle -= arctan_table[iter];
89 		}
90 		coord.i = valtmp;
91 	}
92 
93 	coord.i *= signx;
94 	coord.q *= signx;
95 	return coord;
96 }
97 EXPORT_SYMBOL(cordic_calc_iq);
98 
99 MODULE_DESCRIPTION("CORDIC algorithm");
100 MODULE_AUTHOR("Broadcom Corporation");
101 MODULE_LICENSE("Dual BSD/GPL");
102