From 4c60bc9e681865fcfc149775a1ed7ccd2613d5bf Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Sun, 23 May 2021 17:30:58 +0100 Subject: New port: Shanling Q1 native - Audio playback works - Touchscreen and buttons work - Bootloader works and is capable of dual boot - Plugins are working - Cabbiev2 theme has been ported - Stable for general usage Thanks to Marc Aarts for porting Cabbiev2 and plugin bitmaps. There's a few minor known issues: - Bootloader must be installed manually using 'usbboot' as there is no support in jztool yet. - Keymaps may be lacking, need further testing and feedback. - Some plugins may not be fully adapted to the screen size and could benefit from further tweaking. - LCD shows abnormal effects under some circumstances: for example, after viewing a mostly black screen an afterimage appears briefly when going back to a brightly-lit screen. Sudden power-off without proper shutdown of the backlight causes a "dissolving" effect. - CW2015 battery reporting driver is buggy, and disabled for now. Battery reporting is currently voltage-based using the AXP192. Change-Id: I635e83f02a880192c5a82cb0861ad3a61c137c3a --- .../ingenic_x1000/shanlingq1/audiohw-shanlingq1.c | 191 +++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c (limited to 'firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c') diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c new file mode 100644 index 0000000000..7314f20412 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c @@ -0,0 +1,191 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "audiohw.h" +#include "system.h" +#include "pcm_sampr.h" +#include "aic-x1000.h" +#include "i2c-x1000.h" +#include "gpio-x1000.h" +#include "x1000/aic.h" +#include "x1000/cpm.h" + +/* Codec has an dedicated oscillator connected, so it can operate + * as i2s master or slave. I can't distinguish any difference in + * terms of audio quality or power consumption. Code is left here + * for reference in case it proves useful to change it. */ +#define CODEC_MASTER_MODE 0 + +static int cur_fsel = HW_FREQ_48; +static int cur_vol_l = 0, cur_vol_r = 0; +static int cur_filter = 0; +static enum es9218_amp_mode cur_amp_mode = ES9218_AMP_MODE_1VRMS; + +static void codec_start(void) +{ + es9218_open(); + es9218_mute(true); + es9218_set_iface_role(CODEC_MASTER_MODE ? ES9218_IFACE_ROLE_MASTER + : ES9218_IFACE_ROLE_SLAVE); + es9218_set_iface_format(ES9218_IFACE_FORMAT_I2S, ES9218_IFACE_BITS_32); + es9218_set_dpll_bandwidth(10); + es9218_set_thd_compensation(true); + es9218_set_thd_coeffs(0, 0); + audiohw_set_filter_roll_off(cur_filter); + audiohw_set_frequency(cur_fsel); + audiohw_set_volume(cur_vol_l, cur_vol_r); + es9218_set_amp_mode(cur_amp_mode); +} + +static void codec_stop(void) +{ + es9218_mute(true); + es9218_close(); + mdelay(1); +} + +void audiohw_init(void) +{ + /* Configure AIC */ + aic_set_external_codec(true); + aic_set_i2s_mode(CODEC_MASTER_MODE ? AIC_I2S_SLAVE_MODE + : AIC_I2S_MASTER_MODE); + aic_enable_i2s_bit_clock(true); + + /* Open DAC driver */ + i2c_x1000_set_freq(1, I2C_FREQ_400K); + codec_start(); +} + +void audiohw_postinit(void) +{ + es9218_mute(false); +} + +void audiohw_close(void) +{ + codec_stop(); +} + +void audiohw_set_frequency(int fsel) +{ + int sampr = hw_freq_sampr[fsel]; + + /* choose clock gear setting, in line with the OF */ + enum es9218_clock_gear clkgear; + if(sampr <= 48000) + clkgear = ES9218_CLK_GEAR_4; + else if(sampr <= 96000) + clkgear = ES9218_CLK_GEAR_2; + else + clkgear = ES9218_CLK_GEAR_1; + + aic_enable_i2s_bit_clock(false); + es9218_set_clock_gear(clkgear); + + if(CODEC_MASTER_MODE) + es9218_set_nco_frequency(sampr); + else + aic_set_i2s_clock(X1000_CLK_SCLK_A, sampr, 64); + + aic_enable_i2s_bit_clock(true); + + /* save frequency selection */ + cur_fsel = fsel; +} + +static int round_step_up(int x, int step) +{ + int rem = x % step; + if(rem > 0) + rem -= step; + return x - rem; +} + +void audiohw_set_volume(int vol_l, int vol_r) +{ + /* save volume */ + cur_vol_l = vol_l; + cur_vol_r = vol_r; + + /* adjust the amp setting first */ + int amp = round_step_up(MAX(vol_l, vol_r), ES9218_AMP_VOLUME_STEP); + amp = MIN(amp, ES9218_AMP_VOLUME_MAX); + amp = MAX(amp, ES9218_AMP_VOLUME_MIN); + + /* adjust digital volumes */ + vol_l -= amp; + vol_l = MIN(vol_l, ES9218_DIG_VOLUME_MAX); + vol_l = MAX(vol_l, ES9218_DIG_VOLUME_MIN); + + vol_r -= amp; + vol_r = MIN(vol_r, ES9218_DIG_VOLUME_MAX); + vol_r = MAX(vol_r, ES9218_DIG_VOLUME_MIN); + + /* program DAC */ + es9218_set_amp_volume(amp); + es9218_set_dig_volume(vol_l, vol_r); +} + +void audiohw_set_filter_roll_off(int value) +{ + cur_filter = value; + es9218_set_filter(value); +} + +void audiohw_set_power_mode(int mode) +{ + enum es9218_amp_mode new_amp_mode; + if(mode == 0) + new_amp_mode = ES9218_AMP_MODE_2VRMS; + else + new_amp_mode = ES9218_AMP_MODE_1VRMS; + + if(new_amp_mode != cur_amp_mode) { + codec_stop(); + cur_amp_mode = new_amp_mode; + codec_start(); + es9218_mute(false); + } +} + +void es9218_set_power_pin(int level) +{ + gpio_set_level(GPIO_ES9218_POWER, level ? 1 : 0); +} + +void es9218_set_reset_pin(int level) +{ + gpio_set_level(GPIO_ES9218_RESET, level ? 1 : 0); +} + +uint32_t es9218_get_mclk(void) +{ + /* Measured by running the DAC in asynchronous I2S slave mode, + * and reading back the DPLL number from regs 0x42-0x45 while + * playing back 44.1 KHz audio. + * + * CLK = (44_100 * 2**32) / 0x4b46e5 + * = 38_393_403.29532737 + * ~ 38.4 Mhz + */ + return 38400000; +} -- cgit v1.2.3