From 758bb3bc628705ff8e5c677b3b2d87720c726c13 Mon Sep 17 00:00:00 2001 From: Mark Arigo Date: Mon, 25 May 2009 21:10:45 +0000 Subject: 3 new ports: Samsung YH-820, YH-920, and YH-925. Mostly functional. Audio working on 820 & 925 (untested on the 920). No battery readings. No recording. No plugins. Keymap needs work. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21083 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/audio/ak4537.c | 280 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 firmware/drivers/audio/ak4537.c (limited to 'firmware/drivers/audio') diff --git a/firmware/drivers/audio/ak4537.c b/firmware/drivers/audio/ak4537.c new file mode 100644 index 0000000000..83a040e177 --- /dev/null +++ b/firmware/drivers/audio/ak4537.c @@ -0,0 +1,280 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (c) 2009 Mark Arigo + * + * 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 "config.h" +#include "system.h" +#include "string.h" + +// #define LOGF_ENABLE +#include "logf.h" + +#include "pcm_sampr.h" +#include "audio.h" +#include "akcodec.h" +#include "audiohw.h" +#include "sound.h" + +const struct sound_settings_info audiohw_settings[] = { + [SOUND_VOLUME] = {"dB", 0, 1,-127, 0, -25}, + /* HAVE_SW_TONE_CONTROLS */ + [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0}, + [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, + [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, + [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, +#if defined(HAVE_RECORDING) + [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23}, + [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23}, + [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 0}, +#endif +}; + +static unsigned char akc_regs[AKC_NUM_REGS]; + +static void akc_write(int reg, unsigned val) +{ + if ((unsigned)reg >= AKC_NUM_REGS) + return; + + akc_regs[reg] = (unsigned char)val; + akcodec_write(reg, val); +} + +static void akc_set(int reg, unsigned bits) +{ + akc_write(reg, akc_regs[reg] | bits); +} + +static void akc_clear(int reg, unsigned bits) +{ + akc_write(reg, akc_regs[reg] & ~bits); +} + +static void akc_write_masked(int reg, unsigned bits, unsigned mask) +{ + akc_write(reg, (akc_regs[reg] & ~mask) | (bits & mask)); +} + +#if 0 +static void codec_set_active(int active) +{ + (void)active; +} +#endif + +/* convert tenth of dB volume (-1270..0) to master volume register value */ +int tenthdb2master(int db) +{ + if (db < VOLUME_MIN) + return 0xff; /* mute */ + else if (db >= VOLUME_MAX) + return 0x00; + else + return ((-db)/5); +} + +int sound_val2phys(int setting, int value) +{ + int result; + + switch(setting) + { +#ifdef HAVE_RECORDING + case SOUND_LEFT_GAIN: + case SOUND_RIGHT_GAIN: + result = (value - 23) * 15; /* fix */ + break; + case SOUND_MIC_GAIN: + result = value * 200; /* fix */ + break; +#endif + default: + result = value; + break; + } + + return result; +} + +void audiohw_mute(bool mute) +{ + if (mute) + { + akc_set(AK4537_DAC, SMUTE); + udelay(200000); + } + else + { + udelay(200000); + akc_clear(AK4537_DAC, SMUTE); + } +} + +void audiohw_preinit(void) +{ + int i; + for (i = 0; i < AKC_NUM_REGS; i++) + akc_regs[i] = akcodec_read(i); + + /* POWER UP SEQUENCE (from the datasheet) */ + /* Note: the delay length is what the OF uses, although the datasheet + suggests they can be shorter */ + + /* power up VCOM */ + akc_set(AK4537_PM1, PMVCM); + udelay(100000); + + /* setup AK4537_SIGSEL1 */ + akc_set(AK4537_SIGSEL1, ALCS | MOUT2); + udelay(100000); + + /* setup AK4537_SIGSEL2 */ + akc_write_masked(AK4537_SIGSEL2, DAHS, (DAHS | HPL | HPR)); + udelay(100000); + + /* setup AK4537_MODE1 */ + akc_write_masked(AK4537_MODE1, DIF_I2S | BICK_32FS | MCKI_PLL_12000KHZ, + (DIF_MASK | BICK_MASK | MCKI_MASK)); + udelay(100000); + + /* CLOCK SETUP - X'tal used in PLL mode (master mode) */ + + /* release the pull-down of the XTI pin and power-up the X'tal osc */ + akc_write_masked(AK4537_PM2, PMXTL, (MCLKPD | PMXTL)); + udelay(100000); + + /* power-up the PLL */ + akc_set(AK4537_PM2, PMPLL); + udelay(100000); + + /* enable MCKO output and setup MCKO output freq */ + akc_set(AK4537_MODE1, MCKO_EN); + udelay(100000); + + /* ENABLE HEADPHONE AMP OUTPUT */ + + /* setup the sampling freq if PLL mode is used */ + akc_write_masked(AK4537_MODE2, AKC_PLL_44100HZ, FS_MASK); + + /* setup the low freq boost level */ + akc_write_masked(AK4537_DAC, BST_OFF, BST_MASK); + + /* setup the digital volume */ + akc_write(AK4537_ATTL, 0x10); + akc_write(AK4537_ATTR, 0x10); + + /* power up the DAC */ + akc_set(AK4537_PM2, PMDAC); + udelay(100000); + + /* power up the headphone amp */ + akc_clear(AK4537_SIGSEL2, HPL | HPR); + udelay(100000); + + /* power up the common voltage of headphone amp */ + akc_set(AK4537_PM2, PMHPL | PMHPR); + udelay(100000); +} + +void audiohw_postinit(void) +{ + /* nothing */ +} + +void audiohw_close(void) +{ + /* POWER DOWN SEQUENCE (from the datasheet) */ + + /* mute */ + akc_write(AK4537_ATTL, 0xff); + akc_write(AK4537_ATTR, 0xff); + akc_set(AK4537_DAC, SMUTE); + udelay(100000); + + /* power down the common voltage of headphone amp */ + akc_clear(AK4537_PM2, PMHPL | PMHPR); + + /* power down the DAC */ + akc_clear(AK4537_PM2, PMDAC); + + /* power down the headphone amp */ + akc_set(AK4537_SIGSEL2, HPL | HPR); + + /* disable MCKO */ + akc_clear(AK4537_MODE1, MCKO_EN); + + /* power down X'tal and PLL, pull down the XTI pin */ + akc_write_masked(AK4537_PM2, MCLKPD, (MCLKPD | PMXTL | PMPLL)); + + /* power down VCOM */ + akc_clear(AK4537_PM1, PMVCM); + udelay(100000); + + akcodec_close(); /* target-specific */ +} + +void audiohw_set_master_vol(int vol_l, int vol_r) +{ + akc_write(AK4537_ATTL, vol_l & 0xff); + akc_write(AK4537_ATTR, vol_r & 0xff); +} + +void audiohw_set_frequency(int fsel) +{ + static const unsigned char srctrl_table[HW_NUM_FREQ] = + { + HW_HAVE_8_([HW_FREQ_8] = AKC_PLL_8000HZ, ) + HW_HAVE_11_([HW_FREQ_11] = AKC_PLL_11025HZ,) + HW_HAVE_16_([HW_FREQ_16] = AKC_PLL_16000HZ,) + HW_HAVE_22_([HW_FREQ_22] = AKC_PLL_22050HZ,) + HW_HAVE_24_([HW_FREQ_24] = AKC_PLL_24000HZ,) + HW_HAVE_32_([HW_FREQ_32] = AKC_PLL_32000HZ,) + HW_HAVE_44_([HW_FREQ_44] = AKC_PLL_44100HZ,) + HW_HAVE_48_([HW_FREQ_48] = AKC_PLL_48000HZ,) + }; + + if ((unsigned)fsel >= HW_NUM_FREQ) + fsel = HW_FREQ_DEFAULT; + + akc_write_masked(AK4537_MODE2, srctrl_table[fsel], FS_MASK); +} + +#if defined(HAVE_RECORDING) +void audiohw_enable_recording(bool source_mic) +{ + (void)source_mic; +} + +void audiohw_disable_recording(void) +{ +} + +void audiohw_set_recvol(int left, int right, int type) +{ + (void)left; + (void)right; + (void)type; +} + +void audiohw_set_monitor(bool enable) +{ + (void)enable; +} +#endif /* HAVE_RECORDING */ -- cgit v1.2.3