aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorTomoya MORINAGA <tomoya.rohm@gmail.com>2012-03-19 07:59:28 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-01 06:28:28 -0400
commitd808fe9f3e7f4092580c3294692bb801369b9c9f (patch)
tree52ba355f55bfa6b3e555b22c8084c3a30aff617b /sound/soc/codecs
parentab92d09d1306c738b751b839d81e867af1039d14 (diff)
ASoC: Add LAPIS Semiconductor ML26124 driver
ML26124-01HB/ML26124-02GD is 16bit monaural audio CODEC which has high resistance to voltage noise. On chip regulator realizes power supply rejection ratio be over 90dB so more than 50dB is improved than ever. ML26124-01HB/ ML26124-02GD can deliver stable audio performance without being affected by noise from the power supply circuit and peripheral components. The chip also includes a composite video signal output, which can be applied to various portable device requirements. The ML26124 is realized these functions into very small package the size is only 2.56mm x 2.46mm therefore can be construct high quality sound system easily. ML26124-01HB is 25pin WCSP package; ML26124-02GD is 32pin WQFN package. Signed-off-by: Tomoya MORINAGA <tomoya.rohm@gmail.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ml26124.c681
-rw-r--r--sound/soc/codecs/ml26124.h184
4 files changed, 871 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 6508e8b790bb..e314a66b30cd 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -42,6 +42,7 @@ config SND_SOC_ALL_CODECS
42 select SND_SOC_MAX9850 if I2C 42 select SND_SOC_MAX9850 if I2C
43 select SND_SOC_MAX9768 if I2C 43 select SND_SOC_MAX9768 if I2C
44 select SND_SOC_MAX9877 if I2C 44 select SND_SOC_MAX9877 if I2C
45 select SND_SOC_ML26124 if I2C
45 select SND_SOC_PCM3008 46 select SND_SOC_PCM3008
46 select SND_SOC_RT5631 if I2C 47 select SND_SOC_RT5631 if I2C
47 select SND_SOC_SGTL5000 if I2C 48 select SND_SOC_SGTL5000 if I2C
@@ -436,5 +437,8 @@ config SND_SOC_MAX9768
436config SND_SOC_MAX9877 437config SND_SOC_MAX9877
437 tristate 438 tristate
438 439
440config SND_SOC_ML26124
441 tristate
442
439config SND_SOC_TPA6130A2 443config SND_SOC_TPA6130A2
440 tristate 444 tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6662eb0cdcc0..9108ee992395 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -29,6 +29,7 @@ snd-soc-max9768-objs := max9768.o
29snd-soc-max98088-objs := max98088.o 29snd-soc-max98088-objs := max98088.o
30snd-soc-max98095-objs := max98095.o 30snd-soc-max98095-objs := max98095.o
31snd-soc-max9850-objs := max9850.o 31snd-soc-max9850-objs := max9850.o
32snd-soc-ml26124-objs := ml26124.o
32snd-soc-pcm3008-objs := pcm3008.o 33snd-soc-pcm3008-objs := pcm3008.o
33snd-soc-rt5631-objs := rt5631.o 34snd-soc-rt5631-objs := rt5631.o
34snd-soc-sgtl5000-objs := sgtl5000.o 35snd-soc-sgtl5000-objs := sgtl5000.o
@@ -135,6 +136,7 @@ obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
135obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o 136obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
136obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o 137obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
137obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o 138obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
139obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
138obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 140obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
139obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o 141obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
140obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o 142obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
new file mode 100644
index 000000000000..22cb5bf59273
--- /dev/null
+++ b/sound/soc/codecs/ml26124.c
@@ -0,0 +1,681 @@
1/*
2 * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/init.h>
21#include <linux/delay.h>
22#include <linux/pm.h>
23#include <linux/i2c.h>
24#include <linux/slab.h>
25#include <linux/platform_device.h>
26#include <linux/regmap.h>
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/soc.h>
31#include <sound/tlv.h>
32#include "ml26124.h"
33
34#define DVOL_CTL_DVMUTE_ON BIT(4) /* Digital volume MUTE On */
35#define DVOL_CTL_DVMUTE_OFF 0 /* Digital volume MUTE Off */
36#define ML26124_SAI_NO_DELAY BIT(1)
37#define ML26124_SAI_FRAME_SYNC (BIT(5) | BIT(0)) /* For mono (Telecodec) */
38#define ML26134_CACHESIZE 212
39#define ML26124_VMID BIT(1)
40#define ML26124_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\
41 SNDRV_PCM_RATE_48000)
42#define ML26124_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |\
43 SNDRV_PCM_FMTBIT_S32_LE)
44#define ML26124_NUM_REGISTER ML26134_CACHESIZE
45
46struct ml26124_priv {
47 u32 mclk;
48 u32 rate;
49 struct regmap *regmap;
50 int clk_in;
51 struct snd_pcm_substream *substream;
52};
53
54struct clk_coeff {
55 u32 mclk;
56 u32 rate;
57 u8 pllnl;
58 u8 pllnh;
59 u8 pllml;
60 u8 pllmh;
61 u8 plldiv;
62};
63
64/* ML26124 configuration */
65static const DECLARE_TLV_DB_SCALE(digital_tlv, -7150, 50, 0);
66
67static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0);
68static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0);
69static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0);
70static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0);
71static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
72
73static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
74 "A-law"};
75
76static const struct soc_enum ml26124_adc_companding_enum
77 = SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding);
78
79static const struct soc_enum ml26124_dac_companding_enum
80 = SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding);
81
82static const struct snd_kcontrol_new ml26124_snd_controls[] = {
83 SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
84 0xff, 1, digital_tlv),
85 SOC_SINGLE_TLV("Playback Digital Volume", ML26124_PLBAK_DIG_VOL, 0,
86 0xff, 1, digital_tlv),
87 SOC_SINGLE_TLV("Digital Boost Volume", ML26124_DIGI_BOOST_VOL, 0,
88 0x3f, 0, boost_vol),
89 SOC_SINGLE_TLV("EQ Band0 Volume", ML26124_EQ_GAIN_BRAND0, 0,
90 0xff, 1, digital_tlv),
91 SOC_SINGLE_TLV("EQ Band1 Volume", ML26124_EQ_GAIN_BRAND1, 0,
92 0xff, 1, digital_tlv),
93 SOC_SINGLE_TLV("EQ Band2 Volume", ML26124_EQ_GAIN_BRAND2, 0,
94 0xff, 1, digital_tlv),
95 SOC_SINGLE_TLV("EQ Band3 Volume", ML26124_EQ_GAIN_BRAND3, 0,
96 0xff, 1, digital_tlv),
97 SOC_SINGLE_TLV("EQ Band4 Volume", ML26124_EQ_GAIN_BRAND4, 0,
98 0xff, 1, digital_tlv),
99 SOC_SINGLE_TLV("ALC Target Level", ML26124_ALC_TARGET_LEV, 0,
100 0xf, 1, alclvl),
101 SOC_SINGLE_TLV("ALC Min Input Volume", ML26124_ALC_MAXMIN_GAIN, 0,
102 7, 0, mingain),
103 SOC_SINGLE_TLV("ALC Max Input Volume", ML26124_ALC_MAXMIN_GAIN, 4,
104 7, 1, maxgain),
105 SOC_SINGLE_TLV("Playback Limiter Min Input Volume",
106 ML26124_PL_MAXMIN_GAIN, 0, 7, 0, mingain),
107 SOC_SINGLE_TLV("Playback Limiter Max Input Volume",
108 ML26124_PL_MAXMIN_GAIN, 4, 7, 1, maxgain),
109 SOC_SINGLE_TLV("Playback Boost Volume", ML26124_PLYBAK_BOST_VOL, 0,
110 0x3f, 0, boost_vol),
111 SOC_SINGLE("DC High Pass Filter Switch", ML26124_FILTER_EN, 0, 1, 0),
112 SOC_SINGLE("Noise High Pass Filter Switch", ML26124_FILTER_EN, 1, 1, 0),
113 SOC_SINGLE("ZC Switch", ML26124_PW_ZCCMP_PW_MNG, 1,
114 1, 0),
115 SOC_SINGLE("EQ Band0 Switch", ML26124_FILTER_EN, 2, 1, 0),
116 SOC_SINGLE("EQ Band1 Switch", ML26124_FILTER_EN, 3, 1, 0),
117 SOC_SINGLE("EQ Band2 Switch", ML26124_FILTER_EN, 4, 1, 0),
118 SOC_SINGLE("EQ Band3 Switch", ML26124_FILTER_EN, 5, 1, 0),
119 SOC_SINGLE("EQ Band4 Switch", ML26124_FILTER_EN, 6, 1, 0),
120 SOC_SINGLE("Play Limiter", ML26124_DVOL_CTL, 0, 1, 0),
121 SOC_SINGLE("Capture Limiter", ML26124_DVOL_CTL, 1, 1, 0),
122 SOC_SINGLE("Digital Volume Fade Switch", ML26124_DVOL_CTL, 3, 1, 0),
123 SOC_SINGLE("Digital Switch", ML26124_DVOL_CTL, 4, 1, 0),
124 SOC_ENUM("DAC Companding", ml26124_dac_companding_enum),
125 SOC_ENUM("ADC Companding", ml26124_adc_companding_enum),
126};
127
128static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
129 SOC_DAPM_SINGLE("DAC Switch", ML26124_SPK_AMP_OUT, 1, 1, 0),
130 SOC_DAPM_SINGLE("Line in loopback Switch", ML26124_SPK_AMP_OUT, 3, 1,
131 0),
132 SOC_DAPM_SINGLE("PGA Switch", ML26124_SPK_AMP_OUT, 5, 1, 0),
133};
134
135/* Input mux */
136static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
137 "Digital MIC in", "Analog MIC Differential in"};
138
139static const struct soc_enum ml26124_insel_enum =
140 SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select);
141
142static const struct snd_kcontrol_new ml26124_input_mux_controls =
143 SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
144
145static const struct snd_kcontrol_new ml26124_line_control =
146 SOC_DAPM_SINGLE("Switch", ML26124_PW_LOUT_PW_MNG, 1, 1, 0);
147
148static const struct snd_soc_dapm_widget ml26124_dapm_widgets[] = {
149 SND_SOC_DAPM_SUPPLY("MCLKEN", ML26124_CLK_EN, 0, 0, NULL, 0),
150 SND_SOC_DAPM_SUPPLY("PLLEN", ML26124_CLK_EN, 1, 0, NULL, 0),
151 SND_SOC_DAPM_SUPPLY("PLLOE", ML26124_CLK_EN, 2, 0, NULL, 0),
152 SND_SOC_DAPM_SUPPLY("MICBIAS", ML26124_PW_REF_PW_MNG, 2, 0, NULL, 0),
153 SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
154 &ml26124_output_mixer_controls[0],
155 ARRAY_SIZE(ml26124_output_mixer_controls)),
156 SND_SOC_DAPM_DAC("DAC", "Playback", ML26124_PW_DAC_PW_MNG, 1, 0),
157 SND_SOC_DAPM_ADC("ADC", "Capture", ML26124_PW_IN_PW_MNG, 1, 0),
158 SND_SOC_DAPM_PGA("PGA", ML26124_PW_IN_PW_MNG, 3, 0, NULL, 0),
159 SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
160 &ml26124_input_mux_controls),
161 SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
162 &ml26124_line_control),
163 SND_SOC_DAPM_INPUT("MDIN"),
164 SND_SOC_DAPM_INPUT("MIN"),
165 SND_SOC_DAPM_INPUT("LIN"),
166 SND_SOC_DAPM_OUTPUT("SPOUT"),
167 SND_SOC_DAPM_OUTPUT("LOUT"),
168};
169
170static const struct snd_soc_dapm_route ml26124_intercon[] = {
171 /* Supply */
172 {"DAC", NULL, "MCLKEN"},
173 {"ADC", NULL, "MCLKEN"},
174 {"DAC", NULL, "PLLEN"},
175 {"ADC", NULL, "PLLEN"},
176 {"DAC", NULL, "PLLOE"},
177 {"ADC", NULL, "PLLOE"},
178
179 /* output mixer */
180 {"Output Mixer", "DAC Switch", "DAC"},
181 {"Output Mixer", "Line in loopback Switch", "LIN"},
182
183 /* outputs */
184 {"LOUT", NULL, "Output Mixer"},
185 {"SPOUT", NULL, "Output Mixer"},
186 {"Line Out Enable", NULL, "LOUT"},
187
188 /* input */
189 {"ADC", NULL, "Input Mux"},
190 {"Input Mux", "Analog MIC SingleEnded in", "PGA"},
191 {"Input Mux", "Analog MIC Differential in", "PGA"},
192 {"PGA", NULL, "MIN"},
193};
194
195/* PLLOutputFreq(Hz) = InputMclkFreq(Hz) * PLLM / (PLLN * PLLDIV) */
196static const struct clk_coeff coeff_div[] = {
197 {12288000, 16000, 0xc, 0x0, 0x20, 0x0, 0x4},
198 {12288000, 32000, 0xc, 0x0, 0x20, 0x0, 0x4},
199 {12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4},
200};
201
202static struct reg_default ml26124_reg[] = {
203 /* CLOCK control Register */
204 {0x00, 0x00 }, /* Sampling Rate */
205 {0x02, 0x00}, /* PLL NL */
206 {0x04, 0x00}, /* PLLNH */
207 {0x06, 0x00}, /* PLLML */
208 {0x08, 0x00}, /* MLLMH */
209 {0x0a, 0x00}, /* PLLDIV */
210 {0x0c, 0x00}, /* Clock Enable */
211 {0x0e, 0x00}, /* CLK Input/Output Control */
212
213 /* System Control Register */
214 {0x10, 0x00}, /* Software RESET */
215 {0x12, 0x00}, /* Record/Playback Run */
216 {0x14, 0x00}, /* Mic Input/Output control */
217
218 /* Power Management Register */
219 {0x20, 0x00}, /* Reference Power Management */
220 {0x22, 0x00}, /* Input Power Management */
221 {0x24, 0x00}, /* DAC Power Management */
222 {0x26, 0x00}, /* SP-AMP Power Management */
223 {0x28, 0x00}, /* LINEOUT Power Management */
224 {0x2a, 0x00}, /* VIDEO Power Management */
225 {0x2e, 0x00}, /* AC-CMP Power Management */
226
227 /* Analog reference Control Register */
228 {0x30, 0x04}, /* MICBIAS Voltage Control */
229
230 /* Input/Output Amplifier Control Register */
231 {0x32, 0x10}, /* MIC Input Volume */
232 {0x38, 0x00}, /* Mic Boost Volume */
233 {0x3a, 0x33}, /* Speaker AMP Volume */
234 {0x48, 0x00}, /* AMP Volume Control Function Enable */
235 {0x4a, 0x00}, /* Amplifier Volume Fader Control */
236
237 /* Analog Path Control Register */
238 {0x54, 0x00}, /* Speaker AMP Output Control */
239 {0x5a, 0x00}, /* Mic IF Control */
240 {0xe8, 0x01}, /* Mic Select Control */
241
242 /* Audio Interface Control Register */
243 {0x60, 0x00}, /* SAI-Trans Control */
244 {0x62, 0x00}, /* SAI-Receive Control */
245 {0x64, 0x00}, /* SAI Mode select */
246
247 /* DSP Control Register */
248 {0x66, 0x01}, /* Filter Func Enable */
249 {0x68, 0x00}, /* Volume Control Func Enable */
250 {0x6A, 0x00}, /* Mixer & Volume Control*/
251 {0x6C, 0xff}, /* Record Digital Volume */
252 {0x70, 0xff}, /* Playback Digital Volume */
253 {0x72, 0x10}, /* Digital Boost Volume */
254 {0x74, 0xe7}, /* EQ gain Band0 */
255 {0x76, 0xe7}, /* EQ gain Band1 */
256 {0x78, 0xe7}, /* EQ gain Band2 */
257 {0x7A, 0xe7}, /* EQ gain Band3 */
258 {0x7C, 0xe7}, /* EQ gain Band4 */
259 {0x7E, 0x00}, /* HPF2 CutOff*/
260 {0x80, 0x00}, /* EQ Band0 Coef0L */
261 {0x82, 0x00}, /* EQ Band0 Coef0H */
262 {0x84, 0x00}, /* EQ Band0 Coef0L */
263 {0x86, 0x00}, /* EQ Band0 Coef0H */
264 {0x88, 0x00}, /* EQ Band1 Coef0L */
265 {0x8A, 0x00}, /* EQ Band1 Coef0H */
266 {0x8C, 0x00}, /* EQ Band1 Coef0L */
267 {0x8E, 0x00}, /* EQ Band1 Coef0H */
268 {0x90, 0x00}, /* EQ Band2 Coef0L */
269 {0x92, 0x00}, /* EQ Band2 Coef0H */
270 {0x94, 0x00}, /* EQ Band2 Coef0L */
271 {0x96, 0x00}, /* EQ Band2 Coef0H */
272 {0x98, 0x00}, /* EQ Band3 Coef0L */
273 {0x9A, 0x00}, /* EQ Band3 Coef0H */
274 {0x9C, 0x00}, /* EQ Band3 Coef0L */
275 {0x9E, 0x00}, /* EQ Band3 Coef0H */
276 {0xA0, 0x00}, /* EQ Band4 Coef0L */
277 {0xA2, 0x00}, /* EQ Band4 Coef0H */
278 {0xA4, 0x00}, /* EQ Band4 Coef0L */
279 {0xA6, 0x00}, /* EQ Band4 Coef0H */
280
281 /* ALC Control Register */
282 {0xb0, 0x00}, /* ALC Mode */
283 {0xb2, 0x02}, /* ALC Attack Time */
284 {0xb4, 0x03}, /* ALC Decay Time */
285 {0xb6, 0x00}, /* ALC Hold Time */
286 {0xb8, 0x0b}, /* ALC Target Level */
287 {0xba, 0x70}, /* ALC Max/Min Gain */
288 {0xbc, 0x00}, /* Noise Gate Threshold */
289 {0xbe, 0x00}, /* ALC ZeroCross TimeOut */
290
291 /* Playback Limiter Control Register */
292 {0xc0, 0x04}, /* PL Attack Time */
293 {0xc2, 0x05}, /* PL Decay Time */
294 {0xc4, 0x0d}, /* PL Target Level */
295 {0xc6, 0x70}, /* PL Max/Min Gain */
296 {0xc8, 0x10}, /* Playback Boost Volume */
297 {0xca, 0x00}, /* PL ZeroCross TimeOut */
298
299 /* Video Amplifier Control Register */
300 {0xd0, 0x01}, /* VIDEO AMP Gain Control */
301 {0xd2, 0x01}, /* VIDEO AMP Setup 1 */
302 {0xd4, 0x01}, /* VIDEO AMP Control2 */
303};
304
305/* Get sampling rate value of sampling rate setting register (0x0) */
306static inline int get_srate(int rate)
307{
308 int srate;
309
310 switch (rate) {
311 case 16000:
312 srate = 3;
313 break;
314 case 32000:
315 srate = 6;
316 break;
317 case 48000:
318 srate = 8;
319 break;
320 default:
321 return -EINVAL;
322 }
323 return srate;
324}
325
326static inline int get_coeff(int mclk, int rate)
327{
328 int i;
329
330 for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
331 if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
332 return i;
333 }
334 return -EINVAL;
335}
336
337static int ml26124_hw_params(struct snd_pcm_substream *substream,
338 struct snd_pcm_hw_params *hw_params,
339 struct snd_soc_dai *dai)
340{
341 struct snd_soc_codec *codec = dai->codec;
342 struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
343 int i = get_coeff(priv->mclk, params_rate(hw_params));
344
345 priv->substream = substream;
346 priv->rate = params_rate(hw_params);
347
348 if (priv->clk_in) {
349 switch (priv->mclk / params_rate(hw_params)) {
350 case 256:
351 snd_soc_update_bits(codec, ML26124_CLK_CTL,
352 BIT(0) | BIT(1), 1);
353 break;
354 case 512:
355 snd_soc_update_bits(codec, ML26124_CLK_CTL,
356 BIT(0) | BIT(1), 2);
357 break;
358 case 1024:
359 snd_soc_update_bits(codec, ML26124_CLK_CTL,
360 BIT(0) | BIT(1), 3);
361 break;
362 default:
363 dev_err(codec->dev, "Unsupported MCLKI\n");
364 break;
365 }
366 } else {
367 snd_soc_update_bits(codec, ML26124_CLK_CTL,
368 BIT(0) | BIT(1), 0);
369 }
370
371 switch (params_rate(hw_params)) {
372 case 16000:
373 snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
374 get_srate(params_rate(hw_params)));
375 snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
376 coeff_div[i].pllnl);
377 snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
378 coeff_div[i].pllnh);
379 snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
380 coeff_div[i].pllml);
381 snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
382 coeff_div[i].pllmh);
383 snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
384 coeff_div[i].plldiv);
385 break;
386 case 32000:
387 snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
388 get_srate(params_rate(hw_params)));
389 snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
390 coeff_div[i].pllnl);
391 snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
392 coeff_div[i].pllnh);
393 snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
394 coeff_div[i].pllml);
395 snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
396 coeff_div[i].pllmh);
397 snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
398 coeff_div[i].plldiv);
399 break;
400 case 48000:
401 snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
402 get_srate(params_rate(hw_params)));
403 snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
404 coeff_div[i].pllnl);
405 snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
406 coeff_div[i].pllnh);
407 snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
408 coeff_div[i].pllml);
409 snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
410 coeff_div[i].pllmh);
411 snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
412 coeff_div[i].plldiv);
413 break;
414 default:
415 pr_err("%s:this rate is no support for ml26124\n", __func__);
416 return -EINVAL;
417 }
418
419 return 0;
420}
421
422static int ml26124_mute(struct snd_soc_dai *dai, int mute)
423{
424 struct snd_soc_codec *codec = dai->codec;
425 struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
426
427 switch (priv->substream->stream) {
428 case SNDRV_PCM_STREAM_CAPTURE:
429 snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
430 break;
431 case SNDRV_PCM_STREAM_PLAYBACK:
432 snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
433 break;
434 }
435
436 if (mute)
437 snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
438 DVOL_CTL_DVMUTE_ON);
439 else
440 snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
441 DVOL_CTL_DVMUTE_OFF);
442
443 return 0;
444}
445
446static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
447 unsigned int fmt)
448{
449 unsigned char mode;
450 struct snd_soc_codec *codec = codec_dai->codec;
451
452 /* set master/slave audio interface */
453 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
454 case SND_SOC_DAIFMT_CBM_CFM:
455 mode = 1;
456 break;
457 case SND_SOC_DAIFMT_CBS_CFS:
458 mode = 0;
459 break;
460 default:
461 return -EINVAL;
462 }
463 snd_soc_update_bits(codec, ML26124_SAI_MODE_SEL, BIT(0), mode);
464
465 /* interface format */
466 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
467 case SND_SOC_DAIFMT_I2S:
468 break;
469 default:
470 return -EINVAL;
471 }
472
473 /* clock inversion */
474 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
475 case SND_SOC_DAIFMT_NB_NF:
476 break;
477 default:
478 return -EINVAL;
479 }
480
481 return 0;
482}
483
484static int ml26124_set_dai_sysclk(struct snd_soc_dai *codec_dai,
485 int clk_id, unsigned int freq, int dir)
486{
487 struct snd_soc_codec *codec = codec_dai->codec;
488 struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
489
490 switch (clk_id) {
491 case ML26124_USE_PLLOUT:
492 priv->clk_in = ML26124_USE_PLLOUT;
493 break;
494 case ML26124_USE_MCLKI:
495 priv->clk_in = ML26124_USE_MCLKI;
496 break;
497 default:
498 return -EINVAL;
499 }
500
501 priv->mclk = freq;
502
503 return 0;
504}
505
506static int ml26124_set_bias_level(struct snd_soc_codec *codec,
507 enum snd_soc_bias_level level)
508{
509 struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
510
511 switch (level) {
512 case SND_SOC_BIAS_ON:
513 snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
514 ML26124_R26_MASK, ML26124_BLT_PREAMP_ON);
515 msleep(100);
516 snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
517 ML26124_R26_MASK,
518 ML26124_MICBEN_ON | ML26124_BLT_ALL_ON);
519 break;
520 case SND_SOC_BIAS_PREPARE:
521 break;
522 case SND_SOC_BIAS_STANDBY:
523 /* VMID ON */
524 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
525 snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
526 ML26124_VMID, ML26124_VMID);
527 msleep(500);
528 regcache_sync(priv->regmap);
529 }
530 break;
531 case SND_SOC_BIAS_OFF:
532 /* VMID OFF */
533 snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
534 ML26124_VMID, 0);
535 break;
536 }
537 codec->dapm.bias_level = level;
538 return 0;
539}
540
541static const struct snd_soc_dai_ops ml26124_dai_ops = {
542 .hw_params = ml26124_hw_params,
543 .digital_mute = ml26124_mute,
544 .set_fmt = ml26124_set_dai_fmt,
545 .set_sysclk = ml26124_set_dai_sysclk,
546};
547
548static struct snd_soc_dai_driver ml26124_dai = {
549 .name = "ml26124-hifi",
550 .playback = {
551 .stream_name = "Playback",
552 .channels_min = 1,
553 .channels_max = 2,
554 .rates = ML26124_RATES,
555 .formats = ML26124_FORMATS,},
556 .capture = {
557 .stream_name = "Capture",
558 .channels_min = 1,
559 .channels_max = 2,
560 .rates = ML26124_RATES,
561 .formats = ML26124_FORMATS,},
562 .ops = &ml26124_dai_ops,
563 .symmetric_rates = 1,
564};
565
566#ifdef CONFIG_PM
567static int ml26124_suspend(struct snd_soc_codec *codec)
568{
569 ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF);
570
571 return 0;
572}
573
574static int ml26124_resume(struct snd_soc_codec *codec)
575{
576 ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
577
578 return 0;
579}
580#else
581#define ml26124_suspend NULL
582#define ml26124_resume NULL
583#endif
584
585static int ml26124_probe(struct snd_soc_codec *codec)
586{
587 int ret;
588 struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
589 codec->control_data = priv->regmap;
590
591 ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
592 if (ret < 0) {
593 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
594 return ret;
595 }
596
597 /* Software Reset */
598 snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
599 snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
600
601 ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
602
603 return 0;
604}
605
606static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
607 .probe = ml26124_probe,
608 .suspend = ml26124_suspend,
609 .resume = ml26124_resume,
610 .set_bias_level = ml26124_set_bias_level,
611 .dapm_widgets = ml26124_dapm_widgets,
612 .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
613 .dapm_routes = ml26124_intercon,
614 .num_dapm_routes = ARRAY_SIZE(ml26124_intercon),
615 .controls = ml26124_snd_controls,
616 .num_controls = ARRAY_SIZE(ml26124_snd_controls),
617};
618
619static const struct regmap_config ml26124_i2c_regmap = {
620 .val_bits = 8,
621 .reg_bits = 8,
622 .max_register = ML26124_NUM_REGISTER,
623 .reg_defaults = ml26124_reg,
624 .num_reg_defaults = ARRAY_SIZE(ml26124_reg),
625 .cache_type = REGCACHE_RBTREE,
626 .write_flag_mask = 0x01,
627};
628
629static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
630 const struct i2c_device_id *id)
631{
632 struct ml26124_priv *priv;
633 int ret;
634
635 priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
636 if (!priv)
637 return -ENOMEM;
638
639 i2c_set_clientdata(i2c, priv);
640
641 priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap);
642 if (IS_ERR(priv->regmap)) {
643 ret = PTR_ERR(priv->regmap);
644 dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
645 return ret;
646 }
647
648 return snd_soc_register_codec(&i2c->dev,
649 &soc_codec_dev_ml26124, &ml26124_dai, 1);
650}
651
652static __devexit int ml26124_i2c_remove(struct i2c_client *client)
653{
654 struct ml26124_priv *priv = i2c_get_clientdata(client);
655
656 snd_soc_unregister_codec(&client->dev);
657 regmap_exit(priv->regmap);
658 return 0;
659}
660
661static const struct i2c_device_id ml26124_i2c_id[] = {
662 { "ml26124", 0 },
663 { }
664};
665MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
666
667static struct i2c_driver ml26124_i2c_driver = {
668 .driver = {
669 .name = "ml26124",
670 .owner = THIS_MODULE,
671 },
672 .probe = ml26124_i2c_probe,
673 .remove = __devexit_p(ml26124_i2c_remove),
674 .id_table = ml26124_i2c_id,
675};
676
677module_i2c_driver(ml26124_i2c_driver);
678
679MODULE_AUTHOR("Tomoya MORINAGA <tomoya.rohm@gmail.com>");
680MODULE_DESCRIPTION("LAPIS Semiconductor ML26124 ALSA SoC codec driver");
681MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ml26124.h b/sound/soc/codecs/ml26124.h
new file mode 100644
index 000000000000..5ea0cbb8c46c
--- /dev/null
+++ b/sound/soc/codecs/ml26124.h
@@ -0,0 +1,184 @@
1/*
2 * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 */
17
18#ifndef ML26124_H
19#define ML26124_H
20
21/* Clock Control Register */
22#define ML26124_SMPLING_RATE 0x00
23#define ML26124_PLLNL 0x02
24#define ML26124_PLLNH 0x04
25#define ML26124_PLLML 0x06
26#define ML26124_PLLMH 0x08
27#define ML26124_PLLDIV 0x0a
28#define ML26124_CLK_EN 0x0c
29#define ML26124_CLK_CTL 0x0e
30
31/* System Control Register */
32#define ML26124_SW_RST 0x10
33#define ML26124_REC_PLYBAK_RUN 0x12
34#define ML26124_MIC_TIM 0x14
35
36/* Power Mnagement Register */
37#define ML26124_PW_REF_PW_MNG 0x20
38#define ML26124_PW_IN_PW_MNG 0x22
39#define ML26124_PW_DAC_PW_MNG 0x24
40#define ML26124_PW_SPAMP_PW_MNG 0x26
41#define ML26124_PW_LOUT_PW_MNG 0x28
42#define ML26124_PW_VOUT_PW_MNG 0x2a
43#define ML26124_PW_ZCCMP_PW_MNG 0x2e
44
45/* Analog Reference Control Register */
46#define ML26124_PW_MICBIAS_VOL 0x30
47
48/* Input/Output Amplifier Control Register */
49#define ML26124_PW_MIC_IN_VOL 0x32
50#define ML26124_PW_MIC_BOST_VOL 0x38
51#define ML26124_PW_SPK_AMP_VOL 0x3a
52#define ML26124_PW_AMP_VOL_FUNC 0x48
53#define ML26124_PW_AMP_VOL_FADE 0x4a
54
55/* Analog Path Control Register */
56#define ML26124_SPK_AMP_OUT 0x54
57#define ML26124_MIC_IF_CTL 0x5a
58#define ML26124_MIC_SELECT 0xe8
59
60/* Audio Interface Control Register */
61#define ML26124_SAI_TRANS_CTL 0x60
62#define ML26124_SAI_RCV_CTL 0x62
63#define ML26124_SAI_MODE_SEL 0x64
64
65/* DSP Control Register */
66#define ML26124_FILTER_EN 0x66
67#define ML26124_DVOL_CTL 0x68
68#define ML26124_MIXER_VOL_CTL 0x6a
69#define ML26124_RECORD_DIG_VOL 0x6c
70#define ML26124_PLBAK_DIG_VOL 0x70
71#define ML26124_DIGI_BOOST_VOL 0x72
72#define ML26124_EQ_GAIN_BRAND0 0x74
73#define ML26124_EQ_GAIN_BRAND1 0x76
74#define ML26124_EQ_GAIN_BRAND2 0x78
75#define ML26124_EQ_GAIN_BRAND3 0x7a
76#define ML26124_EQ_GAIN_BRAND4 0x7c
77#define ML26124_HPF2_CUTOFF 0x7e
78#define ML26124_EQBRAND0_F0L 0x80
79#define ML26124_EQBRAND0_F0H 0x82
80#define ML26124_EQBRAND0_F1L 0x84
81#define ML26124_EQBRAND0_F1H 0x86
82#define ML26124_EQBRAND1_F0L 0x88
83#define ML26124_EQBRAND1_F0H 0x8a
84#define ML26124_EQBRAND1_F1L 0x8c
85#define ML26124_EQBRAND1_F1H 0x8e
86#define ML26124_EQBRAND2_F0L 0x90
87#define ML26124_EQBRAND2_F0H 0x92
88#define ML26124_EQBRAND2_F1L 0x94
89#define ML26124_EQBRAND2_F1H 0x96
90#define ML26124_EQBRAND3_F0L 0x98
91#define ML26124_EQBRAND3_F0H 0x9a
92#define ML26124_EQBRAND3_F1L 0x9c
93#define ML26124_EQBRAND3_F1H 0x9e
94#define ML26124_EQBRAND4_F0L 0xa0
95#define ML26124_EQBRAND4_F0H 0xa2
96#define ML26124_EQBRAND4_F1L 0xa4
97#define ML26124_EQBRAND4_F1H 0xa6
98
99/* ALC Control Register */
100#define ML26124_ALC_MODE 0xb0
101#define ML26124_ALC_ATTACK_TIM 0xb2
102#define ML26124_ALC_DECAY_TIM 0xb4
103#define ML26124_ALC_HOLD_TIM 0xb6
104#define ML26124_ALC_TARGET_LEV 0xb8
105#define ML26124_ALC_MAXMIN_GAIN 0xba
106#define ML26124_NOIS_GATE_THRSH 0xbc
107#define ML26124_ALC_ZERO_TIMOUT 0xbe
108
109/* Playback Limiter Control Register */
110#define ML26124_PL_ATTACKTIME 0xc0
111#define ML26124_PL_DECAYTIME 0xc2
112#define ML26124_PL_TARGETTIME 0xc4
113#define ML26124_PL_MAXMIN_GAIN 0xc6
114#define ML26124_PLYBAK_BOST_VOL 0xc8
115#define ML26124_PL_0CROSS_TIMOUT 0xca
116
117/* Video Amplifer Control Register */
118#define ML26124_VIDEO_AMP_GAIN_CTL 0xd0
119#define ML26124_VIDEO_AMP_SETUP1 0xd2
120#define ML26124_VIDEO_AMP_CTL2 0xd4
121
122/* Clock select for machine driver */
123#define ML26124_USE_PLL 0
124#define ML26124_USE_MCLKI_256FS 1
125#define ML26124_USE_MCLKI_512FS 2
126#define ML26124_USE_MCLKI_1024FS 3
127
128/* Register Mask */
129#define ML26124_R0_MASK 0xf
130#define ML26124_R2_MASK 0xff
131#define ML26124_R4_MASK 0x1
132#define ML26124_R6_MASK 0xf
133#define ML26124_R8_MASK 0x3f
134#define ML26124_Ra_MASK 0x1f
135#define ML26124_Rc_MASK 0x1f
136#define ML26124_Re_MASK 0x7
137#define ML26124_R10_MASK 0x1
138#define ML26124_R12_MASK 0x17
139#define ML26124_R14_MASK 0x3f
140#define ML26124_R20_MASK 0x47
141#define ML26124_R22_MASK 0xa
142#define ML26124_R24_MASK 0x2
143#define ML26124_R26_MASK 0x1f
144#define ML26124_R28_MASK 0x2
145#define ML26124_R2a_MASK 0x2
146#define ML26124_R2e_MASK 0x2
147#define ML26124_R30_MASK 0x7
148#define ML26124_R32_MASK 0x3f
149#define ML26124_R38_MASK 0x38
150#define ML26124_R3a_MASK 0x3f
151#define ML26124_R48_MASK 0x3
152#define ML26124_R4a_MASK 0x7
153#define ML26124_R54_MASK 0x2a
154#define ML26124_R5a_MASK 0x3
155#define ML26124_Re8_MASK 0x3
156#define ML26124_R60_MASK 0xff
157#define ML26124_R62_MASK 0xff
158#define ML26124_R64_MASK 0x1
159#define ML26124_R66_MASK 0xff
160#define ML26124_R68_MASK 0x3b
161#define ML26124_R6a_MASK 0xf3
162#define ML26124_R6c_MASK 0xff
163#define ML26124_R70_MASK 0xff
164
165#define ML26124_MCLKEN BIT(0)
166#define ML26124_PLLEN BIT(1)
167#define ML26124_PLLOE BIT(2)
168#define ML26124_MCLKOE BIT(3)
169
170#define ML26124_BLT_ALL_ON 0x1f
171#define ML26124_BLT_PREAMP_ON 0x13
172
173#define ML26124_MICBEN_ON BIT(2)
174
175enum ml26124_regs {
176 ML26124_MCLK = 0,
177};
178
179enum ml26124_clk_in {
180 ML26124_USE_PLLOUT = 0,
181 ML26124_USE_MCLKI,
182};
183
184#endif