aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/ml26124.c
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/ml26124.c
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/ml26124.c')
-rw-r--r--sound/soc/codecs/ml26124.c681
1 files changed, 681 insertions, 0 deletions
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");