blob: 52eada1f17fc761e656ca984e171459a9cfb822e [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
Christian Pellegrin1cad1de2008-11-15 08:58:16 +010031#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
32#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
33 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
34
35struct uda134x_priv {
36 int sysclk;
37 int dai_fmt;
38
39 struct snd_pcm_substream *master_substream;
40 struct snd_pcm_substream *slave_substream;
41};
42
43/* In-data addresses are hard-coded into the reg-cache values */
44static const char uda134x_reg[UDA134X_REGS_NUM] = {
45 /* Extended address registers */
46 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
47 /* Status, data regs */
48 0x00, 0x83, 0x00, 0x40, 0x80, 0x00,
49};
50
51/*
52 * The codec has no support for reading its registers except for peak level...
53 */
54static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec,
55 unsigned int reg)
56{
57 u8 *cache = codec->reg_cache;
58
59 if (reg >= UDA134X_REGS_NUM)
60 return -1;
61 return cache[reg];
62}
63
64/*
65 * Write the register cache
66 */
67static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec,
68 u8 reg, unsigned int value)
69{
70 u8 *cache = codec->reg_cache;
71
72 if (reg >= UDA134X_REGS_NUM)
73 return;
74 cache[reg] = value;
75}
76
77/*
78 * Write to the uda134x registers
79 *
80 */
81static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
82 unsigned int value)
83{
84 int ret;
85 u8 addr;
86 u8 data = value;
87 struct uda134x_platform_data *pd = codec->control_data;
88
89 pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value);
90
91 if (reg >= UDA134X_REGS_NUM) {
André Goddard Rosaaf901ca2009-11-14 13:09:05 -020092 printk(KERN_ERR "%s unknown register: reg: %u",
Christian Pellegrin1cad1de2008-11-15 08:58:16 +010093 __func__, reg);
94 return -EINVAL;
95 }
96
97 uda134x_write_reg_cache(codec, reg, value);
98
99 switch (reg) {
100 case UDA134X_STATUS0:
101 case UDA134X_STATUS1:
102 addr = UDA134X_STATUS_ADDR;
103 break;
104 case UDA134X_DATA000:
105 case UDA134X_DATA001:
106 case UDA134X_DATA010:
107 addr = UDA134X_DATA0_ADDR;
108 break;
109 case UDA134X_DATA1:
110 addr = UDA134X_DATA1_ADDR;
111 break;
112 default:
113 /* It's an extended address register */
114 addr = (reg | UDA134X_EXTADDR_PREFIX);
115
116 ret = l3_write(&pd->l3,
117 UDA134X_DATA0_ADDR, &addr, 1);
118 if (ret != 1)
119 return -EIO;
120
121 addr = UDA134X_DATA0_ADDR;
122 data = (value | UDA134X_EXTDATA_PREFIX);
123 break;
124 }
125
126 ret = l3_write(&pd->l3,
127 addr, &data, 1);
128 if (ret != 1)
129 return -EIO;
130
131 return 0;
132}
133
134static inline void uda134x_reset(struct snd_soc_codec *codec)
135{
136 u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
137 uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6));
138 msleep(1);
139 uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6));
140}
141
142static int uda134x_mute(struct snd_soc_dai *dai, int mute)
143{
144 struct snd_soc_codec *codec = dai->codec;
145 u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010);
146
147 pr_debug("%s mute: %d\n", __func__, mute);
148
149 if (mute)
150 mute_reg |= (1<<2);
151 else
152 mute_reg &= ~(1<<2);
153
Shine Liu0c093fb2009-08-17 18:52:01 +0800154 uda134x_write(codec, UDA134X_DATA010, mute_reg);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100155
156 return 0;
157}
158
Mark Browndee89c42008-11-18 22:11:38 +0000159static int uda134x_startup(struct snd_pcm_substream *substream,
160 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100161{
162 struct snd_soc_pcm_runtime *rtd = substream->private_data;
163 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000164 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900165 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100166 struct snd_pcm_runtime *master_runtime;
167
168 if (uda134x->master_substream) {
169 master_runtime = uda134x->master_substream->runtime;
170
171 pr_debug("%s constraining to %d bits at %d\n", __func__,
172 master_runtime->sample_bits,
173 master_runtime->rate);
174
175 snd_pcm_hw_constraint_minmax(substream->runtime,
176 SNDRV_PCM_HW_PARAM_RATE,
177 master_runtime->rate,
178 master_runtime->rate);
179
180 snd_pcm_hw_constraint_minmax(substream->runtime,
181 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
182 master_runtime->sample_bits,
183 master_runtime->sample_bits);
184
185 uda134x->slave_substream = substream;
186 } else
187 uda134x->master_substream = substream;
188
189 return 0;
190}
191
Mark Browndee89c42008-11-18 22:11:38 +0000192static void uda134x_shutdown(struct snd_pcm_substream *substream,
193 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100194{
195 struct snd_soc_pcm_runtime *rtd = substream->private_data;
196 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000197 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900198 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100199
200 if (uda134x->master_substream == substream)
201 uda134x->master_substream = uda134x->slave_substream;
202
203 uda134x->slave_substream = NULL;
204}
205
206static int uda134x_hw_params(struct snd_pcm_substream *substream,
Mark Browndee89c42008-11-18 22:11:38 +0000207 struct snd_pcm_hw_params *params,
208 struct snd_soc_dai *dai)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100209{
210 struct snd_soc_pcm_runtime *rtd = substream->private_data;
211 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000212 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900213 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100214 u8 hw_params;
215
216 if (substream == uda134x->slave_substream) {
217 pr_debug("%s ignoring hw_params for slave substream\n",
218 __func__);
219 return 0;
220 }
221
222 hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0);
223 hw_params &= STATUS0_SYSCLK_MASK;
224 hw_params &= STATUS0_DAIFMT_MASK;
225
226 pr_debug("%s sysclk: %d, rate:%d\n", __func__,
227 uda134x->sysclk, params_rate(params));
228
229 /* set SYSCLK / fs ratio */
230 switch (uda134x->sysclk / params_rate(params)) {
231 case 512:
232 break;
233 case 384:
234 hw_params |= (1<<4);
235 break;
236 case 256:
237 hw_params |= (1<<5);
238 break;
239 default:
240 printk(KERN_ERR "%s unsupported fs\n", __func__);
241 return -EINVAL;
242 }
243
244 pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__,
245 uda134x->dai_fmt, params_format(params));
246
247 /* set DAI format and word length */
248 switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
249 case SND_SOC_DAIFMT_I2S:
250 break;
251 case SND_SOC_DAIFMT_RIGHT_J:
252 switch (params_format(params)) {
253 case SNDRV_PCM_FORMAT_S16_LE:
254 hw_params |= (1<<1);
255 break;
256 case SNDRV_PCM_FORMAT_S18_3LE:
257 hw_params |= (1<<2);
258 break;
259 case SNDRV_PCM_FORMAT_S20_3LE:
260 hw_params |= ((1<<2) | (1<<1));
261 break;
262 default:
263 printk(KERN_ERR "%s unsupported format (right)\n",
264 __func__);
265 return -EINVAL;
266 }
267 break;
268 case SND_SOC_DAIFMT_LEFT_J:
269 hw_params |= (1<<3);
270 break;
271 default:
272 printk(KERN_ERR "%s unsupported format\n", __func__);
273 return -EINVAL;
274 }
275
276 uda134x_write(codec, UDA134X_STATUS0, hw_params);
277
278 return 0;
279}
280
281static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
282 int clk_id, unsigned int freq, int dir)
283{
284 struct snd_soc_codec *codec = codec_dai->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900285 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100286
Roel Kluin449bd542009-05-27 17:08:39 -0700287 pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100288 clk_id, freq, dir);
289
290 /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
291 because the codec is slave. Of course limitations of the clock
292 master (the IIS controller) apply.
293 We'll error out on set_hw_params if it's not OK */
294 if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
295 uda134x->sysclk = freq;
296 return 0;
297 }
298
299 printk(KERN_ERR "%s unsupported sysclk\n", __func__);
300 return -EINVAL;
301}
302
303static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
304 unsigned int fmt)
305{
306 struct snd_soc_codec *codec = codec_dai->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900307 struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100308
309 pr_debug("%s fmt: %08X\n", __func__, fmt);
310
311 /* codec supports only full slave mode */
312 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
313 printk(KERN_ERR "%s unsupported slave mode\n", __func__);
314 return -EINVAL;
315 }
316
317 /* no support for clock inversion */
318 if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
319 printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
320 return -EINVAL;
321 }
322
323 /* We can't setup DAI format here as it depends on the word bit num */
324 /* so let's just store the value for later */
325 uda134x->dai_fmt = fmt;
326
327 return 0;
328}
329
330static int uda134x_set_bias_level(struct snd_soc_codec *codec,
331 enum snd_soc_bias_level level)
332{
333 u8 reg;
334 struct uda134x_platform_data *pd = codec->control_data;
335 int i;
336 u8 *cache = codec->reg_cache;
337
338 pr_debug("%s bias level %d\n", __func__, level);
339
340 switch (level) {
341 case SND_SOC_BIAS_ON:
342 /* ADC, DAC on */
343 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
344 uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
345 break;
346 case SND_SOC_BIAS_PREPARE:
347 /* power on */
348 if (pd->power) {
349 pd->power(1);
350 /* Sync reg_cache with the hardware */
351 for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
352 codec->write(codec, i, *cache++);
353 }
354 break;
355 case SND_SOC_BIAS_STANDBY:
356 /* ADC, DAC power off */
357 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
358 uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
359 break;
360 case SND_SOC_BIAS_OFF:
361 /* power off */
362 if (pd->power)
363 pd->power(0);
364 break;
365 }
366 codec->bias_level = level;
367 return 0;
368}
369
370static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1",
371 "Minimum2", "Maximum"};
372static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
373static const char *uda134x_mixmode[] = {"Differential", "Analog1",
374 "Analog2", "Both"};
375
376static const struct soc_enum uda134x_mixer_enum[] = {
377SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting),
378SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph),
379SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode),
380};
381
382static const struct snd_kcontrol_new uda1341_snd_controls[] = {
383SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
384SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0),
385SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1),
386SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1),
387
388SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0),
389SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0),
390
391SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
392SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
393
394SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
395SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
396SOC_ENUM("Input Mux", uda134x_mixer_enum[2]),
397
398SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0),
399SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1),
400SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0),
401
402SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0),
403SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0),
404SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0),
405SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0),
406SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0),
407SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
408};
409
410static const struct snd_kcontrol_new uda1340_snd_controls[] = {
411SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
412
413SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0),
414SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0),
415
416SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]),
417SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
418
419SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
420};
421
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400422static const struct snd_kcontrol_new uda1345_snd_controls[] = {
423SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
424
425SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
426
427SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
428};
429
Eric Miao6335d052009-03-03 09:41:00 +0800430static struct snd_soc_dai_ops uda134x_dai_ops = {
431 .startup = uda134x_startup,
432 .shutdown = uda134x_shutdown,
433 .hw_params = uda134x_hw_params,
434 .digital_mute = uda134x_mute,
435 .set_sysclk = uda134x_set_dai_sysclk,
436 .set_fmt = uda134x_set_dai_fmt,
437};
438
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100439struct snd_soc_dai uda134x_dai = {
440 .name = "UDA134X",
441 /* playback capabilities */
442 .playback = {
443 .stream_name = "Playback",
444 .channels_min = 1,
445 .channels_max = 2,
446 .rates = UDA134X_RATES,
447 .formats = UDA134X_FORMATS,
448 },
449 /* capture capabilities */
450 .capture = {
451 .stream_name = "Capture",
452 .channels_min = 1,
453 .channels_max = 2,
454 .rates = UDA134X_RATES,
455 .formats = UDA134X_FORMATS,
456 },
457 /* pcm operations */
Eric Miao6335d052009-03-03 09:41:00 +0800458 .ops = &uda134x_dai_ops,
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100459};
460EXPORT_SYMBOL(uda134x_dai);
461
462
463static int uda134x_soc_probe(struct platform_device *pdev)
464{
465 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
466 struct snd_soc_codec *codec;
467 struct uda134x_priv *uda134x;
468 void *codec_setup_data = socdev->codec_data;
469 int ret = -ENOMEM;
470 struct uda134x_platform_data *pd;
471
472 printk(KERN_INFO "UDA134X SoC Audio Codec\n");
473
474 if (!codec_setup_data) {
475 printk(KERN_ERR "UDA134X SoC codec: "
476 "missing L3 bitbang function\n");
477 return -ENODEV;
478 }
479
480 pd = codec_setup_data;
481 switch (pd->model) {
482 case UDA134X_UDA1340:
483 case UDA134X_UDA1341:
484 case UDA134X_UDA1344:
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400485 case UDA134X_UDA1345:
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100486 break;
487 default:
488 printk(KERN_ERR "UDA134X SoC codec: "
489 "unsupported model %d\n",
490 pd->model);
491 return -EINVAL;
492 }
493
Mark Brown6627a652009-01-23 22:55:23 +0000494 socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
495 if (socdev->card->codec == NULL)
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100496 return ret;
497
Mark Brown6627a652009-01-23 22:55:23 +0000498 codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100499
500 uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
501 if (uda134x == NULL)
502 goto priv_err;
Mark Brownb2c812e2010-04-14 15:35:19 +0900503 snd_soc_codec_set_drvdata(codec, uda134x);
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100504
505 codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
506 GFP_KERNEL);
507 if (codec->reg_cache == NULL)
508 goto reg_err;
509
510 mutex_init(&codec->mutex);
511
512 codec->reg_cache_size = sizeof(uda134x_reg);
513 codec->reg_cache_step = 1;
514
515 codec->name = "UDA134X";
516 codec->owner = THIS_MODULE;
517 codec->dai = &uda134x_dai;
518 codec->num_dai = 1;
519 codec->read = uda134x_read_reg_cache;
520 codec->write = uda134x_write;
Vladimir Zapolskiycc3202f2010-06-24 17:38:50 +0400521
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100522 INIT_LIST_HEAD(&codec->dapm_widgets);
523 INIT_LIST_HEAD(&codec->dapm_paths);
524
525 codec->control_data = codec_setup_data;
526
527 if (pd->power)
528 pd->power(1);
529
530 uda134x_reset(codec);
531
Vladimir Zapolskiye4295b42010-06-24 17:38:51 +0400532 if (pd->is_powered_on_standby) {
533 codec->set_bias_level = NULL;
534 uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
535 } else {
536 codec->set_bias_level = uda134x_set_bias_level;
537 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
538 }
539
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100540 /* register pcms */
541 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
542 if (ret < 0) {
543 printk(KERN_ERR "UDA134X: failed to register pcms\n");
544 goto pcm_err;
545 }
546
Ian Molton3e8e1952009-01-09 00:23:21 +0000547 switch (pd->model) {
548 case UDA134X_UDA1340:
549 case UDA134X_UDA1344:
550 ret = snd_soc_add_controls(codec, uda1340_snd_controls,
551 ARRAY_SIZE(uda1340_snd_controls));
552 break;
553 case UDA134X_UDA1341:
554 ret = snd_soc_add_controls(codec, uda1341_snd_controls,
555 ARRAY_SIZE(uda1341_snd_controls));
556 break;
Vladimir Zapolskiyb28528a2010-04-26 14:56:57 +0400557 case UDA134X_UDA1345:
558 ret = snd_soc_add_controls(codec, uda1345_snd_controls,
559 ARRAY_SIZE(uda1345_snd_controls));
560 break;
Ian Molton3e8e1952009-01-09 00:23:21 +0000561 default:
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200562 printk(KERN_ERR "%s unknown codec type: %d",
Ian Molton3e8e1952009-01-09 00:23:21 +0000563 __func__, pd->model);
564 return -EINVAL;
565 }
566
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100567 if (ret < 0) {
568 printk(KERN_ERR "UDA134X: failed to register controls\n");
569 goto pcm_err;
570 }
571
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100572 return 0;
573
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100574pcm_err:
575 kfree(codec->reg_cache);
576reg_err:
Mark Brownb2c812e2010-04-14 15:35:19 +0900577 kfree(snd_soc_codec_get_drvdata(codec));
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100578priv_err:
579 kfree(codec);
580 return ret;
581}
582
583/* power down chip */
584static int uda134x_soc_remove(struct platform_device *pdev)
585{
586 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000587 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100588
589 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
590 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
591
592 snd_soc_free_pcms(socdev);
593 snd_soc_dapm_free(socdev);
594
Mark Brownb2c812e2010-04-14 15:35:19 +0900595 kfree(snd_soc_codec_get_drvdata(codec));
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100596 kfree(codec->reg_cache);
597 kfree(codec);
598
599 return 0;
600}
601
602#if defined(CONFIG_PM)
603static int uda134x_soc_suspend(struct platform_device *pdev,
604 pm_message_t state)
605{
606 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000607 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100608
609 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
610 uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
611 return 0;
612}
613
614static int uda134x_soc_resume(struct platform_device *pdev)
615{
616 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +0000617 struct snd_soc_codec *codec = socdev->card->codec;
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100618
619 uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
620 uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
621 return 0;
622}
623#else
624#define uda134x_soc_suspend NULL
625#define uda134x_soc_resume NULL
626#endif /* CONFIG_PM */
627
628struct snd_soc_codec_device soc_codec_dev_uda134x = {
629 .probe = uda134x_soc_probe,
630 .remove = uda134x_soc_remove,
631 .suspend = uda134x_soc_suspend,
632 .resume = uda134x_soc_resume,
633};
634EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
635
Takashi Iwaic9b3a402008-12-10 07:47:22 +0100636static int __init uda134x_init(void)
Mark Brown64089b82008-12-08 19:17:58 +0000637{
638 return snd_soc_register_dai(&uda134x_dai);
639}
640module_init(uda134x_init);
641
642static void __exit uda134x_exit(void)
643{
644 snd_soc_unregister_dai(&uda134x_dai);
645}
646module_exit(uda134x_exit);
647
Christian Pellegrin1cad1de2008-11-15 08:58:16 +0100648MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
649MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
650MODULE_LICENSE("GPL");