summaryrefslogtreecommitdiff
path: root/firmware/drivers/audio/rk27xx_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/audio/rk27xx_codec.c')
-rw-r--r--firmware/drivers/audio/rk27xx_codec.c160
1 files changed, 160 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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Driver for internal Rockchip rk27xx audio codec
11 * (shCODlp-100.01-HD IP core from Dolphin)
12 *
13 * Copyright (c) 2011 Marcin Bukat
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24#include "kernel.h"
25#include "audio.h"
26#include "audiohw.h"
27#include "system.h"
28#include "i2c-rk27xx.h"
29
30const struct sound_settings_info audiohw_settings[] = {
31 [SOUND_VOLUME] = {"dB", 1, 5,-335, 45,-255},
32 /* HAVE_SW_TONE_CONTROLS */
33 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
34 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
35 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
36 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
37 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
38#ifdef HAVE_RECORDING /* disabled for now */
39 [SOUND_LEFT_GAIN] = {"dB", 2, 75, -1725, 3000, 0},
40 [SOUND_RIGHT_GAIN] = {"dB", 2, 75, -1725, 3000, 0},
41 [SOUND_MIC_GAIN] = {"dB", 0, 1, 0, 20, 20},
42#endif
43};
44
45/* private functions to read/write codec registers */
46static int codec_write(uint8_t reg, uint8_t val)
47{
48 return i2c_write(CODEC_I2C_ADDR, reg, 1, &val);
49}
50
51#if 0
52static int codec_read(uint8_t reg, uint8_t *val)
53{
54 return i2c_read(CODEC_I2C_ADDR, reg, 1, val);
55}
56#endif
57
58static void audiohw_mute(bool mute)
59{
60 if (mute)
61 codec_write(CR1, SB_MICBIAS|DAC_MUTE|DACSEL);
62 else
63 codec_write(CR1, SB_MICBIAS|DACSEL);
64}
65
66/* public functions */
67int tenthdb2master(int tdb)
68{
69 /* we lie here a bit and present 0.5dB gain steps
70 * but codec has 'variable' gain steps (0.5, 1.0, 2.0)
71 * depending on gain region.
72 */
73
74 if (tdb < VOLUME_MIN)
75 return 31;
76 else if (tdb < -115)
77 return -(((tdb + 115)/20) - 20); /* 2.0 dB steps */
78 else if (tdb < 5)
79 return -(((tdb + 5)/10) - 9); /* 1.0 dB steps */
80 else
81 return -((tdb - 45)/5); /* 0.5 dB steps */
82}
83
84void audiohw_preinit(void)
85{
86 /* PD7 output low */
87 GPIO_PDDR &= ~(1<<7);
88 GPIO_PDCON |= (1<<7);
89
90 codec_write(PMR2, SB_SLEEP|GIM|SB_MC);
91 codec_write(AICR, DAC_SERIAL|ADC_SERIAL|DAC_I2S|ADC_I2S);
92 codec_write(CR1, SB_MICBIAS|DAC_MUTE|DACSEL);
93 codec_write(CR2, ADC_HPF);
94 codec_write(CCR1, CRYSTAL_12M);
95 codec_write(CCR2, (FREQ44100 << 4)|FREQ44100);
96 codec_write(CRR, RATIO_8|KFAST_32|THRESHOLD_128);
97 codec_write(TR1, NOSC);
98}
99
100void audiohw_postinit(void)
101{
102 codec_write(PMR1, SB_OUT|SB_MIX|SB_ADC|SB_IN1|SB_IN2|SB_MIC|SB_IND);
103
104 udelay(10000);
105
106 codec_write(PMR2, GIM | SB_MC);
107
108 udelay(10000);
109
110 codec_write(PMR1, SB_OUT|SB_ADC|SB_IN1|SB_IN2|SB_MIC|SB_IND);
111
112 udelay(10000);
113
114 codec_write(PMR1, SB_ADC|SB_IN1|SB_IN2|SB_MIC|SB_IND);
115
116 sleep(3*HZ);
117 GPIO_PDDR |= (1<<7); /* PD7 high */
118 sleep(HZ/10);
119
120 audiohw_mute(false);
121}
122
123void audiohw_close(void)
124{
125 /* stub */
126}
127
128void audiohw_set_frequency(int fsel)
129{
130 static const unsigned char values_freq[HW_NUM_FREQ] =
131 {
132 HW_HAVE_8_([HW_FREQ_8] = (FREQ8000<<4)|FREQ8000,)
133 HW_HAVE_11_([HW_FREQ_11] = (FREQ11025<<4)|FREQ11025,)
134 HW_HAVE_12_([HW_FREQ_12] = (FREQ12000<<4)|FREQ12000,)
135 HW_HAVE_16_([HW_FREQ_16] = (FREQ16000<<4)|FREQ16000,)
136 HW_HAVE_22_([HW_FREQ_22] = (FREQ22050<<4)|FREQ22050,)
137 HW_HAVE_24_([HW_FREQ_24] = (FREQ24000<<4)|FREQ24000,)
138 HW_HAVE_32_([HW_FREQ_32] = (FREQ32000<<4)|FREQ32000,)
139 HW_HAVE_44_([HW_FREQ_44] = (FREQ44100<<4)|FREQ44100,)
140 HW_HAVE_48_([HW_FREQ_48] = (FREQ48000<<4)|FREQ48000,)
141 HW_HAVE_96_([HW_FREQ_96] = (FREQ96000<<4)|FREQ96000,)
142 };
143
144 if ((unsigned)fsel >= HW_NUM_FREQ)
145 fsel = HW_FREQ_DEFAULT;
146
147 /* we setup the same sampling freq for DAC and ADC */
148 codec_write(CCR2, values_freq[fsel]);
149}
150
151void audiohw_set_master_vol(int vol_l, int vol_r)
152{
153 uint8_t val;
154
155 val = (uint8_t)(vol_r & 0x1f);
156 codec_write(CGR9, val);
157
158 val = (uint8_t)(vol_l & 0x1f);
159 codec_write(CGR8, val);
160}