summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_x1000/aic-x1000.c
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-02-27 22:08:58 +0000
committerAidan MacDonald <amachronic@protonmail.com>2021-03-28 00:01:37 +0000
commit3ec66893e377b088c1284d2d23adb2aeea6d7965 (patch)
treeb647717f83ad56b15dc42cfdef5d04d68cd9bd6b /firmware/target/mips/ingenic_x1000/aic-x1000.c
parent83fcbedc65f4b9ae7e491ecf6f07c0af4b245f74 (diff)
downloadrockbox-3ec66893e377b088c1284d2d23adb2aeea6d7965.tar.gz
rockbox-3ec66893e377b088c1284d2d23adb2aeea6d7965.zip
New port: FiiO M3K on bare metal
Change-Id: I7517e7d5459e129dcfc9465c6fbd708619888fbe
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/aic-x1000.c')
-rw-r--r--firmware/target/mips/ingenic_x1000/aic-x1000.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_x1000/aic-x1000.c b/firmware/target/mips/ingenic_x1000/aic-x1000.c
new file mode 100644
index 0000000000..a0e509d3b6
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/aic-x1000.c
@@ -0,0 +1,119 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "system.h"
23#include "aic-x1000.h"
24#include "gpio-x1000.h"
25#include "x1000/aic.h"
26#include "x1000/cpm.h"
27
28/* Given a rational number m/n < 1, find its representation as a continued
29 * fraction [0; a1, a2, a3, ..., a_k]. At most "cnt" terms are calculated
30 * and written out to "buf". Returns the number of terms written; the result
31 * is complete if this value is less than "cnt", and may be incomplete if it
32 * is equal to "cnt". (Note the leading zero term is not written to "buf".)
33 */
34static unsigned cf_derive(unsigned m, unsigned n, unsigned* buf, unsigned cnt)
35{
36 unsigned wrote = 0;
37 unsigned a = m / n;
38 while(cnt--) {
39 unsigned tmp = n;
40 n = m - n * a;
41 if(n == 0)
42 break;
43
44 m = tmp;
45 a = m / n;
46 *buf++ = a;
47 wrote++;
48 }
49
50 return wrote;
51}
52
53/* Given a finite continued fraction [0; buf[0], buf[1], ..., buf[count-1]],
54 * calculate the rational number m/n which it represents. Returns m and n.
55 * If count is zero, then m and n are undefined.
56 */
57static void cf_expand(const unsigned* buf, unsigned count,
58 unsigned* m, unsigned* n)
59{
60 if(count == 0)
61 return;
62
63 unsigned i = count - 1;
64 unsigned mx = 1, nx = buf[i];
65 while(i--) {
66 unsigned tmp = nx;
67 nx = mx + buf[i] * nx;
68 mx = tmp;
69 }
70
71 *m = mx;
72 *n = nx;
73}
74
75int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult)
76{
77 /* get the input clock rate */
78 uint32_t src_freq = clk_get(clksrc);
79
80 /* reject invalid parameters */
81 if(mult % 64 != 0)
82 return -1;
83
84 if(clksrc == X1000_EXCLK_FREQ) {
85 if(mult != 0)
86 return -1;
87
88 jz_writef(AIC_I2SCR, STPBK(1));
89 jz_writef(CPM_I2SCDR, CS(0), CE(0));
90 REG_AIC_I2SDIV = X1000_EXCLK_FREQ / 64 / fs;
91 } else {
92 if(mult == 0)
93 return -1;
94 if(fs*mult > src_freq)
95 return -1;
96
97 /* calculate best rational approximation that fits our constraints */
98 unsigned m = 0, n = 0;
99 unsigned buf[16];
100 unsigned cnt = cf_derive(fs*mult, src_freq, &buf[0], 16);
101 do {
102 cf_expand(&buf[0], cnt, &m, &n);
103 cnt -= 1;
104 } while(cnt > 0 && (m > 512 || n > 8192) && (n >= 2*m));
105
106 /* wrong values */
107 if(cnt == 0 || n == 0 || m == 0)
108 return -1;
109
110 jz_writef(AIC_I2SCR, STPBK(1));
111 jz_writef(CPM_I2SCDR, PCS(clksrc == X1000_CLK_MPLL ? 1 : 0),
112 CS(1), CE(1), DIV_M(m), DIV_N(n));
113 jz_write(CPM_I2SCDR1, REG_CPM_I2SCDR1);
114 REG_AIC_I2SDIV = (mult / 64) - 1;
115 }
116
117 jz_writef(AIC_I2SCR, STPBK(0));
118 return 0;
119}