blob: 28aac53c97bb799e1b8b731fd75053a15799d4c9 [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;
Mark Brownb2c812e2010-04-14 15:35:19 +0900178 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100179 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;
Mark Brownb2c812e2010-04-14 15:35:19 +0900211 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100212
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;
Mark Brownb2c812e2010-04-14 15:35:19 +0900226 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100227 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;
Mark Brownb2c812e2010-04-14 15:35:19 +0900298 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100299
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;
Mark Brownb2c812e2010-04-14 15:35:19 +0900320 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100321
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
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400435static const struct snd_kcontrol_new uda1345_snd_controls[] = {
436SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
437
438SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
439
440SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
441};
442
Eric Miao6335d052009-03-03 09:41:00 +0800443static 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,
450};
451
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100452struct snd_soc_dai uda134x_dai = {
453 .name = "UDA134X",
454 /* playback capabilities */
455 .playback = {
456 .stream_name = "Playback",
457 .channels_min = 1,
458 .channels_max = 2,
459 .rates = UDA134X_RATES,
460 .formats = UDA134X_FORMATS,
461 },
462 /* capture capabilities */
463 .capture = {
464 .stream_name = "Capture",
465 .channels_min = 1,
466 .channels_max = 2,
467 .rates = UDA134X_RATES,
468 .formats = UDA134X_FORMATS,
469 },
470 /* pcm operations */
Eric Miao6335d052009-03-03 09:41:00 +0800471 .ops = &uda134x_dai_ops,
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100472};
473EXPORT_SYMBOL(uda134x_dai);
474
475
476static int uda134x_soc_probe(struct platform_device *pdev)
477{
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;
482 int ret = -ENOMEM;
483 struct uda134x_platform_data *pd;
484
485 printk(KERN_INFO "UDA134X SoC Audio Codec\n");
486
487 if (!codec_setup_data) {
488 printk(KERN_ERR "UDA134X SoC codec: "
489 "missing L3 bitbang function\n");
490 return -ENODEV;
491 }
492
493 pd = codec_setup_data;
494 switch (pd->model) {
495 case UDA134X_UDA1340:
496 case UDA134X_UDA1341:
497 case UDA134X_UDA1344:
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400498 case UDA134X_UDA1345:
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100499 break;
500 default:
501 printk(KERN_ERR "UDA134X SoC codec: "
502 "unsupported model %d\n",
503 pd->model);
504 return -EINVAL;
505 }
506
Mark Brown6627a652009-01-23 22:55:23 +0000507 socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
508 if (socdev->card->codec == NULL)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100509 return ret;
510
Mark Brown6627a652009-01-23 22:55:23 +0000511 codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100512
513 uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
514 if (uda134x == NULL)
515 goto priv_err;
Mark Brownb2c812e2010-04-14 15:35:19 +0900516 snd_soc_codec_set_drvdata(codec, uda134x);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100517
518 codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
519 GFP_KERNEL);
520 if (codec->reg_cache == NULL)
521 goto reg_err;
522
523 mutex_init(&codec->mutex);
524
525 codec->reg_cache_size = sizeof(uda134x_reg);
526 codec->reg_cache_step = 1;
527
528 codec->name = "UDA134X";
529 codec->owner = THIS_MODULE;
530 codec->dai = &uda134x_dai;
531 codec->num_dai = 1;
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;
536#endif
537 INIT_LIST_HEAD(&codec->dapm_widgets);
538 INIT_LIST_HEAD(&codec->dapm_paths);
539
540 codec->control_data = codec_setup_data;
541
542 if (pd->power)
543 pd->power(1);
544
545 uda134x_reset(codec);
546
547 /* register pcms */
548 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
549 if (ret < 0) {
550 printk(KERN_ERR "UDA134X: failed to register pcms\n");
551 goto pcm_err;
552 }
553
Ian Molton3e8e1952009-01-09 00:23:21 +0000554 switch (pd->model) {
555 case UDA134X_UDA1340:
556 case UDA134X_UDA1344:
557 ret = snd_soc_add_controls(codec, uda1340_snd_controls,
558 ARRAY_SIZE(uda1340_snd_controls));
559 break;
560 case UDA134X_UDA1341:
561 ret = snd_soc_add_controls(codec, uda1341_snd_controls,
562 ARRAY_SIZE(uda1341_snd_controls));
563 break;
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400564 case UDA134X_UDA1345:
565 ret = snd_soc_add_controls(codec, uda1345_snd_controls,
566 ARRAY_SIZE(uda1345_snd_controls));
567 break;
Ian Molton3e8e1952009-01-09 00:23:21 +0000568 default:
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200569 printk(KERN_ERR "%s unknown codec type: %d",
Ian Molton3e8e1952009-01-09 00:23:21 +0000570 __func__, pd->model);
571 return -EINVAL;
572 }
573
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100574 if (ret < 0) {
575 printk(KERN_ERR "UDA134X: failed to register controls\n");
576 goto pcm_err;
577 }
578
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100579 return 0;
580
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100581pcm_err:
582 kfree(codec->reg_cache);
583reg_err:
Mark Brownb2c812e2010-04-14 15:35:19 +0900584 kfree(snd_soc_codec_get_drvdata(codec));
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100585priv_err:
586 kfree(codec);
587 return ret;
588}
589
590/* power down chip */
591static int uda134x_soc_remove(struct platform_device *pdev)
592{
593 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000594 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100595
596 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
597 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
598
599 snd_soc_free_pcms(socdev);
600 snd_soc_dapm_free(socdev);
601
Mark Brownb2c812e2010-04-14 15:35:19 +0900602 kfree(snd_soc_codec_get_drvdata(codec));
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100603 kfree(codec->reg_cache);
604 kfree(codec);
605
606 return 0;
607}
608
609#if defined(CONFIG_PM)
610static int uda134x_soc_suspend(struct platform_device *pdev,
611 pm_message_t state)
612{
613 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000614 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100615
616 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
617 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
618 return 0;
619}
620
621static int uda134x_soc_resume(struct platform_device *pdev)
622{
623 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000624 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100625
626 uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
627 uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
628 return 0;
629}
630#else
631#define uda134x_soc_suspend NULL
632#define uda134x_soc_resume NULL
633#endif /* CONFIG_PM */
634
635struct 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,
640};
641EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
642
Takashi Iwaic9b3a402008-12-10 07:47:22 +0100643static int __init uda134x_init(void)
Mark Brown64089b82008-12-08 19:17:58 +0000644{
645 return snd_soc_register_dai(&uda134x_dai);
646}
647module_init(uda134x_init);
648
649static void __exit uda134x_exit(void)
650{
651 snd_soc_unregister_dai(&uda134x_dai);
652}
653module_exit(uda134x_exit);
654
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100655MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
656MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
657MODULE_LICENSE("GPL");