diff options
-rw-r--r-- | firmware/drivers/audio/rk27xx_codec.c | 160 | ||||
-rw-r--r-- | firmware/export/rk27xx_codec.h | 168 |
2 files changed, 328 insertions, 0 deletions
diff --git a/firmware/drivers/audio/rk27xx_codec.c b/firmware/drivers/audio/rk27xx_codec.c new file mode 100644 index 0000000000..ebc6c476a3 --- /dev/null +++ b/firmware/drivers/audio/rk27xx_codec.c @@ -0,0 +1,160 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for internal Rockchip rk27xx audio codec + * (shCODlp-100.01-HD IP core from Dolphin) + * + * Copyright (c) 2011 Marcin Bukat + * + * 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 "kernel.h" +#include "audio.h" +#include "audiohw.h" +#include "system.h" +#include "i2c-rk27xx.h" + +const struct sound_settings_info audiohw_settings[] = { + [SOUND_VOLUME] = {"dB", 1, 5,-335, 45,-255}, + /* 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}, +#ifdef HAVE_RECORDING /* disabled for now */ + [SOUND_LEFT_GAIN] = {"dB", 2, 75, -1725, 3000, 0}, + [SOUND_RIGHT_GAIN] = {"dB", 2, 75, -1725, 3000, 0}, + [SOUND_MIC_GAIN] = {"dB", 0, 1, 0, 20, 20}, +#endif +}; + +/* private functions to read/write codec registers */ +static int codec_write(uint8_t reg, uint8_t val) +{ + return i2c_write(CODEC_I2C_ADDR, reg, 1, &val); +} + +#if 0 +static int codec_read(uint8_t reg, uint8_t *val) +{ + return i2c_read(CODEC_I2C_ADDR, reg, 1, val); +} +#endif + +static void audiohw_mute(bool mute) +{ + if (mute) + codec_write(CR1, SB_MICBIAS|DAC_MUTE|DACSEL); + else + codec_write(CR1, SB_MICBIAS|DACSEL); +} + +/* public functions */ +int tenthdb2master(int tdb) +{ + /* we lie here a bit and present 0.5dB gain steps + * but codec has 'variable' gain steps (0.5, 1.0, 2.0) + * depending on gain region. + */ + + if (tdb < VOLUME_MIN) + return 31; + else if (tdb < -115) + return -(((tdb + 115)/20) - 20); /* 2.0 dB steps */ + else if (tdb < 5) + return -(((tdb + 5)/10) - 9); /* 1.0 dB steps */ + else + return -((tdb - 45)/5); /* 0.5 dB steps */ +} + +void audiohw_preinit(void) +{ + /* PD7 output low */ + GPIO_PDDR &= ~(1<<7); + GPIO_PDCON |= (1<<7); + + codec_write(PMR2, SB_SLEEP|GIM|SB_MC); + codec_write(AICR, DAC_SERIAL|ADC_SERIAL|DAC_I2S|ADC_I2S); + codec_write(CR1, SB_MICBIAS|DAC_MUTE|DACSEL); + codec_write(CR2, ADC_HPF); + codec_write(CCR1, CRYSTAL_12M); + codec_write(CCR2, (FREQ44100 << 4)|FREQ44100); + codec_write(CRR, RATIO_8|KFAST_32|THRESHOLD_128); + codec_write(TR1, NOSC); +} + +void audiohw_postinit(void) +{ + codec_write(PMR1, SB_OUT|SB_MIX|SB_ADC|SB_IN1|SB_IN2|SB_MIC|SB_IND); + + udelay(10000); + + codec_write(PMR2, GIM | SB_MC); + + udelay(10000); + + codec_write(PMR1, SB_OUT|SB_ADC|SB_IN1|SB_IN2|SB_MIC|SB_IND); + + udelay(10000); + + codec_write(PMR1, SB_ADC|SB_IN1|SB_IN2|SB_MIC|SB_IND); + + sleep(3*HZ); + GPIO_PDDR |= (1<<7); /* PD7 high */ + sleep(HZ/10); + + audiohw_mute(false); +} + +void audiohw_close(void) +{ + /* stub */ +} + +void audiohw_set_frequency(int fsel) +{ + static const unsigned char values_freq[HW_NUM_FREQ] = + { + HW_HAVE_8_([HW_FREQ_8] = (FREQ8000<<4)|FREQ8000,) + HW_HAVE_11_([HW_FREQ_11] = (FREQ11025<<4)|FREQ11025,) + HW_HAVE_12_([HW_FREQ_12] = (FREQ12000<<4)|FREQ12000,) + HW_HAVE_16_([HW_FREQ_16] = (FREQ16000<<4)|FREQ16000,) + HW_HAVE_22_([HW_FREQ_22] = (FREQ22050<<4)|FREQ22050,) + HW_HAVE_24_([HW_FREQ_24] = (FREQ24000<<4)|FREQ24000,) + HW_HAVE_32_([HW_FREQ_32] = (FREQ32000<<4)|FREQ32000,) + HW_HAVE_44_([HW_FREQ_44] = (FREQ44100<<4)|FREQ44100,) + HW_HAVE_48_([HW_FREQ_48] = (FREQ48000<<4)|FREQ48000,) + HW_HAVE_96_([HW_FREQ_96] = (FREQ96000<<4)|FREQ96000,) + }; + + if ((unsigned)fsel >= HW_NUM_FREQ) + fsel = HW_FREQ_DEFAULT; + + /* we setup the same sampling freq for DAC and ADC */ + codec_write(CCR2, values_freq[fsel]); +} + +void audiohw_set_master_vol(int vol_l, int vol_r) +{ + uint8_t val; + + val = (uint8_t)(vol_r & 0x1f); + codec_write(CGR9, val); + + val = (uint8_t)(vol_l & 0x1f); + codec_write(CGR8, val); +} diff --git a/firmware/export/rk27xx_codec.h b/firmware/export/rk27xx_codec.h new file mode 100644 index 0000000000..e770e476a2 --- /dev/null +++ b/firmware/export/rk27xx_codec.h @@ -0,0 +1,168 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Driver for internal Rockchip rk27xx audio codec + * (shCODlp-100.01-HD IP core from Dolphin) + * + * Copyright (c) 2011 Marcin Bukat + * + * 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. + * + ****************************************************************************/ +#ifndef _RK27XX_CODEC_H_ +#define _RK27XX_CODEC_H_ + +#define VOLUME_MIN -335 +#define VOLUME_MAX 45 +#define AUDIOHW_CAPS (BASS_CAP | TREBLE_CAP) + +extern int tenthdb2master(int db); +extern void audiohw_set_master_vol(int vol_l, int vol_r); + +#define CODEC_I2C_ADDR 0x4e + +/* registers */ +#define AICR 0x00 /* Audio Interface Control */ +#define DAC_SERIAL (1<<3) +#define ADC_SERIAL (1<<2) +#define DAC_I2S (1<<1) +#define ADC_I2S (1<<0) + +#define CR1 0x02 /* Control Register 1 */ +#define SB_MICBIAS (1<<7) +#define CR1_MONO (1<<6) +#define DAC_MUTE (1<<5) +#define HP_DIS (1<<4) +#define DACSEL (1<<3) +#define BYPASS1 (1<<2) +#define BYPASS2 (1<<1) +#define SIDETONE (1<<0) + +#define CR2 0x04 /* Control Register 2 */ +#define DAC_DEEMP (1<<7) +#define ADC_HPF (1<<2) +#define INSEL_MIX (3<<0) +#define INSEL_MIC (2<<0) +#define INSEL_LINE2 (1<<0) +#define INSEL_LINE1 (0<<0) + +#define CCR1 0x06 /* Control Clock Register 1 */ +#define CRYSTAL_16M (1<<0) +#define CRYSTAL_12M (0<<0) + +#define CCR2 0x08 /* Control Clock Register 2 */ +#define FREQ8000 0x0a +#define FREQ9600 0x09 +#define FREQ11025 0x08 +#define FREQ12000 0x07 +#define FREQ16000 0x06 +#define FREQ22050 0x05 +#define FREQ24000 0x04 +#define FREQ32000 0x03 +#define FREQ44100 0x02 +#define FREQ48000 0x01 +#define FREQ96000 0x00 + +#define PMR1 0x0a /* Power Mode Register 1 */ +#define SB_DAC (1<<7) +#define SB_OUT (1<<6) +#define SB_MIX (1<<5) +#define SB_ADC (1<<4) +#define SB_IN1 (1<<3) +#define SB_IN2 (1<<2) +#define SB_MIC (1<<1) +#define SB_IND (1<<0) + +#define PMR2 0x0c /* Power Mode Register 1 */ +#define LRGI (1<<7) +#define RLGI (1<<6) +#define LRGOD (1<<5) +#define RLGOD (1<<4) +#define GIM (1<<3) +#define SB_MC (1<<2) +#define SB (1<<1) +#define SB_SLEEP (1<<0) + +#define CRR 0x0e /* Control Ramp Register */ +#define RATIO_8 (3<<5) +#define RATIO_4 (2<<5) +#define RATIO_2 (1<<5) +#define RATIO_1 (0<<5) +#define KFAST_32 (5<<2) +#define KFAST_16 (4<<2) +#define KFAST_8 (3<<2) +#define KFAST_4 (2<<2) +#define KFAST_2 (1<<2) +#define KFAST_1 (0<<2) +#define THRESHOLD_128 (3<<0) +#define THRESHOLD_64 (2<<0) +#define THRESHOLD_32 (1<<0) +#define THRESHOLD_0 (0<<0) + +#define ICR 0x10 /* Interrupt Control Register */ +#define IRQ_LOW_PULSE (3<<6) +#define IRQ_HIGH_PULSE (2<<6) +#define IRQ_LOW (1<<6) +#define IRQ_HIGH (0<<6) +#define JACK_MASK (1<<5) +#define CCMC_MASK (1<<4) +#define RUD_MASK (1<<3) +#define RDD_MASK (1<<2) +#define GUD_MASK (1<<1) +#define GDD_MASK (1<<0) + +#define IFR 0x12 /* Interrupt Flag Register */ +#define JACK (1<<6) +#define JACK_EVENT (1<<5) +#define CCMC (1<<4) +#define RAMP_UP_DONE (1<<3) +#define RAMP_DOWN_DONE (1<<2) +#define GAIN_UP_DONE (1<<1) +#define GAIN_DOWN_DONE (1<<0) + +#define CGR1 0x14 /* Control Gain Register 1 (DAC mixing) */ + +#define CGR2 0x16 /* Control Gain Register 2 (LINE1 mixing) */ +#define LRGOB1 (1<<7) +#define RLGOB1 (1<<6) + +#define CGR3 0x18 /* Control Gain Register 3 (LINE1 mixing) */ + +#define CGR4 0x1a /* Control Gain Register 4 (LINE2 mixing) */ +#define LRGOB2 (1<<7) +#define RLGOB2 (1<<6) + +#define CGR5 0x1c /* Control Gain Register 5 (LINE2 mixing) */ + +#define CGR6 0x1e /* Control Gain Register 6 (MIC mixing) */ +#define LRGOS (1<<7) +#define RLGOS (1<<6) + +#define CGR7 0x20 /* Control Gain Register 7 (MIC mixing) */ + +#define CGR8 0x22 /* Control Gain Register 8 (OUT STAGE gain) */ +#define LRGO (1<<7) +#define RLGO (1<<6) + +#define CGR9 0x24 /* Control Gain Register 9 (OUT STAGE gain) */ + +#define CGR10 0x26 /* Control Gain Register 10 (ADC input gain) */ + +#define TR1 0x28 /* undocumented */ +#define NOSC (1<<1) + +#define TR2 0x2a /* undocumented */ + +#endif /* _RK27XX_CODEC_H_ */ |