2 * uda134x.c -- UDA134X ALSA SoC Codec driver
4 * Modifications by Christian Pellegrin <chripell@evolware.org>
6 * Copyright 2007 Dension Audio Systems Ltd.
9 * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
16 #include <linux/module.h>
17 #include <linux/delay.h>
18 #include <linux/slab.h>
19 #include <sound/pcm.h>
20 #include <sound/pcm_params.h>
21 #include <sound/soc.h>
22 #include <sound/soc-dapm.h>
23 #include <sound/initval.h>
25 #include <sound/uda134x.h>
31 #define POWER_OFF_ON_STANDBY 1
33 ALSA SOC usually puts the device in standby mode when it's not used
34 for sometime. If you define POWER_OFF_ON_STANDBY the driver will
35 turn off the ADC/DAC when this callback is invoked and turn it back
36 on when needed. Unfortunately this will result in a very light bump
37 (it can be audible only with good earphones). If this bothers you
38 just comment this line, you will have slightly higher power
39 consumption . Please note that sending the L3 command for ADC is
40 enough to make the bump, so it doesn't make difference if you
41 completely take off power from the codec.
44 #define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
45 #define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
46 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
52 struct snd_pcm_substream
*master_substream
;
53 struct snd_pcm_substream
*slave_substream
;
56 /* In-data addresses are hard-coded into the reg-cache values */
57 static const char uda134x_reg
[UDA134X_REGS_NUM
] = {
58 /* Extended address registers */
59 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
60 /* Status, data regs */
61 0x00, 0x83, 0x00, 0x40, 0x80, 0x00,
65 * The codec has no support for reading its registers except for peak level...
67 static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec
*codec
,
70 u8
*cache
= codec
->reg_cache
;
72 if (reg
>= UDA134X_REGS_NUM
)
78 * Write the register cache
80 static inline void uda134x_write_reg_cache(struct snd_soc_codec
*codec
,
81 u8 reg
, unsigned int value
)
83 u8
*cache
= codec
->reg_cache
;
85 if (reg
>= UDA134X_REGS_NUM
)
91 * Write to the uda134x registers
94 static int uda134x_write(struct snd_soc_codec
*codec
, unsigned int reg
,
100 struct uda134x_platform_data
*pd
= codec
->control_data
;
102 pr_debug("%s reg: %02X, value:%02X\n", __func__
, reg
, value
);
104 if (reg
>= UDA134X_REGS_NUM
) {
105 printk(KERN_ERR
"%s unknown register: reg: %u",
110 uda134x_write_reg_cache(codec
, reg
, value
);
113 case UDA134X_STATUS0
:
114 case UDA134X_STATUS1
:
115 addr
= UDA134X_STATUS_ADDR
;
117 case UDA134X_DATA000
:
118 case UDA134X_DATA001
:
119 case UDA134X_DATA010
:
120 addr
= UDA134X_DATA0_ADDR
;
123 addr
= UDA134X_DATA1_ADDR
;
126 /* It's an extended address register */
127 addr
= (reg
| UDA134X_EXTADDR_PREFIX
);
129 ret
= l3_write(&pd
->l3
,
130 UDA134X_DATA0_ADDR
, &addr
, 1);
134 addr
= UDA134X_DATA0_ADDR
;
135 data
= (value
| UDA134X_EXTDATA_PREFIX
);
139 ret
= l3_write(&pd
->l3
,
147 static inline void uda134x_reset(struct snd_soc_codec
*codec
)
149 u8 reset_reg
= uda134x_read_reg_cache(codec
, UDA134X_STATUS0
);
150 uda134x_write(codec
, UDA134X_STATUS0
, reset_reg
| (1<<6));
152 uda134x_write(codec
, UDA134X_STATUS0
, reset_reg
& ~(1<<6));
155 static int uda134x_mute(struct snd_soc_dai
*dai
, int mute
)
157 struct snd_soc_codec
*codec
= dai
->codec
;
158 u8 mute_reg
= uda134x_read_reg_cache(codec
, UDA134X_DATA010
);
160 pr_debug("%s mute: %d\n", __func__
, mute
);
167 uda134x_write(codec
, UDA134X_DATA010
, mute_reg
);
172 static int uda134x_startup(struct snd_pcm_substream
*substream
,
173 struct snd_soc_dai
*dai
)
175 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
176 struct snd_soc_device
*socdev
= rtd
->socdev
;
177 struct snd_soc_codec
*codec
= socdev
->card
->codec
;
178 struct uda134x_priv
*uda134x
= snd_soc_codec_get_drvdata(codec
);
179 struct snd_pcm_runtime
*master_runtime
;
181 if (uda134x
->master_substream
) {
182 master_runtime
= uda134x
->master_substream
->runtime
;
184 pr_debug("%s constraining to %d bits at %d\n", __func__
,
185 master_runtime
->sample_bits
,
186 master_runtime
->rate
);
188 snd_pcm_hw_constraint_minmax(substream
->runtime
,
189 SNDRV_PCM_HW_PARAM_RATE
,
190 master_runtime
->rate
,
191 master_runtime
->rate
);
193 snd_pcm_hw_constraint_minmax(substream
->runtime
,
194 SNDRV_PCM_HW_PARAM_SAMPLE_BITS
,
195 master_runtime
->sample_bits
,
196 master_runtime
->sample_bits
);
198 uda134x
->slave_substream
= substream
;
200 uda134x
->master_substream
= substream
;
205 static void uda134x_shutdown(struct snd_pcm_substream
*substream
,
206 struct snd_soc_dai
*dai
)
208 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
209 struct snd_soc_device
*socdev
= rtd
->socdev
;
210 struct snd_soc_codec
*codec
= socdev
->card
->codec
;
211 struct uda134x_priv
*uda134x
= snd_soc_codec_get_drvdata(codec
);
213 if (uda134x
->master_substream
== substream
)
214 uda134x
->master_substream
= uda134x
->slave_substream
;
216 uda134x
->slave_substream
= NULL
;
219 static int uda134x_hw_params(struct snd_pcm_substream
*substream
,
220 struct snd_pcm_hw_params
*params
,
221 struct snd_soc_dai
*dai
)
223 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
224 struct snd_soc_device
*socdev
= rtd
->socdev
;
225 struct snd_soc_codec
*codec
= socdev
->card
->codec
;
226 struct uda134x_priv
*uda134x
= snd_soc_codec_get_drvdata(codec
);
229 if (substream
== uda134x
->slave_substream
) {
230 pr_debug("%s ignoring hw_params for slave substream\n",
235 hw_params
= uda134x_read_reg_cache(codec
, UDA134X_STATUS0
);
236 hw_params
&= STATUS0_SYSCLK_MASK
;
237 hw_params
&= STATUS0_DAIFMT_MASK
;
239 pr_debug("%s sysclk: %d, rate:%d\n", __func__
,
240 uda134x
->sysclk
, params_rate(params
));
242 /* set SYSCLK / fs ratio */
243 switch (uda134x
->sysclk
/ params_rate(params
)) {
253 printk(KERN_ERR
"%s unsupported fs\n", __func__
);
257 pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__
,
258 uda134x
->dai_fmt
, params_format(params
));
260 /* set DAI format and word length */
261 switch (uda134x
->dai_fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
262 case SND_SOC_DAIFMT_I2S
:
264 case SND_SOC_DAIFMT_RIGHT_J
:
265 switch (params_format(params
)) {
266 case SNDRV_PCM_FORMAT_S16_LE
:
269 case SNDRV_PCM_FORMAT_S18_3LE
:
272 case SNDRV_PCM_FORMAT_S20_3LE
:
273 hw_params
|= ((1<<2) | (1<<1));
276 printk(KERN_ERR
"%s unsupported format (right)\n",
281 case SND_SOC_DAIFMT_LEFT_J
:
285 printk(KERN_ERR
"%s unsupported format\n", __func__
);
289 uda134x_write(codec
, UDA134X_STATUS0
, hw_params
);
294 static int uda134x_set_dai_sysclk(struct snd_soc_dai
*codec_dai
,
295 int clk_id
, unsigned int freq
, int dir
)
297 struct snd_soc_codec
*codec
= codec_dai
->codec
;
298 struct uda134x_priv
*uda134x
= snd_soc_codec_get_drvdata(codec
);
300 pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__
,
303 /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
304 because the codec is slave. Of course limitations of the clock
305 master (the IIS controller) apply.
306 We'll error out on set_hw_params if it's not OK */
307 if ((freq
>= (256 * 8000)) && (freq
<= (512 * 48000))) {
308 uda134x
->sysclk
= freq
;
312 printk(KERN_ERR
"%s unsupported sysclk\n", __func__
);
316 static int uda134x_set_dai_fmt(struct snd_soc_dai
*codec_dai
,
319 struct snd_soc_codec
*codec
= codec_dai
->codec
;
320 struct uda134x_priv
*uda134x
= snd_soc_codec_get_drvdata(codec
);
322 pr_debug("%s fmt: %08X\n", __func__
, fmt
);
324 /* codec supports only full slave mode */
325 if ((fmt
& SND_SOC_DAIFMT_MASTER_MASK
) != SND_SOC_DAIFMT_CBS_CFS
) {
326 printk(KERN_ERR
"%s unsupported slave mode\n", __func__
);
330 /* no support for clock inversion */
331 if ((fmt
& SND_SOC_DAIFMT_INV_MASK
) != SND_SOC_DAIFMT_NB_NF
) {
332 printk(KERN_ERR
"%s unsupported clock inversion\n", __func__
);
336 /* We can't setup DAI format here as it depends on the word bit num */
337 /* so let's just store the value for later */
338 uda134x
->dai_fmt
= fmt
;
343 static int uda134x_set_bias_level(struct snd_soc_codec
*codec
,
344 enum snd_soc_bias_level level
)
347 struct uda134x_platform_data
*pd
= codec
->control_data
;
349 u8
*cache
= codec
->reg_cache
;
351 pr_debug("%s bias level %d\n", __func__
, level
);
354 case SND_SOC_BIAS_ON
:
356 reg
= uda134x_read_reg_cache(codec
, UDA134X_STATUS1
);
357 uda134x_write(codec
, UDA134X_STATUS1
, reg
| 0x03);
359 case SND_SOC_BIAS_PREPARE
:
363 /* Sync reg_cache with the hardware */
364 for (i
= 0; i
< ARRAY_SIZE(uda134x_reg
); i
++)
365 codec
->write(codec
, i
, *cache
++);
368 case SND_SOC_BIAS_STANDBY
:
369 /* ADC, DAC power off */
370 reg
= uda134x_read_reg_cache(codec
, UDA134X_STATUS1
);
371 uda134x_write(codec
, UDA134X_STATUS1
, reg
& ~(0x03));
373 case SND_SOC_BIAS_OFF
:
379 codec
->bias_level
= level
;
383 static const char *uda134x_dsp_setting
[] = {"Flat", "Minimum1",
384 "Minimum2", "Maximum"};
385 static const char *uda134x_deemph
[] = {"None", "32Khz", "44.1Khz", "48Khz"};
386 static const char *uda134x_mixmode
[] = {"Differential", "Analog1",
389 static const struct soc_enum uda134x_mixer_enum
[] = {
390 SOC_ENUM_SINGLE(UDA134X_DATA010
, 0, 0x04, uda134x_dsp_setting
),
391 SOC_ENUM_SINGLE(UDA134X_DATA010
, 3, 0x04, uda134x_deemph
),
392 SOC_ENUM_SINGLE(UDA134X_EA010
, 0, 0x04, uda134x_mixmode
),
395 static const struct snd_kcontrol_new uda1341_snd_controls
[] = {
396 SOC_SINGLE("Master Playback Volume", UDA134X_DATA000
, 0, 0x3F, 1),
397 SOC_SINGLE("Capture Volume", UDA134X_EA010
, 2, 0x07, 0),
398 SOC_SINGLE("Analog1 Volume", UDA134X_EA000
, 0, 0x1F, 1),
399 SOC_SINGLE("Analog2 Volume", UDA134X_EA001
, 0, 0x1F, 1),
401 SOC_SINGLE("Mic Sensitivity", UDA134X_EA010
, 2, 7, 0),
402 SOC_SINGLE("Mic Volume", UDA134X_EA101
, 0, 0x1F, 0),
404 SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001
, 2, 0xF, 0),
405 SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001
, 0, 3, 0),
407 SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum
[0]),
408 SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum
[1]),
409 SOC_ENUM("Input Mux", uda134x_mixer_enum
[2]),
411 SOC_SINGLE("AGC Switch", UDA134X_EA100
, 4, 1, 0),
412 SOC_SINGLE("AGC Target Volume", UDA134X_EA110
, 0, 0x03, 1),
413 SOC_SINGLE("AGC Timing", UDA134X_EA110
, 2, 0x07, 0),
415 SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1
, 6, 1, 0),
416 SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1
, 5, 1, 0),
417 SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1
, 4, 1, 0),
418 SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1
, 3, 1, 0),
419 SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1
, 2, 1, 0),
420 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0
, 0, 1, 0),
423 static const struct snd_kcontrol_new uda1340_snd_controls
[] = {
424 SOC_SINGLE("Master Playback Volume", UDA134X_DATA000
, 0, 0x3F, 1),
426 SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001
, 2, 0xF, 0),
427 SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001
, 0, 3, 0),
429 SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum
[0]),
430 SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum
[1]),
432 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0
, 0, 1, 0),
435 static const struct snd_kcontrol_new uda1345_snd_controls
[] = {
436 SOC_SINGLE("Master Playback Volume", UDA134X_DATA000
, 0, 0x3F, 1),
438 SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum
[1]),
440 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0
, 0, 1, 0),
443 static struct snd_soc_dai_ops uda134x_dai_ops
= {
444 .startup
= uda134x_startup
,
445 .shutdown
= uda134x_shutdown
,
446 .hw_params
= uda134x_hw_params
,
447 .digital_mute
= uda134x_mute
,
448 .set_sysclk
= uda134x_set_dai_sysclk
,
449 .set_fmt
= uda134x_set_dai_fmt
,
452 struct snd_soc_dai uda134x_dai
= {
454 /* playback capabilities */
456 .stream_name
= "Playback",
459 .rates
= UDA134X_RATES
,
460 .formats
= UDA134X_FORMATS
,
462 /* capture capabilities */
464 .stream_name
= "Capture",
467 .rates
= UDA134X_RATES
,
468 .formats
= UDA134X_FORMATS
,
471 .ops
= &uda134x_dai_ops
,
473 EXPORT_SYMBOL(uda134x_dai
);
476 static int uda134x_soc_probe(struct platform_device
*pdev
)
478 struct snd_soc_device
*socdev
= platform_get_drvdata(pdev
);
479 struct snd_soc_codec
*codec
;
480 struct uda134x_priv
*uda134x
;
481 void *codec_setup_data
= socdev
->codec_data
;
483 struct uda134x_platform_data
*pd
;
485 printk(KERN_INFO
"UDA134X SoC Audio Codec\n");
487 if (!codec_setup_data
) {
488 printk(KERN_ERR
"UDA134X SoC codec: "
489 "missing L3 bitbang function\n");
493 pd
= codec_setup_data
;
495 case UDA134X_UDA1340
:
496 case UDA134X_UDA1341
:
497 case UDA134X_UDA1344
:
498 case UDA134X_UDA1345
:
501 printk(KERN_ERR
"UDA134X SoC codec: "
502 "unsupported model %d\n",
507 socdev
->card
->codec
= kzalloc(sizeof(struct snd_soc_codec
), GFP_KERNEL
);
508 if (socdev
->card
->codec
== NULL
)
511 codec
= socdev
->card
->codec
;
513 uda134x
= kzalloc(sizeof(struct uda134x_priv
), GFP_KERNEL
);
516 snd_soc_codec_set_drvdata(codec
, uda134x
);
518 codec
->reg_cache
= kmemdup(uda134x_reg
, sizeof(uda134x_reg
),
520 if (codec
->reg_cache
== NULL
)
523 mutex_init(&codec
->mutex
);
525 codec
->reg_cache_size
= sizeof(uda134x_reg
);
526 codec
->reg_cache_step
= 1;
528 codec
->name
= "UDA134X";
529 codec
->owner
= THIS_MODULE
;
530 codec
->dai
= &uda134x_dai
;
532 codec
->read
= uda134x_read_reg_cache
;
533 codec
->write
= uda134x_write
;
534 #ifdef POWER_OFF_ON_STANDBY
535 codec
->set_bias_level
= uda134x_set_bias_level
;
537 INIT_LIST_HEAD(&codec
->dapm_widgets
);
538 INIT_LIST_HEAD(&codec
->dapm_paths
);
540 codec
->control_data
= codec_setup_data
;
545 uda134x_reset(codec
);
548 ret
= snd_soc_new_pcms(socdev
, SNDRV_DEFAULT_IDX1
, SNDRV_DEFAULT_STR1
);
550 printk(KERN_ERR
"UDA134X: failed to register pcms\n");
555 case UDA134X_UDA1340
:
556 case UDA134X_UDA1344
:
557 ret
= snd_soc_add_controls(codec
, uda1340_snd_controls
,
558 ARRAY_SIZE(uda1340_snd_controls
));
560 case UDA134X_UDA1341
:
561 ret
= snd_soc_add_controls(codec
, uda1341_snd_controls
,
562 ARRAY_SIZE(uda1341_snd_controls
));
564 case UDA134X_UDA1345
:
565 ret
= snd_soc_add_controls(codec
, uda1345_snd_controls
,
566 ARRAY_SIZE(uda1345_snd_controls
));
569 printk(KERN_ERR
"%s unknown codec type: %d",
570 __func__
, pd
->model
);
575 printk(KERN_ERR
"UDA134X: failed to register controls\n");
582 kfree(codec
->reg_cache
);
584 kfree(snd_soc_codec_get_drvdata(codec
));
590 /* power down chip */
591 static int uda134x_soc_remove(struct platform_device
*pdev
)
593 struct snd_soc_device
*socdev
= platform_get_drvdata(pdev
);
594 struct snd_soc_codec
*codec
= socdev
->card
->codec
;
596 uda134x_set_bias_level(codec
, SND_SOC_BIAS_STANDBY
);
597 uda134x_set_bias_level(codec
, SND_SOC_BIAS_OFF
);
599 snd_soc_free_pcms(socdev
);
600 snd_soc_dapm_free(socdev
);
602 kfree(snd_soc_codec_get_drvdata(codec
));
603 kfree(codec
->reg_cache
);
609 #if defined(CONFIG_PM)
610 static int uda134x_soc_suspend(struct platform_device
*pdev
,
613 struct snd_soc_device
*socdev
= platform_get_drvdata(pdev
);
614 struct snd_soc_codec
*codec
= socdev
->card
->codec
;
616 uda134x_set_bias_level(codec
, SND_SOC_BIAS_STANDBY
);
617 uda134x_set_bias_level(codec
, SND_SOC_BIAS_OFF
);
621 static int uda134x_soc_resume(struct platform_device
*pdev
)
623 struct snd_soc_device
*socdev
= platform_get_drvdata(pdev
);
624 struct snd_soc_codec
*codec
= socdev
->card
->codec
;
626 uda134x_set_bias_level(codec
, SND_SOC_BIAS_PREPARE
);
627 uda134x_set_bias_level(codec
, SND_SOC_BIAS_ON
);
631 #define uda134x_soc_suspend NULL
632 #define uda134x_soc_resume NULL
633 #endif /* CONFIG_PM */
635 struct snd_soc_codec_device soc_codec_dev_uda134x
= {
636 .probe
= uda134x_soc_probe
,
637 .remove
= uda134x_soc_remove
,
638 .suspend
= uda134x_soc_suspend
,
639 .resume
= uda134x_soc_resume
,
641 EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x
);
643 static int __init
uda134x_init(void)
645 return snd_soc_register_dai(&uda134x_dai
);
647 module_init(uda134x_init
);
649 static void __exit
uda134x_exit(void)
651 snd_soc_unregister_dai(&uda134x_dai
);
653 module_exit(uda134x_exit
);
655 MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
656 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
657 MODULE_LICENSE("GPL");