rockbox/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c
Aidan MacDonald b25d8457bc Shanling Q1: fix DAC power mode switching
The OST prescaler bugfix (7a5130a277) broke runtime switching
between 1.0V and 2.0V modes. The 1ms delay after shutting down
the DAC isn't long enough to reset it, so it gets stuck in the
power mode assigned at boot. Change the delay back to 4ms, the
effective value prior to the OST bugfix.

Change-Id: Ic4583d1a6fa82540062aa185386f14bbf785a3f4
2022-01-30 17:37:24 +00:00

191 lines
5 KiB
C

/***************************************************************************
* __________ __ ___.
* 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(4);
}
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 == SOUND_HIGH_POWER)
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;
}