blob: eafa164a8f861d542c72cfde9c19653ddcb1e5ea [file] [log] [blame]
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001/*
2 * ALSA SoC TLV320AIC3X codec driver
3 *
Vladimir Barinovd6b52032008-09-29 23:14:11 +04004 * Author: Vladimir Barinov, <vbarinov@embeddedalley.com>
Vladimir Barinov44d0a872007-11-14 17:07:17 +01005 * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com>
6 *
7 * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Notes:
14 * The AIC3X is a driver for a low power stereo audio
15 * codecs aic31, aic32, aic33.
16 *
17 * It supports full aic33 codec functionality.
18 * The compatibility with aic32, aic31 is as follows:
19 * aic32 | aic31
20 * ---------------------------------------
21 * MONO_LOUT -> N/A | MONO_LOUT -> N/A
22 * | IN1L -> LINE1L
23 * | IN1R -> LINE1R
24 * | IN2L -> LINE2L
25 * | IN2R -> LINE2R
26 * | MIC3L/R -> N/A
27 * truncated internal functionality in
28 * accordance with documentation
29 * ---------------------------------------
30 *
31 * Hence the machine layer should disable unsupported inputs/outputs by
Liam Girdwooda5302182008-07-07 13:35:17 +010032 * snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc.
Vladimir Barinov44d0a872007-11-14 17:07:17 +010033 */
34
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/init.h>
38#include <linux/delay.h>
39#include <linux/pm.h>
40#include <linux/i2c.h>
Jarkko Nikula5193d622010-05-05 13:02:03 +030041#include <linux/gpio.h>
Jarkko Nikula07779fd2010-04-26 15:49:14 +030042#include <linux/regulator/consumer.h>
Vladimir Barinov44d0a872007-11-14 17:07:17 +010043#include <linux/platform_device.h>
Vladimir Barinov44d0a872007-11-14 17:07:17 +010044#include <sound/core.h>
45#include <sound/pcm.h>
46#include <sound/pcm_params.h>
47#include <sound/soc.h>
48#include <sound/soc-dapm.h>
49#include <sound/initval.h>
Jarkko Nikula7565fc32009-02-09 14:27:07 +020050#include <sound/tlv.h>
Jarkko Nikula5193d622010-05-05 13:02:03 +030051#include <sound/tlv320aic3x.h>
Vladimir Barinov44d0a872007-11-14 17:07:17 +010052
53#include "tlv320aic3x.h"
54
Jarkko Nikula07779fd2010-04-26 15:49:14 +030055#define AIC3X_NUM_SUPPLIES 4
56static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
57 "IOVDD", /* I/O Voltage */
58 "DVDD", /* Digital Core Voltage */
59 "AVDD", /* Analog DAC Voltage */
60 "DRVDD", /* ADC Analog and Output Driver Voltage */
61};
62
Vladimir Barinov44d0a872007-11-14 17:07:17 +010063/* codec private data */
64struct aic3x_priv {
Ben Dookscb3826f2009-08-20 22:50:41 +010065 struct snd_soc_codec codec;
Jarkko Nikula07779fd2010-04-26 15:49:14 +030066 struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
Vladimir Barinov44d0a872007-11-14 17:07:17 +010067 unsigned int sysclk;
68 int master;
Jarkko Nikula5193d622010-05-05 13:02:03 +030069 int gpio_reset;
Vladimir Barinov44d0a872007-11-14 17:07:17 +010070};
71
72/*
73 * AIC3X register cache
74 * We can't read the AIC3X register space when we are
75 * using 2 wire for device control, so we cache them instead.
76 * There is no point in caching the reset register
77 */
78static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
79 0x00, 0x00, 0x00, 0x10, /* 0 */
80 0x04, 0x00, 0x00, 0x00, /* 4 */
81 0x00, 0x00, 0x00, 0x01, /* 8 */
82 0x00, 0x00, 0x00, 0x80, /* 12 */
83 0x80, 0xff, 0xff, 0x78, /* 16 */
84 0x78, 0x78, 0x78, 0x78, /* 20 */
85 0x78, 0x00, 0x00, 0xfe, /* 24 */
86 0x00, 0x00, 0xfe, 0x00, /* 28 */
87 0x18, 0x18, 0x00, 0x00, /* 32 */
88 0x00, 0x00, 0x00, 0x00, /* 36 */
89 0x00, 0x00, 0x00, 0x80, /* 40 */
90 0x80, 0x00, 0x00, 0x00, /* 44 */
91 0x00, 0x00, 0x00, 0x04, /* 48 */
92 0x00, 0x00, 0x00, 0x00, /* 52 */
93 0x00, 0x00, 0x04, 0x00, /* 56 */
94 0x00, 0x00, 0x00, 0x00, /* 60 */
95 0x00, 0x04, 0x00, 0x00, /* 64 */
96 0x00, 0x00, 0x00, 0x00, /* 68 */
97 0x04, 0x00, 0x00, 0x00, /* 72 */
98 0x00, 0x00, 0x00, 0x00, /* 76 */
99 0x00, 0x00, 0x00, 0x00, /* 80 */
100 0x00, 0x00, 0x00, 0x00, /* 84 */
101 0x00, 0x00, 0x00, 0x00, /* 88 */
102 0x00, 0x00, 0x00, 0x00, /* 92 */
103 0x00, 0x00, 0x00, 0x00, /* 96 */
104 0x00, 0x00, 0x02, /* 100 */
105};
106
107/*
108 * read aic3x register cache
109 */
110static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
111 unsigned int reg)
112{
113 u8 *cache = codec->reg_cache;
114 if (reg >= AIC3X_CACHEREGNUM)
115 return -1;
116 return cache[reg];
117}
118
119/*
120 * write aic3x register cache
121 */
122static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec,
123 u8 reg, u8 value)
124{
125 u8 *cache = codec->reg_cache;
126 if (reg >= AIC3X_CACHEREGNUM)
127 return;
128 cache[reg] = value;
129}
130
131/*
132 * write to the aic3x register space
133 */
134static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
135 unsigned int value)
136{
137 u8 data[2];
138
139 /* data is
140 * D15..D8 aic3x register offset
141 * D7...D0 register data
142 */
143 data[0] = reg & 0xff;
144 data[1] = value & 0xff;
145
146 aic3x_write_reg_cache(codec, data[0], data[1]);
147 if (codec->hw_write(codec->control_data, data, 2) == 2)
148 return 0;
149 else
150 return -EIO;
151}
152
Daniel Mack54e7e612008-04-30 16:20:52 +0200153/*
154 * read from the aic3x register space
155 */
156static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
157 u8 *value)
158{
159 *value = reg & 0xff;
Mark Brown5f345342009-07-05 17:35:28 +0100160
161 value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]);
Daniel Mack54e7e612008-04-30 16:20:52 +0200162
163 aic3x_write_reg_cache(codec, reg, *value);
164 return 0;
165}
166
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100167#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
168{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
169 .info = snd_soc_info_volsw, \
170 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \
171 .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) }
172
173/*
174 * All input lines are connected when !0xf and disconnected with 0xf bit field,
175 * so we have to use specific dapm_put call for input mixer
176 */
177static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
178 struct snd_ctl_elem_value *ucontrol)
179{
180 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
Eero Nurkkala4453dba2009-02-06 12:01:04 +0200181 struct soc_mixer_control *mc =
182 (struct soc_mixer_control *)kcontrol->private_value;
183 unsigned int reg = mc->reg;
184 unsigned int shift = mc->shift;
185 int max = mc->max;
186 unsigned int mask = (1 << fls(max)) - 1;
187 unsigned int invert = mc->invert;
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100188 unsigned short val, val_mask;
189 int ret;
190 struct snd_soc_dapm_path *path;
191 int found = 0;
192
193 val = (ucontrol->value.integer.value[0] & mask);
194
195 mask = 0xf;
196 if (val)
197 val = mask;
198
199 if (invert)
200 val = mask - val;
201 val_mask = mask << shift;
202 val = val << shift;
203
204 mutex_lock(&widget->codec->mutex);
205
206 if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
207 /* find dapm widget path assoc with kcontrol */
208 list_for_each_entry(path, &widget->codec->dapm_paths, list) {
209 if (path->kcontrol != kcontrol)
210 continue;
211
212 /* found, now check type */
213 found = 1;
214 if (val)
215 /* new connection */
216 path->connect = invert ? 0 : 1;
217 else
218 /* old connection must be powered down */
219 path->connect = invert ? 1 : 0;
220 break;
221 }
222
223 if (found)
Liam Girdwooda5302182008-07-07 13:35:17 +0100224 snd_soc_dapm_sync(widget->codec);
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100225 }
226
227 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
228
229 mutex_unlock(&widget->codec->mutex);
230 return ret;
231}
232
233static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
234static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
235static const char *aic3x_left_hpcom_mux[] =
236 { "differential of HPLOUT", "constant VCM", "single-ended" };
237static const char *aic3x_right_hpcom_mux[] =
238 { "differential of HPROUT", "constant VCM", "single-ended",
239 "differential of HPLCOM", "external feedback" };
240static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" };
Jarkko Nikula4d20f702008-06-27 14:07:57 +0300241static const char *aic3x_adc_hpf[] =
242 { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" };
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100243
244#define LDAC_ENUM 0
245#define RDAC_ENUM 1
246#define LHPCOM_ENUM 2
247#define RHPCOM_ENUM 3
248#define LINE1L_ENUM 4
249#define LINE1R_ENUM 5
250#define LINE2L_ENUM 6
251#define LINE2R_ENUM 7
Jarkko Nikula4d20f702008-06-27 14:07:57 +0300252#define ADC_HPF_ENUM 8
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100253
254static const struct soc_enum aic3x_enum[] = {
255 SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux),
256 SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux),
257 SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux),
258 SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux),
259 SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
260 SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
261 SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
262 SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
Jarkko Nikula4d20f702008-06-27 14:07:57 +0300263 SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100264};
265
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200266/*
267 * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
268 */
269static DECLARE_TLV_DB_SCALE(dac_tlv, -6350, 50, 0);
270/* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */
271static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0);
272/*
273 * Output stage volumes. From -78.3 to 0 dB. Muted below -78.3 dB.
274 * Step size is approximately 0.5 dB over most of the scale but increasing
275 * near the very low levels.
276 * Define dB scale so that it is mostly correct for range about -55 to 0 dB
277 * but having increasing dB difference below that (and where it doesn't count
278 * so much). This setting shows -50 dB (actual is -50.3 dB) for register
279 * value 100 and -58.5 dB (actual is -78.3 dB) for register value 117.
280 */
281static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1);
282
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100283static const struct snd_kcontrol_new aic3x_snd_controls[] = {
284 /* Output */
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200285 SOC_DOUBLE_R_TLV("PCM Playback Volume",
286 LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100287
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200288 SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
289 DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
290 0, 118, 1, output_stage_tlv),
Daniel Mack28a1d862008-12-05 17:31:00 +0100291 SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
292 SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200293 SOC_DOUBLE_R_TLV("LineL DAC Playback Volume",
294 DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL,
295 0, 118, 1, output_stage_tlv),
296 SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume",
297 PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
298 SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume",
299 PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
300 SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume",
301 LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL,
302 0, 118, 1, output_stage_tlv),
303 SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume",
304 LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL,
305 0, 118, 1, output_stage_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100306
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200307 SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
308 DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
309 0, 118, 1, output_stage_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100310 SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200311 SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
312 PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
313 0, 118, 1, output_stage_tlv),
314 SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume",
315 LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
316 0, 118, 1, output_stage_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100317
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200318 SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
319 DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
320 0, 118, 1, output_stage_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100321 SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
322 0x01, 0),
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200323 SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
324 PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
325 0, 118, 1, output_stage_tlv),
326 SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume",
327 PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
328 SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume",
329 PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
330 SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume",
331 LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
332 0, 118, 1, output_stage_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100333
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200334 SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
335 DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
336 0, 118, 1, output_stage_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100337 SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
338 0x01, 0),
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200339 SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
340 PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
341 SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume",
342 PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
343 SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume",
344 LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
345 0, 118, 1, output_stage_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100346
347 /*
348 * Note: enable Automatic input Gain Controller with care. It can
349 * adjust PGA to max value when ADC is on and will never go back.
350 */
351 SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
352
353 /* Input */
Jarkko Nikula7565fc32009-02-09 14:27:07 +0200354 SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL,
355 0, 119, 0, adc_tlv),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100356 SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
Jarkko Nikula4d20f702008-06-27 14:07:57 +0300357
358 SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100359};
360
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100361/* Left DAC Mux */
362static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
363SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
364
365/* Right DAC Mux */
366static const struct snd_kcontrol_new aic3x_right_dac_mux_controls =
367SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]);
368
369/* Left HPCOM Mux */
370static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls =
371SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]);
372
373/* Right HPCOM Mux */
374static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
375SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
376
377/* Left DAC_L1 Mixer */
378static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
Daniel Mack54f01912008-11-26 17:47:36 +0100379 SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
380 SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100381 SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
382 SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
383 SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
384};
385
386/* Right DAC_R1 Mixer */
387static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
Daniel Mack54f01912008-11-26 17:47:36 +0100388 SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
389 SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100390 SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
391 SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
392 SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
393};
394
395/* Left PGA Mixer */
396static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = {
397 SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
Daniel Mack54f01912008-11-26 17:47:36 +0100398 SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100399 SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1),
400 SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
Daniel Mack54f01912008-11-26 17:47:36 +0100401 SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100402};
403
404/* Right PGA Mixer */
405static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
406 SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
Daniel Mack54f01912008-11-26 17:47:36 +0100407 SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100408 SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1),
Daniel Mack54f01912008-11-26 17:47:36 +0100409 SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100410 SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
411};
412
413/* Left Line1 Mux */
414static const struct snd_kcontrol_new aic3x_left_line1_mux_controls =
415SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]);
416
417/* Right Line1 Mux */
418static const struct snd_kcontrol_new aic3x_right_line1_mux_controls =
419SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]);
420
421/* Left Line2 Mux */
422static const struct snd_kcontrol_new aic3x_left_line2_mux_controls =
423SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]);
424
425/* Right Line2 Mux */
426static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
427SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
428
429/* Left PGA Bypass Mixer */
430static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
Daniel Mack54f01912008-11-26 17:47:36 +0100431 SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
432 SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100433 SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
Daniel Mack54f01912008-11-26 17:47:36 +0100434 SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
435 SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
436 SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
437 SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100438};
439
440/* Right PGA Bypass Mixer */
441static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
Daniel Mack54f01912008-11-26 17:47:36 +0100442 SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
443 SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100444 SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
Daniel Mack54f01912008-11-26 17:47:36 +0100445 SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
446 SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
447 SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
448 SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100449};
450
451/* Left Line2 Bypass Mixer */
452static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
Daniel Mack54f01912008-11-26 17:47:36 +0100453 SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
454 SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100455 SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
456 SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
Daniel Mack54f01912008-11-26 17:47:36 +0100457 SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100458};
459
460/* Right Line2 Bypass Mixer */
461static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
Daniel Mack54f01912008-11-26 17:47:36 +0100462 SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
463 SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100464 SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
465 SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
Daniel Mack54f01912008-11-26 17:47:36 +0100466 SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100467};
468
469static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
470 /* Left DAC to Left Outputs */
471 SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
472 SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
473 &aic3x_left_dac_mux_controls),
474 SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0,
475 &aic3x_left_dac_mixer_controls[0],
476 ARRAY_SIZE(aic3x_left_dac_mixer_controls)),
477 SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
478 &aic3x_left_hpcom_mux_controls),
479 SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
480 SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0),
481 SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0),
482
483 /* Right DAC to Right Outputs */
484 SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
485 SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
486 &aic3x_right_dac_mux_controls),
487 SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0,
488 &aic3x_right_dac_mixer_controls[0],
489 ARRAY_SIZE(aic3x_right_dac_mixer_controls)),
490 SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
491 &aic3x_right_hpcom_mux_controls),
492 SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
493 SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
494 SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
495
496 /* Mono Output */
497 SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
498
Daniel Mack54f01912008-11-26 17:47:36 +0100499 /* Inputs to Left ADC */
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100500 SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
501 SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
502 &aic3x_left_pga_mixer_controls[0],
503 ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
504 SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
505 &aic3x_left_line1_mux_controls),
Daniel Mack54f01912008-11-26 17:47:36 +0100506 SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
507 &aic3x_left_line1_mux_controls),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100508 SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
509 &aic3x_left_line2_mux_controls),
510
Daniel Mack54f01912008-11-26 17:47:36 +0100511 /* Inputs to Right ADC */
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100512 SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
513 LINE1R_2_RADC_CTRL, 2, 0),
514 SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
515 &aic3x_right_pga_mixer_controls[0],
516 ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
Daniel Mack54f01912008-11-26 17:47:36 +0100517 SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
518 &aic3x_right_line1_mux_controls),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100519 SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
520 &aic3x_right_line1_mux_controls),
521 SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
522 &aic3x_right_line2_mux_controls),
523
Jarkko Nikulaee15ffd2008-06-25 14:58:46 +0300524 /*
525 * Not a real mic bias widget but similar function. This is for dynamic
526 * control of GPIO1 digital mic modulator clock output function when
527 * using digital mic.
528 */
529 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk",
530 AIC3X_GPIO1_REG, 4, 0xf,
531 AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK,
532 AIC3X_GPIO1_FUNC_DISABLED),
533
534 /*
535 * Also similar function like mic bias. Selects digital mic with
536 * configurable oversampling rate instead of ADC converter.
537 */
538 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128",
539 AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0),
540 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64",
541 AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0),
542 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32",
543 AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
544
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100545 /* Mic Bias */
Jarkko Nikula0bd72a32008-06-25 14:42:08 +0300546 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V",
547 MICBIAS_CTRL, 6, 3, 1, 0),
548 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V",
549 MICBIAS_CTRL, 6, 3, 2, 0),
550 SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
551 MICBIAS_CTRL, 6, 3, 3, 0),
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100552
553 /* Left PGA to Left Output bypass */
554 SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
555 &aic3x_left_pga_bp_mixer_controls[0],
556 ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)),
557
558 /* Right PGA to Right Output bypass */
559 SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
560 &aic3x_right_pga_bp_mixer_controls[0],
561 ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)),
562
563 /* Left Line2 to Left Output bypass */
564 SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
565 &aic3x_left_line2_bp_mixer_controls[0],
566 ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)),
567
568 /* Right Line2 to Right Output bypass */
569 SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
570 &aic3x_right_line2_bp_mixer_controls[0],
571 ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)),
572
573 SND_SOC_DAPM_OUTPUT("LLOUT"),
574 SND_SOC_DAPM_OUTPUT("RLOUT"),
575 SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
576 SND_SOC_DAPM_OUTPUT("HPLOUT"),
577 SND_SOC_DAPM_OUTPUT("HPROUT"),
578 SND_SOC_DAPM_OUTPUT("HPLCOM"),
579 SND_SOC_DAPM_OUTPUT("HPRCOM"),
580
581 SND_SOC_DAPM_INPUT("MIC3L"),
582 SND_SOC_DAPM_INPUT("MIC3R"),
583 SND_SOC_DAPM_INPUT("LINE1L"),
584 SND_SOC_DAPM_INPUT("LINE1R"),
585 SND_SOC_DAPM_INPUT("LINE2L"),
586 SND_SOC_DAPM_INPUT("LINE2R"),
587};
588
Mark Brownd0cc0d32008-05-13 14:55:22 +0200589static const struct snd_soc_dapm_route intercon[] = {
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100590 /* Left Output */
591 {"Left DAC Mux", "DAC_L1", "Left DAC"},
592 {"Left DAC Mux", "DAC_L2", "Left DAC"},
593 {"Left DAC Mux", "DAC_L3", "Left DAC"},
594
Daniel Mack54f01912008-11-26 17:47:36 +0100595 {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"},
596 {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100597 {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
598 {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
599 {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
600 {"Left Line Out", NULL, "Left DAC Mux"},
601 {"Left HP Out", NULL, "Left DAC Mux"},
602
603 {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"},
604 {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"},
605 {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"},
606
607 {"Left Line Out", NULL, "Left DAC_L1 Mixer"},
608 {"Mono Out", NULL, "Left DAC_L1 Mixer"},
609 {"Left HP Out", NULL, "Left DAC_L1 Mixer"},
610 {"Left HP Com", NULL, "Left HPCOM Mux"},
611
612 {"LLOUT", NULL, "Left Line Out"},
613 {"LLOUT", NULL, "Left Line Out"},
614 {"HPLOUT", NULL, "Left HP Out"},
615 {"HPLCOM", NULL, "Left HP Com"},
616
617 /* Right Output */
618 {"Right DAC Mux", "DAC_R1", "Right DAC"},
619 {"Right DAC Mux", "DAC_R2", "Right DAC"},
620 {"Right DAC Mux", "DAC_R3", "Right DAC"},
621
Daniel Mack54f01912008-11-26 17:47:36 +0100622 {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"},
623 {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100624 {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
625 {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
626 {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
627 {"Right Line Out", NULL, "Right DAC Mux"},
628 {"Right HP Out", NULL, "Right DAC Mux"},
629
630 {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"},
631 {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"},
632 {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"},
633 {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"},
634 {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"},
635
636 {"Right Line Out", NULL, "Right DAC_R1 Mixer"},
637 {"Mono Out", NULL, "Right DAC_R1 Mixer"},
638 {"Right HP Out", NULL, "Right DAC_R1 Mixer"},
639 {"Right HP Com", NULL, "Right HPCOM Mux"},
640
641 {"RLOUT", NULL, "Right Line Out"},
642 {"RLOUT", NULL, "Right Line Out"},
643 {"HPROUT", NULL, "Right HP Out"},
644 {"HPRCOM", NULL, "Right HP Com"},
645
646 /* Mono Output */
Jarkko Nikula5b006132008-05-09 15:05:41 +0200647 {"MONO_LOUT", NULL, "Mono Out"},
648 {"MONO_LOUT", NULL, "Mono Out"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100649
650 /* Left Input */
651 {"Left Line1L Mux", "single-ended", "LINE1L"},
652 {"Left Line1L Mux", "differential", "LINE1L"},
653
654 {"Left Line2L Mux", "single-ended", "LINE2L"},
655 {"Left Line2L Mux", "differential", "LINE2L"},
656
657 {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
Daniel Mack54f01912008-11-26 17:47:36 +0100658 {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100659 {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
660 {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
Daniel Mack54f01912008-11-26 17:47:36 +0100661 {"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100662
663 {"Left ADC", NULL, "Left PGA Mixer"},
Jarkko Nikulaee15ffd2008-06-25 14:58:46 +0300664 {"Left ADC", NULL, "GPIO1 dmic modclk"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100665
666 /* Right Input */
667 {"Right Line1R Mux", "single-ended", "LINE1R"},
668 {"Right Line1R Mux", "differential", "LINE1R"},
669
670 {"Right Line2R Mux", "single-ended", "LINE2R"},
671 {"Right Line2R Mux", "differential", "LINE2R"},
672
Daniel Mack54f01912008-11-26 17:47:36 +0100673 {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100674 {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
675 {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
Daniel Mack54f01912008-11-26 17:47:36 +0100676 {"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100677 {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
678
679 {"Right ADC", NULL, "Right PGA Mixer"},
Jarkko Nikulaee15ffd2008-06-25 14:58:46 +0300680 {"Right ADC", NULL, "GPIO1 dmic modclk"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100681
682 /* Left PGA Bypass */
Daniel Mack54f01912008-11-26 17:47:36 +0100683 {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"},
684 {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100685 {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
Daniel Mack54f01912008-11-26 17:47:36 +0100686 {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"},
687 {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"},
688 {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"},
689 {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100690
691 {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
692 {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
693 {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"},
694
695 {"Left Line Out", NULL, "Left PGA Bypass Mixer"},
696 {"Mono Out", NULL, "Left PGA Bypass Mixer"},
697 {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
698
699 /* Right PGA Bypass */
Daniel Mack54f01912008-11-26 17:47:36 +0100700 {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"},
701 {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100702 {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
Daniel Mack54f01912008-11-26 17:47:36 +0100703 {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"},
704 {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"},
705 {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"},
706 {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100707
708 {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
709 {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
710 {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"},
711 {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"},
712 {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"},
713
714 {"Right Line Out", NULL, "Right PGA Bypass Mixer"},
715 {"Mono Out", NULL, "Right PGA Bypass Mixer"},
716 {"Right HP Out", NULL, "Right PGA Bypass Mixer"},
717
718 /* Left Line2 Bypass */
Daniel Mack54f01912008-11-26 17:47:36 +0100719 {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"},
720 {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100721 {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
722 {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
Daniel Mack54f01912008-11-26 17:47:36 +0100723 {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100724
725 {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
726 {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
727 {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"},
728
729 {"Left Line Out", NULL, "Left Line2 Bypass Mixer"},
730 {"Mono Out", NULL, "Left Line2 Bypass Mixer"},
731 {"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
732
733 /* Right Line2 Bypass */
Daniel Mack54f01912008-11-26 17:47:36 +0100734 {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"},
735 {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100736 {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
737 {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
Daniel Mack54f01912008-11-26 17:47:36 +0100738 {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100739
740 {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
741 {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
742 {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"},
743 {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"},
744 {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"},
745
746 {"Right Line Out", NULL, "Right Line2 Bypass Mixer"},
747 {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
748 {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
Jarkko Nikulaee15ffd2008-06-25 14:58:46 +0300749
750 /*
751 * Logical path between digital mic enable and GPIO1 modulator clock
752 * output function
753 */
754 {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
755 {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
756 {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100757};
758
759static int aic3x_add_widgets(struct snd_soc_codec *codec)
760{
Mark Brownd0cc0d32008-05-13 14:55:22 +0200761 snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
762 ARRAY_SIZE(aic3x_dapm_widgets));
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100763
764 /* set up audio path interconnects */
Mark Brownd0cc0d32008-05-13 14:55:22 +0200765 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100766
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100767 return 0;
768}
769
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100770static int aic3x_hw_params(struct snd_pcm_substream *substream,
Mark Browndee89c42008-11-18 22:11:38 +0000771 struct snd_pcm_hw_params *params,
772 struct snd_soc_dai *dai)
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100773{
774 struct snd_soc_pcm_runtime *rtd = substream->private_data;
775 struct snd_soc_device *socdev = rtd->socdev;
Mark Brown6627a652009-01-23 22:55:23 +0000776 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900777 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200778 int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
Peter Meerwald255173b2009-12-14 14:44:56 +0100779 u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
780 u16 d, pll_d = 1;
Chaithrika U S06c71282009-07-22 07:45:04 -0400781 u8 reg;
Peter Meerwald255173b2009-12-14 14:44:56 +0100782 int clk;
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100783
784 /* select data word length */
785 data =
786 aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
787 switch (params_format(params)) {
788 case SNDRV_PCM_FORMAT_S16_LE:
789 break;
790 case SNDRV_PCM_FORMAT_S20_3LE:
791 data |= (0x01 << 4);
792 break;
793 case SNDRV_PCM_FORMAT_S24_LE:
794 data |= (0x02 << 4);
795 break;
796 case SNDRV_PCM_FORMAT_S32_LE:
797 data |= (0x03 << 4);
798 break;
799 }
800 aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
801
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200802 /* Fsref can be 44100 or 48000 */
803 fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
804
805 /* Try to find a value for Q which allows us to bypass the PLL and
806 * generate CODEC_CLK directly. */
807 for (pll_q = 2; pll_q < 18; pll_q++)
808 if (aic3x->sysclk / (128 * pll_q) == fsref) {
809 bypass_pll = 1;
810 break;
811 }
812
813 if (bypass_pll) {
814 pll_q &= 0xf;
815 aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
816 aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
Chaithrika U S06c71282009-07-22 07:45:04 -0400817 /* disable PLL if it is bypassed */
818 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
819 aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
820
821 } else {
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200822 aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
Chaithrika U S06c71282009-07-22 07:45:04 -0400823 /* enable PLL when it is used */
824 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
825 aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
826 }
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200827
828 /* Route Left DAC to left channel input and
829 * right DAC to right channel input */
830 data = (LDAC2LCH | RDAC2RCH);
831 data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
832 if (params_rate(params) >= 64000)
833 data |= DUAL_RATE_MODE;
834 aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
835
836 /* codec sample rate select */
837 data = (fsref * 20) / params_rate(params);
838 if (params_rate(params) < 64000)
839 data /= 2;
840 data /= 5;
841 data -= 2;
842 data |= (data << 4);
843 aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
844
845 if (bypass_pll)
846 return 0;
847
Peter Meerwald255173b2009-12-14 14:44:56 +0100848 /* Use PLL, compute apropriate setup for j, d, r and p, the closest
849 * one wins the game. Try with d==0 first, next with d!=0.
850 * Constraints for j are according to the datasheet.
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200851 * The sysclk is divided by 1000 to prevent integer overflows.
852 */
Peter Meerwald255173b2009-12-14 14:44:56 +0100853
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200854 codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000);
855
856 for (r = 1; r <= 16; r++)
857 for (p = 1; p <= 8; p++) {
Peter Meerwald255173b2009-12-14 14:44:56 +0100858 for (j = 4; j <= 55; j++) {
859 /* This is actually 1000*((j+(d/10000))*r)/p
860 * The term had to be converted to get
861 * rid of the division by 10000; d = 0 here
862 */
Mark Brown5baf8312010-01-02 13:13:42 +0000863 int tmp_clk = (1000 * j * r) / p;
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200864
Peter Meerwald255173b2009-12-14 14:44:56 +0100865 /* Check whether this values get closer than
866 * the best ones we had before
867 */
Mark Brown5baf8312010-01-02 13:13:42 +0000868 if (abs(codec_clk - tmp_clk) <
Peter Meerwald255173b2009-12-14 14:44:56 +0100869 abs(codec_clk - last_clk)) {
870 pll_j = j; pll_d = 0;
871 pll_r = r; pll_p = p;
Mark Brown5baf8312010-01-02 13:13:42 +0000872 last_clk = tmp_clk;
Peter Meerwald255173b2009-12-14 14:44:56 +0100873 }
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200874
Peter Meerwald255173b2009-12-14 14:44:56 +0100875 /* Early exit for exact matches */
Mark Brown5baf8312010-01-02 13:13:42 +0000876 if (tmp_clk == codec_clk)
Peter Meerwald255173b2009-12-14 14:44:56 +0100877 goto found;
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200878 }
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200879 }
880
Peter Meerwald255173b2009-12-14 14:44:56 +0100881 /* try with d != 0 */
882 for (p = 1; p <= 8; p++) {
883 j = codec_clk * p / 1000;
884
885 if (j < 4 || j > 11)
886 continue;
887
888 /* do not use codec_clk here since we'd loose precision */
889 d = ((2048 * p * fsref) - j * aic3x->sysclk)
890 * 100 / (aic3x->sysclk/100);
891
892 clk = (10000 * j + d) / (10 * p);
893
894 /* check whether this values get closer than the best
895 * ones we had before */
896 if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
897 pll_j = j; pll_d = d; pll_r = 1; pll_p = p;
898 last_clk = clk;
899 }
900
901 /* Early exit for exact matches */
902 if (clk == codec_clk)
903 goto found;
904 }
905
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200906 if (last_clk == 0) {
907 printk(KERN_ERR "%s(): unable to setup PLL\n", __func__);
908 return -EINVAL;
909 }
910
Peter Meerwald255173b2009-12-14 14:44:56 +0100911found:
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200912 data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
913 aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
914 aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
915 aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
916 aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT);
917 aic3x_write(codec, AIC3X_PLL_PROGD_REG,
918 (pll_d & 0x3F) << PLLD_LSB_SHIFT);
919
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100920 return 0;
921}
922
Liam Girdwoode550e172008-07-07 16:07:52 +0100923static int aic3x_mute(struct snd_soc_dai *dai, int mute)
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100924{
925 struct snd_soc_codec *codec = dai->codec;
926 u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
927 u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON;
928
929 if (mute) {
930 aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
931 aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
932 } else {
933 aic3x_write(codec, LDAC_VOL, ldac_reg);
934 aic3x_write(codec, RDAC_VOL, rdac_reg);
935 }
936
937 return 0;
938}
939
Liam Girdwoode550e172008-07-07 16:07:52 +0100940static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100941 int clk_id, unsigned int freq, int dir)
942{
943 struct snd_soc_codec *codec = codec_dai->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900944 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100945
Daniel Mack4f9c16c2008-04-30 16:20:19 +0200946 aic3x->sysclk = freq;
947 return 0;
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100948}
949
Liam Girdwoode550e172008-07-07 16:07:52 +0100950static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100951 unsigned int fmt)
952{
953 struct snd_soc_codec *codec = codec_dai->codec;
Mark Brownb2c812e2010-04-14 15:35:19 +0900954 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
Jarkko Nikula81971a12008-06-25 14:58:45 +0300955 u8 iface_areg, iface_breg;
Troy Kiskya24f4f62008-12-19 13:05:22 -0700956 int delay = 0;
Jarkko Nikula81971a12008-06-25 14:58:45 +0300957
958 iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
959 iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100960
961 /* set master/slave audio interface */
962 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
963 case SND_SOC_DAIFMT_CBM_CFM:
964 aic3x->master = 1;
965 iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
966 break;
967 case SND_SOC_DAIFMT_CBS_CFS:
968 aic3x->master = 0;
969 break;
970 default:
971 return -EINVAL;
972 }
973
Jarkko Nikula4b7d2832008-10-23 14:27:03 +0300974 /*
975 * match both interface format and signal polarities since they
976 * are fixed
977 */
978 switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
979 SND_SOC_DAIFMT_INV_MASK)) {
980 case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100981 break;
Troy Kiskya24f4f62008-12-19 13:05:22 -0700982 case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
983 delay = 1;
Jarkko Nikula4b7d2832008-10-23 14:27:03 +0300984 case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100985 iface_breg |= (0x01 << 6);
986 break;
Jarkko Nikula4b7d2832008-10-23 14:27:03 +0300987 case (SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_NB_NF):
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100988 iface_breg |= (0x02 << 6);
989 break;
Jarkko Nikula4b7d2832008-10-23 14:27:03 +0300990 case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF):
Vladimir Barinov44d0a872007-11-14 17:07:17 +0100991 iface_breg |= (0x03 << 6);
992 break;
993 default:
994 return -EINVAL;
995 }
996
997 /* set iface */
998 aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
999 aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
Troy Kiskya24f4f62008-12-19 13:05:22 -07001000 aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001001
1002 return 0;
1003}
1004
Mark Brown0be98982008-05-19 12:31:28 +02001005static int aic3x_set_bias_level(struct snd_soc_codec *codec,
1006 enum snd_soc_bias_level level)
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001007{
Mark Brownb2c812e2010-04-14 15:35:19 +09001008 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001009 u8 reg;
1010
Mark Brown0be98982008-05-19 12:31:28 +02001011 switch (level) {
1012 case SND_SOC_BIAS_ON:
Jarkko Nikuladb138022010-04-26 15:49:13 +03001013 break;
1014 case SND_SOC_BIAS_PREPARE:
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001015 if (aic3x->master) {
1016 /* enable pll */
1017 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
1018 aic3x_write(codec, AIC3X_PLL_PROGA_REG,
1019 reg | PLL_ENABLE);
1020 }
1021 break;
Mark Brown0be98982008-05-19 12:31:28 +02001022 case SND_SOC_BIAS_STANDBY:
Jarkko Nikuladb138022010-04-26 15:49:13 +03001023 /* fall through and disable pll */
Mark Brown0be98982008-05-19 12:31:28 +02001024 case SND_SOC_BIAS_OFF:
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001025 if (aic3x->master) {
1026 /* disable pll */
1027 reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
1028 aic3x_write(codec, AIC3X_PLL_PROGA_REG,
1029 reg & ~PLL_ENABLE);
1030 }
1031 break;
1032 }
Mark Brown0be98982008-05-19 12:31:28 +02001033 codec->bias_level = level;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001034
1035 return 0;
1036}
1037
Daniel Mack54e7e612008-04-30 16:20:52 +02001038void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state)
1039{
1040 u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
1041 u8 bit = gpio ? 3: 0;
1042 u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit);
1043 aic3x_write(codec, reg, val | (!!state << bit));
1044}
1045EXPORT_SYMBOL_GPL(aic3x_set_gpio);
1046
1047int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio)
1048{
1049 u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
1050 u8 val, bit = gpio ? 2: 1;
1051
1052 aic3x_read(codec, reg, &val);
1053 return (val >> bit) & 1;
1054}
1055EXPORT_SYMBOL_GPL(aic3x_get_gpio);
1056
Daniel Mack6f2a9742008-12-03 11:44:17 +01001057void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
1058 int headset_debounce, int button_debounce)
1059{
1060 u8 val;
1061
1062 val = ((detect & AIC3X_HEADSET_DETECT_MASK)
1063 << AIC3X_HEADSET_DETECT_SHIFT) |
1064 ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK)
1065 << AIC3X_HEADSET_DEBOUNCE_SHIFT) |
1066 ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK)
1067 << AIC3X_BUTTON_DEBOUNCE_SHIFT);
1068
1069 if (detect & AIC3X_HEADSET_DETECT_MASK)
1070 val |= AIC3X_HEADSET_DETECT_ENABLED;
1071
1072 aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
1073}
1074EXPORT_SYMBOL_GPL(aic3x_set_headset_detection);
1075
Daniel Mack54e7e612008-04-30 16:20:52 +02001076int aic3x_headset_detected(struct snd_soc_codec *codec)
1077{
1078 u8 val;
Daniel Mack6f2a9742008-12-03 11:44:17 +01001079 aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
1080 return (val >> 4) & 1;
Daniel Mack54e7e612008-04-30 16:20:52 +02001081}
1082EXPORT_SYMBOL_GPL(aic3x_headset_detected);
1083
Daniel Mack6f2a9742008-12-03 11:44:17 +01001084int aic3x_button_pressed(struct snd_soc_codec *codec)
1085{
1086 u8 val;
1087 aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val);
1088 return (val >> 5) & 1;
1089}
1090EXPORT_SYMBOL_GPL(aic3x_button_pressed);
1091
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001092#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000
1093#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
1094 SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
1095
Eric Miao6335d052009-03-03 09:41:00 +08001096static struct snd_soc_dai_ops aic3x_dai_ops = {
1097 .hw_params = aic3x_hw_params,
1098 .digital_mute = aic3x_mute,
1099 .set_sysclk = aic3x_set_dai_sysclk,
1100 .set_fmt = aic3x_set_dai_fmt,
1101};
1102
Liam Girdwoode550e172008-07-07 16:07:52 +01001103struct snd_soc_dai aic3x_dai = {
Jarkko Nikulae78cc182008-10-07 14:49:23 +03001104 .name = "tlv320aic3x",
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001105 .playback = {
1106 .stream_name = "Playback",
1107 .channels_min = 1,
1108 .channels_max = 2,
1109 .rates = AIC3X_RATES,
1110 .formats = AIC3X_FORMATS,},
1111 .capture = {
1112 .stream_name = "Capture",
1113 .channels_min = 1,
1114 .channels_max = 2,
1115 .rates = AIC3X_RATES,
1116 .formats = AIC3X_FORMATS,},
Eric Miao6335d052009-03-03 09:41:00 +08001117 .ops = &aic3x_dai_ops,
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001118};
1119EXPORT_SYMBOL_GPL(aic3x_dai);
1120
1121static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
1122{
1123 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +00001124 struct snd_soc_codec *codec = socdev->card->codec;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001125
Mark Brown0be98982008-05-19 12:31:28 +02001126 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001127
1128 return 0;
1129}
1130
1131static int aic3x_resume(struct platform_device *pdev)
1132{
1133 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +00001134 struct snd_soc_codec *codec = socdev->card->codec;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001135 int i;
1136 u8 data[2];
1137 u8 *cache = codec->reg_cache;
1138
1139 /* Sync reg_cache with the hardware */
1140 for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
1141 data[0] = i;
1142 data[1] = cache[i];
1143 codec->hw_write(codec->control_data, data, 2);
1144 }
1145
Mark Brown29e189c2010-05-07 20:30:00 +01001146 aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001147
1148 return 0;
1149}
1150
1151/*
1152 * initialise the AIC3X driver
1153 * register the mixer and dsp interfaces with the kernel
1154 */
Ben Dookscb3826f2009-08-20 22:50:41 +01001155static int aic3x_init(struct snd_soc_codec *codec)
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001156{
Ben Dookscb3826f2009-08-20 22:50:41 +01001157 int reg;
1158
1159 mutex_init(&codec->mutex);
1160 INIT_LIST_HEAD(&codec->dapm_widgets);
1161 INIT_LIST_HEAD(&codec->dapm_paths);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001162
Jarkko Nikulae78cc182008-10-07 14:49:23 +03001163 codec->name = "tlv320aic3x";
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001164 codec->owner = THIS_MODULE;
1165 codec->read = aic3x_read_reg_cache;
1166 codec->write = aic3x_write;
Mark Brown0be98982008-05-19 12:31:28 +02001167 codec->set_bias_level = aic3x_set_bias_level;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001168 codec->dai = &aic3x_dai;
1169 codec->num_dai = 1;
Mark Brownae2ff192008-06-11 13:47:08 +01001170 codec->reg_cache_size = ARRAY_SIZE(aic3x_reg);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001171 codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
1172 if (codec->reg_cache == NULL)
1173 return -ENOMEM;
1174
1175 aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
1176 aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
1177
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001178 /* DAC default volume and mute */
1179 aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
1180 aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
1181
1182 /* DAC to HP default volume and route to Output mixer */
1183 aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
1184 aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
1185 aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
1186 aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
1187 /* DAC to Line Out default volume and route to Output mixer */
1188 aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1189 aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1190 /* DAC to Mono Line Out default volume and route to Output mixer */
1191 aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1192 aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
1193
1194 /* unmute all outputs */
1195 reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
1196 aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE);
1197 reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
1198 aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE);
1199 reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
1200 aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
1201 reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
1202 aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE);
1203 reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
1204 aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE);
1205 reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
1206 aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE);
1207 reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
1208 aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE);
1209
1210 /* ADC default volume and unmute */
1211 aic3x_write(codec, LADC_VOL, DEFAULT_GAIN);
1212 aic3x_write(codec, RADC_VOL, DEFAULT_GAIN);
1213 /* By default route Line1 to ADC PGA mixer */
1214 aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0);
1215 aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0);
1216
1217 /* PGA to HP Bypass default volume, disconnect from Output Mixer */
1218 aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
1219 aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
1220 aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
1221 aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
1222 /* PGA to Line Out default volume, disconnect from Output Mixer */
1223 aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
1224 aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
1225 /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
1226 aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
1227 aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
1228
1229 /* Line2 to HP Bypass default volume, disconnect from Output Mixer */
1230 aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
1231 aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
1232 aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
1233 aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
1234 /* Line2 Line Out default volume, disconnect from Output Mixer */
1235 aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
1236 aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
1237 /* Line2 to Mono Out default volume, disconnect from Output Mixer */
1238 aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
1239 aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
1240
1241 /* off, with power on */
Mark Brown0be98982008-05-19 12:31:28 +02001242 aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001243
Ben Dookscb3826f2009-08-20 22:50:41 +01001244 return 0;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001245}
1246
Ben Dookscb3826f2009-08-20 22:50:41 +01001247static struct snd_soc_codec *aic3x_codec;
1248
1249static int aic3x_register(struct snd_soc_codec *codec)
1250{
1251 int ret;
1252
1253 ret = aic3x_init(codec);
1254 if (ret < 0) {
1255 dev_err(codec->dev, "Failed to initialise device\n");
1256 return ret;
1257 }
1258
1259 aic3x_codec = codec;
1260
1261 ret = snd_soc_register_codec(codec);
1262 if (ret) {
1263 dev_err(codec->dev, "Failed to register codec\n");
1264 return ret;
1265 }
1266
1267 ret = snd_soc_register_dai(&aic3x_dai);
1268 if (ret) {
1269 dev_err(codec->dev, "Failed to register dai\n");
1270 snd_soc_unregister_codec(codec);
1271 return ret;
1272 }
1273
1274 return 0;
1275}
1276
1277static int aic3x_unregister(struct aic3x_priv *aic3x)
1278{
1279 aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF);
1280
1281 snd_soc_unregister_dai(&aic3x_dai);
1282 snd_soc_unregister_codec(&aic3x->codec);
1283
Jarkko Nikula5193d622010-05-05 13:02:03 +03001284 if (aic3x->gpio_reset >= 0) {
1285 gpio_set_value(aic3x->gpio_reset, 0);
1286 gpio_free(aic3x->gpio_reset);
1287 }
Jarkko Nikula07779fd2010-04-26 15:49:14 +03001288 regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1289 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1290
Ben Dookscb3826f2009-08-20 22:50:41 +01001291 kfree(aic3x);
1292 aic3x_codec = NULL;
1293
1294 return 0;
1295}
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001296
1297#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1298/*
1299 * AIC3X 2 wire address can be up to 4 devices with device addresses
1300 * 0x18, 0x19, 0x1A, 0x1B
1301 */
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001302
1303/*
1304 * If the i2c layer weren't so broken, we could pass this kind of data
1305 * around
1306 */
Jean Delvareba8ed122008-09-22 14:15:53 +02001307static int aic3x_i2c_probe(struct i2c_client *i2c,
1308 const struct i2c_device_id *id)
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001309{
Ben Dookscb3826f2009-08-20 22:50:41 +01001310 struct snd_soc_codec *codec;
1311 struct aic3x_priv *aic3x;
Jarkko Nikula5193d622010-05-05 13:02:03 +03001312 struct aic3x_pdata *pdata = i2c->dev.platform_data;
Jarkko Nikula07779fd2010-04-26 15:49:14 +03001313 int ret, i;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001314
Ben Dookscb3826f2009-08-20 22:50:41 +01001315 aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
1316 if (aic3x == NULL) {
1317 dev_err(&i2c->dev, "failed to create private data\n");
1318 return -ENOMEM;
1319 }
1320
1321 codec = &aic3x->codec;
1322 codec->dev = &i2c->dev;
Mark Brownb2c812e2010-04-14 15:35:19 +09001323 snd_soc_codec_set_drvdata(codec, aic3x);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001324 codec->control_data = i2c;
Ben Dookscb3826f2009-08-20 22:50:41 +01001325 codec->hw_write = (hw_write_t) i2c_master_send;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001326
Ben Dookscb3826f2009-08-20 22:50:41 +01001327 i2c_set_clientdata(i2c, aic3x);
1328
Jarkko Nikula5193d622010-05-05 13:02:03 +03001329 aic3x->gpio_reset = -1;
1330 if (pdata && pdata->gpio_reset >= 0) {
1331 ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset");
1332 if (ret != 0)
1333 goto err_gpio;
1334 aic3x->gpio_reset = pdata->gpio_reset;
1335 gpio_direction_output(aic3x->gpio_reset, 0);
1336 }
1337
Jarkko Nikula07779fd2010-04-26 15:49:14 +03001338 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
1339 aic3x->supplies[i].supply = aic3x_supply_names[i];
1340
1341 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
1342 aic3x->supplies);
1343 if (ret != 0) {
1344 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
1345 goto err_get;
1346 }
1347
1348 ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
1349 aic3x->supplies);
1350 if (ret != 0) {
1351 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
1352 goto err_enable;
1353 }
1354
Jarkko Nikula5193d622010-05-05 13:02:03 +03001355 if (aic3x->gpio_reset >= 0) {
1356 udelay(1);
1357 gpio_set_value(aic3x->gpio_reset, 1);
1358 }
1359
Ben Dookscb3826f2009-08-20 22:50:41 +01001360 return aic3x_register(codec);
Jarkko Nikula07779fd2010-04-26 15:49:14 +03001361
1362err_enable:
1363 regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
1364err_get:
Jarkko Nikula5193d622010-05-05 13:02:03 +03001365 if (aic3x->gpio_reset >= 0)
1366 gpio_free(aic3x->gpio_reset);
1367err_gpio:
Jarkko Nikula07779fd2010-04-26 15:49:14 +03001368 kfree(aic3x);
1369 return ret;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001370}
1371
Jean Delvareba8ed122008-09-22 14:15:53 +02001372static int aic3x_i2c_remove(struct i2c_client *client)
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001373{
Ben Dookscb3826f2009-08-20 22:50:41 +01001374 struct aic3x_priv *aic3x = i2c_get_clientdata(client);
1375
1376 return aic3x_unregister(aic3x);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001377}
1378
Jean Delvareba8ed122008-09-22 14:15:53 +02001379static const struct i2c_device_id aic3x_i2c_id[] = {
1380 { "tlv320aic3x", 0 },
Ben Dookscb3826f2009-08-20 22:50:41 +01001381 { "tlv320aic33", 0 },
Jean Delvareba8ed122008-09-22 14:15:53 +02001382 { }
1383};
1384MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001385
1386/* machine i2c codec control layer */
1387static struct i2c_driver aic3x_i2c_driver = {
1388 .driver = {
1389 .name = "aic3x I2C Codec",
1390 .owner = THIS_MODULE,
1391 },
Ben Dookscb3826f2009-08-20 22:50:41 +01001392 .probe = aic3x_i2c_probe,
Jean Delvareba8ed122008-09-22 14:15:53 +02001393 .remove = aic3x_i2c_remove,
1394 .id_table = aic3x_i2c_id,
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001395};
Daniel Mack54e7e612008-04-30 16:20:52 +02001396
Ben Dookscb3826f2009-08-20 22:50:41 +01001397static inline void aic3x_i2c_init(void)
Jean Delvareba8ed122008-09-22 14:15:53 +02001398{
Jean Delvareba8ed122008-09-22 14:15:53 +02001399 int ret;
1400
1401 ret = i2c_add_driver(&aic3x_i2c_driver);
Ben Dookscb3826f2009-08-20 22:50:41 +01001402 if (ret)
1403 printk(KERN_ERR "%s: error regsitering i2c driver, %d\n",
1404 __func__, ret);
Jean Delvareba8ed122008-09-22 14:15:53 +02001405}
Ben Dookscb3826f2009-08-20 22:50:41 +01001406
1407static inline void aic3x_i2c_exit(void)
1408{
1409 i2c_del_driver(&aic3x_i2c_driver);
1410}
1411#else
1412static inline void aic3x_i2c_init(void) { }
1413static inline void aic3x_i2c_exit(void) { }
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001414#endif
1415
1416static int aic3x_probe(struct platform_device *pdev)
1417{
1418 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1419 struct aic3x_setup_data *setup;
1420 struct snd_soc_codec *codec;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001421 int ret = 0;
1422
Ben Dookscb3826f2009-08-20 22:50:41 +01001423 codec = aic3x_codec;
1424 if (!codec) {
1425 dev_err(&pdev->dev, "Codec not registered\n");
1426 return -ENODEV;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001427 }
1428
Mark Brown6627a652009-01-23 22:55:23 +00001429 socdev->card->codec = codec;
Ben Dookscb3826f2009-08-20 22:50:41 +01001430 setup = socdev->codec_data;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001431
Mark Brown977d49e2009-08-26 13:05:14 +01001432 if (setup) {
1433 /* setup GPIO functions */
1434 aic3x_write(codec, AIC3X_GPIO1_REG,
1435 (setup->gpio_func[0] & 0xf) << 4);
1436 aic3x_write(codec, AIC3X_GPIO2_REG,
1437 (setup->gpio_func[1] & 0xf) << 4);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001438 }
Jean Delvare3051e412008-08-25 11:49:20 +01001439
Ben Dookscb3826f2009-08-20 22:50:41 +01001440 /* register pcms */
1441 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1442 if (ret < 0) {
1443 printk(KERN_ERR "aic3x: failed to create pcms\n");
1444 goto pcm_err;
Jean Delvare3051e412008-08-25 11:49:20 +01001445 }
Ben Dookscb3826f2009-08-20 22:50:41 +01001446
1447 snd_soc_add_controls(codec, aic3x_snd_controls,
1448 ARRAY_SIZE(aic3x_snd_controls));
1449
1450 aic3x_add_widgets(codec);
1451
Ben Dookscb3826f2009-08-20 22:50:41 +01001452 return ret;
1453
Ben Dookscb3826f2009-08-20 22:50:41 +01001454pcm_err:
1455 kfree(codec->reg_cache);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001456 return ret;
1457}
1458
1459static int aic3x_remove(struct platform_device *pdev)
1460{
1461 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
Mark Brown6627a652009-01-23 22:55:23 +00001462 struct snd_soc_codec *codec = socdev->card->codec;
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001463
1464 /* power down chip */
1465 if (codec->control_data)
Mark Brown0be98982008-05-19 12:31:28 +02001466 aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001467
1468 snd_soc_free_pcms(socdev);
1469 snd_soc_dapm_free(socdev);
Ben Dookscb3826f2009-08-20 22:50:41 +01001470
1471 kfree(codec->reg_cache);
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001472
1473 return 0;
1474}
1475
1476struct snd_soc_codec_device soc_codec_dev_aic3x = {
1477 .probe = aic3x_probe,
1478 .remove = aic3x_remove,
1479 .suspend = aic3x_suspend,
1480 .resume = aic3x_resume,
1481};
1482EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
1483
Takashi Iwaic9b3a402008-12-10 07:47:22 +01001484static int __init aic3x_modinit(void)
Mark Brown64089b82008-12-08 19:17:58 +00001485{
Ben Dookscb3826f2009-08-20 22:50:41 +01001486 aic3x_i2c_init();
1487
1488 return 0;
Mark Brown64089b82008-12-08 19:17:58 +00001489}
1490module_init(aic3x_modinit);
1491
1492static void __exit aic3x_exit(void)
1493{
Ben Dookscb3826f2009-08-20 22:50:41 +01001494 aic3x_i2c_exit();
Mark Brown64089b82008-12-08 19:17:58 +00001495}
1496module_exit(aic3x_exit);
1497
Vladimir Barinov44d0a872007-11-14 17:07:17 +01001498MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
1499MODULE_AUTHOR("Vladimir Barinov");
1500MODULE_LICENSE("GPL");