From 3ec66893e377b088c1284d2d23adb2aeea6d7965 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Sat, 27 Feb 2021 22:08:58 +0000 Subject: New port: FiiO M3K on bare metal Change-Id: I7517e7d5459e129dcfc9465c6fbd708619888fbe --- firmware/target/mips/ingenic_x1000/aic-x1000.c | 119 +++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 firmware/target/mips/ingenic_x1000/aic-x1000.c (limited to 'firmware/target/mips/ingenic_x1000/aic-x1000.c') 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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2021 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "system.h" +#include "aic-x1000.h" +#include "gpio-x1000.h" +#include "x1000/aic.h" +#include "x1000/cpm.h" + +/* Given a rational number m/n < 1, find its representation as a continued + * fraction [0; a1, a2, a3, ..., a_k]. At most "cnt" terms are calculated + * and written out to "buf". Returns the number of terms written; the result + * is complete if this value is less than "cnt", and may be incomplete if it + * is equal to "cnt". (Note the leading zero term is not written to "buf".) + */ +static unsigned cf_derive(unsigned m, unsigned n, unsigned* buf, unsigned cnt) +{ + unsigned wrote = 0; + unsigned a = m / n; + while(cnt--) { + unsigned tmp = n; + n = m - n * a; + if(n == 0) + break; + + m = tmp; + a = m / n; + *buf++ = a; + wrote++; + } + + return wrote; +} + +/* Given a finite continued fraction [0; buf[0], buf[1], ..., buf[count-1]], + * calculate the rational number m/n which it represents. Returns m and n. + * If count is zero, then m and n are undefined. + */ +static void cf_expand(const unsigned* buf, unsigned count, + unsigned* m, unsigned* n) +{ + if(count == 0) + return; + + unsigned i = count - 1; + unsigned mx = 1, nx = buf[i]; + while(i--) { + unsigned tmp = nx; + nx = mx + buf[i] * nx; + mx = tmp; + } + + *m = mx; + *n = nx; +} + +int aic_i2s_set_mclk(x1000_clk_t clksrc, unsigned fs, unsigned mult) +{ + /* get the input clock rate */ + uint32_t src_freq = clk_get(clksrc); + + /* reject invalid parameters */ + if(mult % 64 != 0) + return -1; + + if(clksrc == X1000_EXCLK_FREQ) { + if(mult != 0) + return -1; + + jz_writef(AIC_I2SCR, STPBK(1)); + jz_writef(CPM_I2SCDR, CS(0), CE(0)); + REG_AIC_I2SDIV = X1000_EXCLK_FREQ / 64 / fs; + } else { + if(mult == 0) + return -1; + if(fs*mult > src_freq) + return -1; + + /* calculate best rational approximation that fits our constraints */ + unsigned m = 0, n = 0; + unsigned buf[16]; + unsigned cnt = cf_derive(fs*mult, src_freq, &buf[0], 16); + do { + cf_expand(&buf[0], cnt, &m, &n); + cnt -= 1; + } while(cnt > 0 && (m > 512 || n > 8192) && (n >= 2*m)); + + /* wrong values */ + if(cnt == 0 || n == 0 || m == 0) + return -1; + + jz_writef(AIC_I2SCR, STPBK(1)); + jz_writef(CPM_I2SCDR, PCS(clksrc == X1000_CLK_MPLL ? 1 : 0), + CS(1), CE(1), DIV_M(m), DIV_N(n)); + jz_write(CPM_I2SCDR1, REG_CPM_I2SCDR1); + REG_AIC_I2SDIV = (mult / 64) - 1; + } + + jz_writef(AIC_I2SCR, STPBK(0)); + return 0; +} -- cgit v1.2.3