blob: 2f4d7287fa3cf7f2db7342733b52de21d99d0b66 [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>
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22#include <sound/initval.h>
23
24#include <sound/uda134x.h>
25#include <sound/l3.h>
26
Mark Brown72f2b892008-11-18 12:25:46 +000027#include "uda134x.h"
Christian Pellegrin1cad1de2008-11-15 08:58:16 +010028
29
30#define POWER_OFF_ON_STANDBY 1
31/*
32 ALSA SOC usually puts the device in standby mode when it's not used
33 for sometime. If you define POWER_OFF_ON_STANDBY the driver will
34 turn off the ADC/DAC when this callback is invoked and turn it back
35 on when needed. Unfortunately this will result in a very light bump
36 (it can be audible only with good earphones). If this bothers you
37 just comment this line, you will have slightly higher power
38 consumption . Please note that sending the L3 command for ADC is
39 enough to make the bump, so it doesn't make difference if you
40 completely take off power from the codec.
41 */
42
43#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
44#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
45 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
46
47struct uda134x_priv {
48 int sysclk;
49 int dai_fmt;
50
51 struct snd_pcm_substream *master_substream;
52 struct snd_pcm_substream *slave_substream;
53};
54
55/* In-data addresses are hard-coded into the reg-cache values */
56static const char uda134x_reg[UDA134X_REGS_NUM] = {
57 /* Extended address registers */
58 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
59 /* Status, data regs */
60 0x00, 0x83, 0x00, 0x40, 0x80, 0x00,
61};
62
63/*
64 * The codec has no support for reading its registers except for peak level...
65 */
66static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec,
67 unsigned int reg)
68{
69 u8 *cache = codec->reg_cache;
70
71 if (reg >= UDA134X_REGS_NUM)
72 return -1;
73 return cache[reg];
74}
75
76/*
77 * Write the register cache
78 */
79static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec,
80 u8 reg, unsigned int value)
81{
82 u8 *cache = codec->reg_cache;
83
84 if (reg >= UDA134X_REGS_NUM)
85 return;
86 cache[reg] = value;
87}
88
89/*
90 * Write to the uda134x registers
91 *
92 */
93static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
94 unsigned int value)
95{
96 int ret;
97 u8 addr;
98 u8 data = value;
99 struct uda134x_platform_data *pd = codec->control_data;
100
101 pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
102
103 if (reg >= UDA134X_REGS_NUM) {
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200104 printk(KERN_ERR "%s unknown register: reg: %u",
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100105 __func__, reg);
106 return -EINVAL;
107 }
108
109 uda134x_write_reg_cache(codec, reg, value);
110
111 switch (reg) {
112 case UDA134X_STATUS0:
113 case UDA134X_STATUS1:
114 addr = UDA134X_STATUS_ADDR;
115 break;
116 case UDA134X_DATA000:
117 case UDA134X_DATA001:
118 case UDA134X_DATA010:
119 addr = UDA134X_DATA0_ADDR;
120 break;
121 case UDA134X_DATA1:
122 addr = UDA134X_DATA1_ADDR;
123 break;
124 default:
125 /* It's an extended address register */
126 addr = (reg | UDA134X_EXTADDR_PREFIX);
127
128 ret = l3_write(&pd->l3,
129 UDA134X_DATA0_ADDR, &addr, 1);
130 if (ret != 1)
131 return -EIO;
132
133 addr = UDA134X_DATA0_ADDR;
134 data = (value | UDA134X_EXTDATA_PREFIX);
135 break;
136 }
137
138 ret = l3_write(&pd->l3,
139 addr, &data, 1);
140 if (ret != 1)
141 return -EIO;
142
143 return 0;
144}
145
146static inline void uda134x_reset(struct snd_soc_codec *codec)
147{
148 u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
149 uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6));
150 msleep(1);
151 uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6));
152}
153
154static int uda134x_mute(struct snd_soc_dai *dai, int mute)
155{
156 struct snd_soc_codec *codec = dai->codec;
157 u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010);
158
159 pr_debug("%s mute: %d\n", __func__, mute);
160
161 if (mute)
162 mute_reg |= (1<<2);
163 else
164 mute_reg &= ~(1<<2);
165
Shine Liu0c093fb2009-08-17 18:52:01 +0800166 uda134x_write(codec, UDA134X_DATA010, mute_reg);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100167
168 return 0;
169}
170
Mark Browndee89c42008-11-18 22:11:38 +0000171static int uda134x_startup(struct snd_pcm_substream *substream,
172 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100173{
174 struct snd_soc_pcm_runtime *rtd = substream->private_data;
175 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000176 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900177 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100178 struct snd_pcm_runtime *master_runtime;
179
180 if (uda134x->master_substream) {
181 master_runtime = uda134x->master_substream->runtime;
182
183 pr_debug("%s constraining to %d bits at %d\n", __func__,
184 master_runtime->sample_bits,
185 master_runtime->rate);
186
187 snd_pcm_hw_constraint_minmax(substream->runtime,
188 SNDRV_PCM_HW_PARAM_RATE,
189 master_runtime->rate,
190 master_runtime->rate);
191
192 snd_pcm_hw_constraint_minmax(substream->runtime,
193 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
194 master_runtime->sample_bits,
195 master_runtime->sample_bits);
196
197 uda134x->slave_substream = substream;
198 } else
199 uda134x->master_substream = substream;
200
201 return 0;
202}
203
Mark Browndee89c42008-11-18 22:11:38 +0000204static void uda134x_shutdown(struct snd_pcm_substream *substream,
205 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100206{
207 struct snd_soc_pcm_runtime *rtd = substream->private_data;
208 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000209 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900210 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100211
212 if (uda134x->master_substream == substream)
213 uda134x->master_substream = uda134x->slave_substream;
214
215 uda134x->slave_substream = NULL;
216}
217
218static int uda134x_hw_params(struct snd_pcm_substream *substream,
Mark Browndee89c42008-11-18 22:11:38 +0000219 struct snd_pcm_hw_params *params,
220 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100221{
222 struct snd_soc_pcm_runtime *rtd = substream->private_data;
223 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000224 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900225 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100226 u8 hw_params;
227
228 if (substream == uda134x->slave_substream) {
229 pr_debug("%s ignoring hw_params for slave substream\n",
230 __func__);
231 return 0;
232 }
233
234 hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
235 hw_params &= STATUS0_SYSCLK_MASK;
236 hw_params &= STATUS0_DAIFMT_MASK;
237
238 pr_debug("%s sysclk: %d, rate:%d\n", __func__,
239 uda134x->sysclk, params_rate(params));
240
241 /* set SYSCLK / fs ratio */
242 switch (uda134x->sysclk / params_rate(params)) {
243 case 512:
244 break;
245 case 384:
246 hw_params |= (1<<4);
247 break;
248 case 256:
249 hw_params |= (1<<5);
250 break;
251 default:
252 printk(KERN_ERR "%s unsupported fs\n", __func__);
253 return -EINVAL;
254 }
255
256 pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
257 uda134x->dai_fmt, params_format(params));
258
259 /* set DAI format and word length */
260 switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
261 case SND_SOC_DAIFMT_I2S:
262 break;
263 case SND_SOC_DAIFMT_RIGHT_J:
264 switch (params_format(params)) {
265 case SNDRV_PCM_FORMAT_S16_LE:
266 hw_params |= (1<<1);
267 break;
268 case SNDRV_PCM_FORMAT_S18_3LE:
269 hw_params |= (1<<2);
270 break;
271 case SNDRV_PCM_FORMAT_S20_3LE:
272 hw_params |= ((1<<2) | (1<<1));
273 break;
274 default:
275 printk(KERN_ERR "%s unsupported format (right)\n",
276 __func__);
277 return -EINVAL;
278 }
279 break;
280 case SND_SOC_DAIFMT_LEFT_J:
281 hw_params |= (1<<3);
282 break;
283 default:
284 printk(KERN_ERR "%s unsupported format\n", __func__);
285 return -EINVAL;
286 }
287
288 uda134x_write(codec, UDA134X_STATUS0, hw_params);
289
290 return 0;
291}
292
293static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
294 int clk_id, unsigned int freq, int dir)
295{
296 struct snd_soc_codec *codec = codec_dai->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900297 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100298
Roel Kluin449bd542009-05-27 17:08:39 -0700299 pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100300 clk_id, freq, dir);
301
302 /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
303 because the codec is slave. Of course limitations of the clock
304 master (the IIS controller) apply.
305 We'll error out on set_hw_params if it's not OK */
306 if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
307 uda134x->sysclk = freq;
308 return 0;
309 }
310
311 printk(KERN_ERR "%s unsupported sysclk\n", __func__);
312 return -EINVAL;
313}
314
315static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
316 unsigned int fmt)
317{
318 struct snd_soc_codec *codec = codec_dai->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900319 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100320
321 pr_debug("%s fmt: %08X\n", __func__, fmt);
322
323 /* codec supports only full slave mode */
324 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
325 printk(KERN_ERR "%s unsupported slave mode\n", __func__);
326 return -EINVAL;
327 }
328
329 /* no support for clock inversion */
330 if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
331 printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
332 return -EINVAL;
333 }
334
335 /* We can't setup DAI format here as it depends on the word bit num */
336 /* so let's just store the value for later */
337 uda134x->dai_fmt = fmt;
338
339 return 0;
340}
341
342static int uda134x_set_bias_level(struct snd_soc_codec *codec,
343 enum snd_soc_bias_level level)
344{
345 u8 reg;
346 struct uda134x_platform_data *pd = codec->control_data;
347 int i;
348 u8 *cache = codec->reg_cache;
349
350 pr_debug("%s bias level %d\n", __func__, level);
351
352 switch (level) {
353 case SND_SOC_BIAS_ON:
354 /* ADC, DAC on */
355 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
356 uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
357 break;
358 case SND_SOC_BIAS_PREPARE:
359 /* power on */
360 if (pd->power) {
361 pd->power(1);
362 /* Sync reg_cache with the hardware */
363 for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
364 codec->write(codec, i, *cache++);
365 }
366 break;
367 case SND_SOC_BIAS_STANDBY:
368 /* ADC, DAC power off */
369 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
370 uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
371 break;
372 case SND_SOC_BIAS_OFF:
373 /* power off */
374 if (pd->power)
375 pd->power(0);
376 break;
377 }
378 codec->bias_level = level;
379 return 0;
380}
381
382static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
383 "Minimum2", "Maximum"};
384static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
385static const char *uda134x_mixmode[] = {"Differential", "Analog1",
386 "Analog2", "Both"};
387
388static const struct soc_enum uda134x_mixer_enum[] = {
389SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
390SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
391SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
392};
393
394static const struct snd_kcontrol_new uda1341_snd_controls[] = {
395SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
396SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
397SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
398SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
399
400SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
401SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
402
403SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
404SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
405
406SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
407SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
408SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
409
410SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
411SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
412SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
413
414SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
415SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
416SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
417SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
418SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
419SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
420};
421
422static const struct snd_kcontrol_new uda1340_snd_controls[] = {
423SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
424
425SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
426SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
427
428SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
429SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
430
431SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
432};
433
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400434static const struct snd_kcontrol_new uda1345_snd_controls[] = {
435SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
436
437SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
438
439SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
440};
441
Eric Miao6335d052009-03-03 09:41:00 +0800442static struct snd_soc_dai_ops uda134x_dai_ops = {
443 .startup = uda134x_startup,
444 .shutdown = uda134x_shutdown,
445 .hw_params = uda134x_hw_params,
446 .digital_mute = uda134x_mute,
447 .set_sysclk = uda134x_set_dai_sysclk,
448 .set_fmt = uda134x_set_dai_fmt,
449};
450
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100451struct snd_soc_dai uda134x_dai = {
452 .name = "UDA134X",
453 /* playback capabilities */
454 .playback = {
455 .stream_name = "Playback",
456 .channels_min = 1,
457 .channels_max = 2,
458 .rates = UDA134X_RATES,
459 .formats = UDA134X_FORMATS,
460 },
461 /* capture capabilities */
462 .capture = {
463 .stream_name = "Capture",
464 .channels_min = 1,
465 .channels_max = 2,
466 .rates = UDA134X_RATES,
467 .formats = UDA134X_FORMATS,
468 },
469 /* pcm operations */
Eric Miao6335d052009-03-03 09:41:00 +0800470 .ops = &uda134x_dai_ops,
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100471};
472EXPORT_SYMBOL(uda134x_dai);
473
474
475static int uda134x_soc_probe(struct platform_device *pdev)
476{
477 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
478 struct snd_soc_codec *codec;
479 struct uda134x_priv *uda134x;
480 void *codec_setup_data = socdev->codec_data;
481 int ret = -ENOMEM;
482 struct uda134x_platform_data *pd;
483
484 printk(KERN_INFO "UDA134X SoC Audio Codec\n");
485
486 if (!codec_setup_data) {
487 printk(KERN_ERR "UDA134X SoC codec: "
488 "missing L3 bitbang function\n");
489 return -ENODEV;
490 }
491
492 pd = codec_setup_data;
493 switch (pd->model) {
494 case UDA134X_UDA1340:
495 case UDA134X_UDA1341:
496 case UDA134X_UDA1344:
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400497 case UDA134X_UDA1345:
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100498 break;
499 default:
500 printk(KERN_ERR "UDA134X SoC codec: "
501 "unsupported model %d\n",
502 pd->model);
503 return -EINVAL;
504 }
505
Mark Brown6627a652009-01-23 22:55:23 +0000506 socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
507 if (socdev->card->codec == NULL)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100508 return ret;
509
Mark Brown6627a652009-01-23 22:55:23 +0000510 codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100511
512 uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
513 if (uda134x == NULL)
514 goto priv_err;
Mark Brownb2c812e2010-04-14 15:35:19 +0900515 snd_soc_codec_set_drvdata(codec, uda134x);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100516
517 codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
518 GFP_KERNEL);
519 if (codec->reg_cache == NULL)
520 goto reg_err;
521
522 mutex_init(&codec->mutex);
523
524 codec->reg_cache_size = sizeof(uda134x_reg);
525 codec->reg_cache_step = 1;
526
527 codec->name = "UDA134X";
528 codec->owner = THIS_MODULE;
529 codec->dai = &uda134x_dai;
530 codec->num_dai = 1;
531 codec->read = uda134x_read_reg_cache;
532 codec->write = uda134x_write;
533#ifdef POWER_OFF_ON_STANDBY
534 codec->set_bias_level = uda134x_set_bias_level;
535#endif
536 INIT_LIST_HEAD(&codec->dapm_widgets);
537 INIT_LIST_HEAD(&codec->dapm_paths);
538
539 codec->control_data = codec_setup_data;
540
541 if (pd->power)
542 pd->power(1);
543
544 uda134x_reset(codec);
545
546 /* register pcms */
547 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
548 if (ret < 0) {
549 printk(KERN_ERR "UDA134X: failed to register pcms\n");
550 goto pcm_err;
551 }
552
Ian Molton3e8e1952009-01-09 00:23:21 +0000553 switch (pd->model) {
554 case UDA134X_UDA1340:
555 case UDA134X_UDA1344:
556 ret = snd_soc_add_controls(codec, uda1340_snd_controls,
557 ARRAY_SIZE(uda1340_snd_controls));
558 break;
559 case UDA134X_UDA1341:
560 ret = snd_soc_add_controls(codec, uda1341_snd_controls,
561 ARRAY_SIZE(uda1341_snd_controls));
562 break;
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400563 case UDA134X_UDA1345:
564 ret = snd_soc_add_controls(codec, uda1345_snd_controls,
565 ARRAY_SIZE(uda1345_snd_controls));
566 break;
Ian Molton3e8e1952009-01-09 00:23:21 +0000567 default:
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200568 printk(KERN_ERR "%s unknown codec type: %d",
Ian Molton3e8e1952009-01-09 00:23:21 +0000569 __func__, pd->model);
570 return -EINVAL;
571 }
572
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100573 if (ret < 0) {
574 printk(KERN_ERR "UDA134X: failed to register controls\n");
575 goto pcm_err;
576 }
577
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100578 return 0;
579
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100580pcm_err:
581 kfree(codec->reg_cache);
582reg_err:
Mark Brownb2c812e2010-04-14 15:35:19 +0900583 kfree(snd_soc_codec_get_drvdata(codec));
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100584priv_err:
585 kfree(codec);
586 return ret;
587}
588
589/* power down chip */
590static int uda134x_soc_remove(struct platform_device *pdev)
591{
592 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000593 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100594
595 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
596 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
597
598 snd_soc_free_pcms(socdev);
599 snd_soc_dapm_free(socdev);
600
Mark Brownb2c812e2010-04-14 15:35:19 +0900601 kfree(snd_soc_codec_get_drvdata(codec));
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100602 kfree(codec->reg_cache);
603 kfree(codec);
604
605 return 0;
606}
607
608#if defined(CONFIG_PM)
609static int uda134x_soc_suspend(struct platform_device *pdev,
610 pm_message_t state)
611{
612 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000613 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100614
615 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
616 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
617 return 0;
618}
619
620static int uda134x_soc_resume(struct platform_device *pdev)
621{
622 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000623 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100624
625 uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
626 uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
627 return 0;
628}
629#else
630#define uda134x_soc_suspend NULL
631#define uda134x_soc_resume NULL
632#endif /* CONFIG_PM */
633
634struct snd_soc_codec_device soc_codec_dev_uda134x = {
635 .probe = uda134x_soc_probe,
636 .remove = uda134x_soc_remove,
637 .suspend = uda134x_soc_suspend,
638 .resume = uda134x_soc_resume,
639};
640EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
641
Takashi Iwaic9b3a402008-12-10 07:47:22 +0100642static int __init uda134x_init(void)
Mark Brown64089b82008-12-08 19:17:58 +0000643{
644 return snd_soc_register_dai(&uda134x_dai);
645}
646module_init(uda134x_init);
647
648static void __exit uda134x_exit(void)
649{
650 snd_soc_unregister_dai(&uda134x_dai);
651}
652module_exit(uda134x_exit);
653
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100654MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
655MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
656MODULE_LICENSE("GPL");