blob: a8dcd5a5bbcb2e0ac743e95a731ecb4c7e1c123f [file] [log] [blame]
Christian Pellegrin1cad1de2008-11-15 08:58:16 +01001/*
2 * uda134x.c -- UDA134X ALSA SoC Codec driver
3 *
4 * Modifications by Christian Pellegrin <chripell@evolware.org>
5 *
6 * Copyright 2007 Dension Audio Systems Ltd.
7 * Author: Zoltan Devai
8 *
9 * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie
10 *
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.
14 */
15
16#include <linux/module.h>
17#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
Christian Pellegrin1cad1de2008-11-15 08:58:16 +010019#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>
24
25#include <sound/uda134x.h>
26#include <sound/l3.h>
27
Mark Brown72f2b892008-11-18 12:25:46 +000028#include "uda134x.h"
Christian Pellegrin1cad1de2008-11-15 08:58:16 +010029
30
31#define POWER_OFF_ON_STANDBY 1
32/*
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.
42 */
43
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)
47
48struct uda134x_priv {
49 int sysclk;
50 int dai_fmt;
51
52 struct snd_pcm_substream *master_substream;
53 struct snd_pcm_substream *slave_substream;
54};
55
56/* In-data addresses are hard-coded into the reg-cache values */
57static 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,
62};
63
64/*
65 * The codec has no support for reading its registers except for peak level...
66 */
67static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec,
68 unsigned int reg)
69{
70 u8 *cache = codec->reg_cache;
71
72 if (reg >= UDA134X_REGS_NUM)
73 return -1;
74 return cache[reg];
75}
76
77/*
78 * Write the register cache
79 */
80static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec,
81 u8 reg, unsigned int value)
82{
83 u8 *cache = codec->reg_cache;
84
85 if (reg >= UDA134X_REGS_NUM)
86 return;
87 cache[reg] = value;
88}
89
90/*
91 * Write to the uda134x registers
92 *
93 */
94static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
95 unsigned int value)
96{
97 int ret;
98 u8 addr;
99 u8 data = value;
100 struct uda134x_platform_data *pd = codec->control_data;
101
102 pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
103
104 if (reg >= UDA134X_REGS_NUM) {
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200105 printk(KERN_ERR "%s unknown register: reg: %u",
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100106 __func__, reg);
107 return -EINVAL;
108 }
109
110 uda134x_write_reg_cache(codec, reg, value);
111
112 switch (reg) {
113 case UDA134X_STATUS0:
114 case UDA134X_STATUS1:
115 addr = UDA134X_STATUS_ADDR;
116 break;
117 case UDA134X_DATA000:
118 case UDA134X_DATA001:
119 case UDA134X_DATA010:
120 addr = UDA134X_DATA0_ADDR;
121 break;
122 case UDA134X_DATA1:
123 addr = UDA134X_DATA1_ADDR;
124 break;
125 default:
126 /* It's an extended address register */
127 addr = (reg | UDA134X_EXTADDR_PREFIX);
128
129 ret = l3_write(&pd->l3,
130 UDA134X_DATA0_ADDR, &addr, 1);
131 if (ret != 1)
132 return -EIO;
133
134 addr = UDA134X_DATA0_ADDR;
135 data = (value | UDA134X_EXTDATA_PREFIX);
136 break;
137 }
138
139 ret = l3_write(&pd->l3,
140 addr, &data, 1);
141 if (ret != 1)
142 return -EIO;
143
144 return 0;
145}
146
147static inline void uda134x_reset(struct snd_soc_codec *codec)
148{
149 u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
150 uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6));
151 msleep(1);
152 uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6));
153}
154
155static int uda134x_mute(struct snd_soc_dai *dai, int mute)
156{
157 struct snd_soc_codec *codec = dai->codec;
158 u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010);
159
160 pr_debug("%s mute: %d\n", __func__, mute);
161
162 if (mute)
163 mute_reg |= (1<<2);
164 else
165 mute_reg &= ~(1<<2);
166
Shine Liu0c093fb2009-08-17 18:52:01 +0800167 uda134x_write(codec, UDA134X_DATA010, mute_reg);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100168
169 return 0;
170}
171
Mark Browndee89c42008-11-18 22:11:38 +0000172static int uda134x_startup(struct snd_pcm_substream *substream,
173 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100174{
175 struct snd_soc_pcm_runtime *rtd = substream->private_data;
176 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000177 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100178 struct uda134x_priv *uda134x = codec->private_data;
179 struct snd_pcm_runtime *master_runtime;
180
181 if (uda134x->master_substream) {
182 master_runtime = uda134x->master_substream->runtime;
183
184 pr_debug("%s constraining to %d bits at %d\n", __func__,
185 master_runtime->sample_bits,
186 master_runtime->rate);
187
188 snd_pcm_hw_constraint_minmax(substream->runtime,
189 SNDRV_PCM_HW_PARAM_RATE,
190 master_runtime->rate,
191 master_runtime->rate);
192
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);
197
198 uda134x->slave_substream = substream;
199 } else
200 uda134x->master_substream = substream;
201
202 return 0;
203}
204
Mark Browndee89c42008-11-18 22:11:38 +0000205static void uda134x_shutdown(struct snd_pcm_substream *substream,
206 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100207{
208 struct snd_soc_pcm_runtime *rtd = substream->private_data;
209 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000210 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100211 struct uda134x_priv *uda134x = codec->private_data;
212
213 if (uda134x->master_substream == substream)
214 uda134x->master_substream = uda134x->slave_substream;
215
216 uda134x->slave_substream = NULL;
217}
218
219static int uda134x_hw_params(struct snd_pcm_substream *substream,
Mark Browndee89c42008-11-18 22:11:38 +0000220 struct snd_pcm_hw_params *params,
221 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100222{
223 struct snd_soc_pcm_runtime *rtd = substream->private_data;
224 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000225 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100226 struct uda134x_priv *uda134x = codec->private_data;
227 u8 hw_params;
228
229 if (substream == uda134x->slave_substream) {
230 pr_debug("%s ignoring hw_params for slave substream\n",
231 __func__);
232 return 0;
233 }
234
235 hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
236 hw_params &= STATUS0_SYSCLK_MASK;
237 hw_params &= STATUS0_DAIFMT_MASK;
238
239 pr_debug("%s sysclk: %d, rate:%d\n", __func__,
240 uda134x->sysclk, params_rate(params));
241
242 /* set SYSCLK / fs ratio */
243 switch (uda134x->sysclk / params_rate(params)) {
244 case 512:
245 break;
246 case 384:
247 hw_params |= (1<<4);
248 break;
249 case 256:
250 hw_params |= (1<<5);
251 break;
252 default:
253 printk(KERN_ERR "%s unsupported fs\n", __func__);
254 return -EINVAL;
255 }
256
257 pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
258 uda134x->dai_fmt, params_format(params));
259
260 /* set DAI format and word length */
261 switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
262 case SND_SOC_DAIFMT_I2S:
263 break;
264 case SND_SOC_DAIFMT_RIGHT_J:
265 switch (params_format(params)) {
266 case SNDRV_PCM_FORMAT_S16_LE:
267 hw_params |= (1<<1);
268 break;
269 case SNDRV_PCM_FORMAT_S18_3LE:
270 hw_params |= (1<<2);
271 break;
272 case SNDRV_PCM_FORMAT_S20_3LE:
273 hw_params |= ((1<<2) | (1<<1));
274 break;
275 default:
276 printk(KERN_ERR "%s unsupported format (right)\n",
277 __func__);
278 return -EINVAL;
279 }
280 break;
281 case SND_SOC_DAIFMT_LEFT_J:
282 hw_params |= (1<<3);
283 break;
284 default:
285 printk(KERN_ERR "%s unsupported format\n", __func__);
286 return -EINVAL;
287 }
288
289 uda134x_write(codec, UDA134X_STATUS0, hw_params);
290
291 return 0;
292}
293
294static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
295 int clk_id, unsigned int freq, int dir)
296{
297 struct snd_soc_codec *codec = codec_dai->codec;
298 struct uda134x_priv *uda134x = codec->private_data;
299
Roel Kluin449bd542009-05-27 17:08:39 -0700300 pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100301 clk_id, freq, dir);
302
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;
309 return 0;
310 }
311
312 printk(KERN_ERR "%s unsupported sysclk\n", __func__);
313 return -EINVAL;
314}
315
316static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
317 unsigned int fmt)
318{
319 struct snd_soc_codec *codec = codec_dai->codec;
320 struct uda134x_priv *uda134x = codec->private_data;
321
322 pr_debug("%s fmt: %08X\n", __func__, fmt);
323
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__);
327 return -EINVAL;
328 }
329
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__);
333 return -EINVAL;
334 }
335
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;
339
340 return 0;
341}
342
343static int uda134x_set_bias_level(struct snd_soc_codec *codec,
344 enum snd_soc_bias_level level)
345{
346 u8 reg;
347 struct uda134x_platform_data *pd = codec->control_data;
348 int i;
349 u8 *cache = codec->reg_cache;
350
351 pr_debug("%s bias level %d\n", __func__, level);
352
353 switch (level) {
354 case SND_SOC_BIAS_ON:
355 /* ADC, DAC on */
356 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
357 uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
358 break;
359 case SND_SOC_BIAS_PREPARE:
360 /* power on */
361 if (pd->power) {
362 pd->power(1);
363 /* Sync reg_cache with the hardware */
364 for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
365 codec->write(codec, i, *cache++);
366 }
367 break;
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));
372 break;
373 case SND_SOC_BIAS_OFF:
374 /* power off */
375 if (pd->power)
376 pd->power(0);
377 break;
378 }
379 codec->bias_level = level;
380 return 0;
381}
382
383static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
384 "Minimum2", "Maximum"};
385static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
386static const char *uda134x_mixmode[] = {"Differential", "Analog1",
387 "Analog2", "Both"};
388
389static const struct soc_enum uda134x_mixer_enum[] = {
390SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
391SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
392SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
393};
394
395static const struct snd_kcontrol_new uda1341_snd_controls[] = {
396SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
397SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
398SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
399SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
400
401SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
402SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
403
404SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
405SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
406
407SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
408SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
409SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
410
411SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
412SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
413SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
414
415SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
416SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
417SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
418SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
419SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
420SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
421};
422
423static const struct snd_kcontrol_new uda1340_snd_controls[] = {
424SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
425
426SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
427SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
428
429SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
430SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
431
432SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
433};
434
Eric Miao6335d052009-03-03 09:41:00 +0800435static struct snd_soc_dai_ops uda134x_dai_ops = {
436 .startup = uda134x_startup,
437 .shutdown = uda134x_shutdown,
438 .hw_params = uda134x_hw_params,
439 .digital_mute = uda134x_mute,
440 .set_sysclk = uda134x_set_dai_sysclk,
441 .set_fmt = uda134x_set_dai_fmt,
442};
443
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100444struct snd_soc_dai uda134x_dai = {
445 .name = "UDA134X",
446 /* playback capabilities */
447 .playback = {
448 .stream_name = "Playback",
449 .channels_min = 1,
450 .channels_max = 2,
451 .rates = UDA134X_RATES,
452 .formats = UDA134X_FORMATS,
453 },
454 /* capture capabilities */
455 .capture = {
456 .stream_name = "Capture",
457 .channels_min = 1,
458 .channels_max = 2,
459 .rates = UDA134X_RATES,
460 .formats = UDA134X_FORMATS,
461 },
462 /* pcm operations */
Eric Miao6335d052009-03-03 09:41:00 +0800463 .ops = &uda134x_dai_ops,
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100464};
465EXPORT_SYMBOL(uda134x_dai);
466
467
468static int uda134x_soc_probe(struct platform_device *pdev)
469{
470 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
471 struct snd_soc_codec *codec;
472 struct uda134x_priv *uda134x;
473 void *codec_setup_data = socdev->codec_data;
474 int ret = -ENOMEM;
475 struct uda134x_platform_data *pd;
476
477 printk(KERN_INFO "UDA134X SoC Audio Codec\n");
478
479 if (!codec_setup_data) {
480 printk(KERN_ERR "UDA134X SoC codec: "
481 "missing L3 bitbang function\n");
482 return -ENODEV;
483 }
484
485 pd = codec_setup_data;
486 switch (pd->model) {
487 case UDA134X_UDA1340:
488 case UDA134X_UDA1341:
489 case UDA134X_UDA1344:
490 break;
491 default:
492 printk(KERN_ERR "UDA134X SoC codec: "
493 "unsupported model %d\n",
494 pd->model);
495 return -EINVAL;
496 }
497
Mark Brown6627a652009-01-23 22:55:23 +0000498 socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
499 if (socdev->card->codec == NULL)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100500 return ret;
501
Mark Brown6627a652009-01-23 22:55:23 +0000502 codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100503
504 uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
505 if (uda134x == NULL)
506 goto priv_err;
507 codec->private_data = uda134x;
508
509 codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
510 GFP_KERNEL);
511 if (codec->reg_cache == NULL)
512 goto reg_err;
513
514 mutex_init(&codec->mutex);
515
516 codec->reg_cache_size = sizeof(uda134x_reg);
517 codec->reg_cache_step = 1;
518
519 codec->name = "UDA134X";
520 codec->owner = THIS_MODULE;
521 codec->dai = &uda134x_dai;
522 codec->num_dai = 1;
523 codec->read = uda134x_read_reg_cache;
524 codec->write = uda134x_write;
525#ifdef POWER_OFF_ON_STANDBY
526 codec->set_bias_level = uda134x_set_bias_level;
527#endif
528 INIT_LIST_HEAD(&codec->dapm_widgets);
529 INIT_LIST_HEAD(&codec->dapm_paths);
530
531 codec->control_data = codec_setup_data;
532
533 if (pd->power)
534 pd->power(1);
535
536 uda134x_reset(codec);
537
538 /* register pcms */
539 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
540 if (ret < 0) {
541 printk(KERN_ERR "UDA134X: failed to register pcms\n");
542 goto pcm_err;
543 }
544
Ian Molton3e8e1952009-01-09 00:23:21 +0000545 switch (pd->model) {
546 case UDA134X_UDA1340:
547 case UDA134X_UDA1344:
548 ret = snd_soc_add_controls(codec, uda1340_snd_controls,
549 ARRAY_SIZE(uda1340_snd_controls));
550 break;
551 case UDA134X_UDA1341:
552 ret = snd_soc_add_controls(codec, uda1341_snd_controls,
553 ARRAY_SIZE(uda1341_snd_controls));
554 break;
555 default:
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200556 printk(KERN_ERR "%s unknown codec type: %d",
Ian Molton3e8e1952009-01-09 00:23:21 +0000557 __func__, pd->model);
558 return -EINVAL;
559 }
560
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100561 if (ret < 0) {
562 printk(KERN_ERR "UDA134X: failed to register controls\n");
563 goto pcm_err;
564 }
565
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100566 return 0;
567
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100568pcm_err:
569 kfree(codec->reg_cache);
570reg_err:
571 kfree(codec->private_data);
572priv_err:
573 kfree(codec);
574 return ret;
575}
576
577/* power down chip */
578static int uda134x_soc_remove(struct platform_device *pdev)
579{
580 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000581 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100582
583 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
584 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
585
586 snd_soc_free_pcms(socdev);
587 snd_soc_dapm_free(socdev);
588
589 kfree(codec->private_data);
590 kfree(codec->reg_cache);
591 kfree(codec);
592
593 return 0;
594}
595
596#if defined(CONFIG_PM)
597static int uda134x_soc_suspend(struct platform_device *pdev,
598 pm_message_t state)
599{
600 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000601 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100602
603 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
604 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
605 return 0;
606}
607
608static int uda134x_soc_resume(struct platform_device *pdev)
609{
610 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000611 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100612
613 uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
614 uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
615 return 0;
616}
617#else
618#define uda134x_soc_suspend NULL
619#define uda134x_soc_resume NULL
620#endif /* CONFIG_PM */
621
622struct snd_soc_codec_device soc_codec_dev_uda134x = {
623 .probe = uda134x_soc_probe,
624 .remove = uda134x_soc_remove,
625 .suspend = uda134x_soc_suspend,
626 .resume = uda134x_soc_resume,
627};
628EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
629
Takashi Iwaic9b3a402008-12-10 07:47:22 +0100630static int __init uda134x_init(void)
Mark Brown64089b82008-12-08 19:17:58 +0000631{
632 return snd_soc_register_dai(&uda134x_dai);
633}
634module_init(uda134x_init);
635
636static void __exit uda134x_exit(void)
637{
638 snd_soc_unregister_dai(&uda134x_dai);
639}
640module_exit(uda134x_exit);
641
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100642MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
643MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
644MODULE_LICENSE("GPL");