• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/sound/soc/codecs/
1/*
2 * wm_hubs.c  --  WM8993/4 common code
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
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
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/init.h>
17#include <linux/delay.h>
18#include <linux/pm.h>
19#include <linux/i2c.h>
20#include <linux/platform_device.h>
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26#include <sound/initval.h>
27#include <sound/tlv.h>
28
29#include "wm8993.h"
30#include "wm_hubs.h"
31
32const DECLARE_TLV_DB_SCALE(wm_hubs_spkmix_tlv, -300, 300, 0);
33EXPORT_SYMBOL_GPL(wm_hubs_spkmix_tlv);
34
35static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
36static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
37static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
38static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
39static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
40static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
41static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
42static const unsigned int spkboost_tlv[] = {
43	TLV_DB_RANGE_HEAD(7),
44	0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
45	7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
46};
47static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
48
49static const char *speaker_ref_text[] = {
50	"SPKVDD/2",
51	"VMID",
52};
53
54static const struct soc_enum speaker_ref =
55	SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text);
56
57static const char *speaker_mode_text[] = {
58	"Class D",
59	"Class AB",
60};
61
62static const struct soc_enum speaker_mode =
63	SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text);
64
65static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
66{
67	unsigned int reg;
68	int count = 0;
69	unsigned int val;
70
71	val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
72
73	/* Trigger the command */
74	snd_soc_write(codec, WM8993_DC_SERVO_0, val);
75
76	dev_dbg(codec->dev, "Waiting for DC servo...\n");
77
78	do {
79		count++;
80		msleep(1);
81		reg = snd_soc_read(codec, WM8993_DC_SERVO_0);
82		dev_dbg(codec->dev, "DC servo: %x\n", reg);
83	} while (reg & op && count < 400);
84
85	if (reg & op)
86		dev_err(codec->dev, "Timed out waiting for DC Servo\n");
87}
88
89/*
90 * Startup calibration of the DC servo
91 */
92static void calibrate_dc_servo(struct snd_soc_codec *codec)
93{
94	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
95	s8 offset;
96	u16 reg, reg_l, reg_r, dcs_cfg;
97
98	/* Set for 32 series updates */
99	snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
100			    WM8993_DCS_SERIES_NO_01_MASK,
101			    32 << WM8993_DCS_SERIES_NO_01_SHIFT);
102	wait_for_dc_servo(codec,
103			  WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1);
104
105	/* Apply correction to DC servo result */
106	if (hubs->dcs_codes) {
107		dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
108			hubs->dcs_codes);
109
110		/* Different chips in the family support different
111		 * readback methods.
112		 */
113		switch (hubs->dcs_readback_mode) {
114		case 0:
115			reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
116				& WM8993_DCS_INTEG_CHAN_0_MASK;;
117			reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
118				& WM8993_DCS_INTEG_CHAN_1_MASK;
119			break;
120		case 1:
121			reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
122			reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
123				>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
124			reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
125			break;
126		default:
127			WARN(1, "Unknown DCS readback method");
128			break;
129		}
130
131		dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
132
133		/* HPOUT1L */
134		offset = reg_l;
135		offset += hubs->dcs_codes;
136		dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
137
138		/* HPOUT1R */
139		offset = reg_r;
140		offset += hubs->dcs_codes;
141		dcs_cfg |= (u8)offset;
142
143		dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
144
145		/* Do it */
146		snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
147		wait_for_dc_servo(codec,
148				  WM8993_DCS_TRIG_DAC_WR_0 |
149				  WM8993_DCS_TRIG_DAC_WR_1);
150	}
151}
152
153/*
154 * Update the DC servo calibration on gain changes
155 */
156static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
157			       struct snd_ctl_elem_value *ucontrol)
158{
159	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
160	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
161	int ret;
162
163	ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
164
165	/* If we're applying an offset correction then updating the
166	 * callibration would be likely to introduce further offsets. */
167	if (hubs->dcs_codes)
168		return ret;
169
170	/* Only need to do this if the outputs are active */
171	if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1)
172	    & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
173		snd_soc_update_bits(codec,
174				    WM8993_DC_SERVO_0,
175				    WM8993_DCS_TRIG_SINGLE_0 |
176				    WM8993_DCS_TRIG_SINGLE_1,
177				    WM8993_DCS_TRIG_SINGLE_0 |
178				    WM8993_DCS_TRIG_SINGLE_1);
179
180	return ret;
181}
182
183static const struct snd_kcontrol_new analogue_snd_controls[] = {
184SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
185	       inpga_tlv),
186SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
187SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
188
189SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
190	       inpga_tlv),
191SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
192SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 0),
193
194
195SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
196	       inpga_tlv),
197SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
198SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
199
200SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
201	       inpga_tlv),
202SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
203SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 0),
204
205SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
206	       inmix_sw_tlv),
207SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
208	       inmix_sw_tlv),
209SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
210	       inmix_tlv),
211SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
212SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
213	       inmix_tlv),
214
215SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
216	       inmix_sw_tlv),
217SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
218	       inmix_sw_tlv),
219SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
220	       inmix_tlv),
221SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
222SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
223	       inmix_tlv),
224
225SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
226	       outmix_tlv),
227SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
228	       outmix_tlv),
229SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
230	       outmix_tlv),
231SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
232	       outmix_tlv),
233SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
234	       outmix_tlv),
235SOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
236	       WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
237SOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
238	       WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
239SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
240	       outmix_tlv),
241
242SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
243	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
244SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
245	       WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
246SOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
247	       WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
248SOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
249	       WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
250SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
251	       WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
252SOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
253	       WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
254SOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
255	       WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
256SOC_SINGLE_TLV("Right Output Mixer DAC Volume",
257	       WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),
258
259SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
260		 WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
261SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
262	     WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
263SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
264	     WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),
265
266SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
267SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),
268
269SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
270	       5, 1, 1, wm_hubs_spkmix_tlv),
271SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
272	       4, 1, 1, wm_hubs_spkmix_tlv),
273SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
274	       3, 1, 1, wm_hubs_spkmix_tlv),
275
276SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
277	       5, 1, 1, wm_hubs_spkmix_tlv),
278SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
279	       4, 1, 1, wm_hubs_spkmix_tlv),
280SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
281	       3, 1, 1, wm_hubs_spkmix_tlv),
282
283SOC_DOUBLE_R_TLV("Speaker Mixer Volume",
284		 WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
285		 0, 3, 1, spkmixout_tlv),
286SOC_DOUBLE_R_TLV("Speaker Volume",
287		 WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
288		 0, 63, 0, outpga_tlv),
289SOC_DOUBLE_R("Speaker Switch",
290	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
291	     6, 1, 0),
292SOC_DOUBLE_R("Speaker ZC Switch",
293	     WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
294	     7, 1, 0),
295SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
296	       spkboost_tlv),
297SOC_ENUM("Speaker Reference", speaker_ref),
298SOC_ENUM("Speaker Mode", speaker_mode),
299
300{
301	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Volume",
302	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
303		 SNDRV_CTL_ELEM_ACCESS_READWRITE,
304	.tlv.p = outpga_tlv,
305	.info = snd_soc_info_volsw_2r,
306	.get = snd_soc_get_volsw_2r, .put = wm8993_put_dc_servo,
307	.private_value = (unsigned long)&(struct soc_mixer_control) {
308		.reg = WM8993_LEFT_OUTPUT_VOLUME,
309		.rreg = WM8993_RIGHT_OUTPUT_VOLUME,
310		.shift = 0, .max = 63
311	},
312},
313SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
314	     WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
315SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
316	     WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
317
318SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
319SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
320SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
321	       line_tlv),
322
323SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
324SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
325SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
326	       line_tlv),
327};
328
329static int hp_supply_event(struct snd_soc_dapm_widget *w,
330			   struct snd_kcontrol *kcontrol, int event)
331{
332	struct snd_soc_codec *codec = w->codec;
333	struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
334
335	switch (event) {
336	case SND_SOC_DAPM_PRE_PMU:
337		switch (hubs->hp_startup_mode) {
338		case 0:
339			break;
340		case 1:
341			/* Enable the headphone amp */
342			snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
343					    WM8993_HPOUT1L_ENA |
344					    WM8993_HPOUT1R_ENA,
345					    WM8993_HPOUT1L_ENA |
346					    WM8993_HPOUT1R_ENA);
347
348			/* Enable the second stage */
349			snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
350					    WM8993_HPOUT1L_DLY |
351					    WM8993_HPOUT1R_DLY,
352					    WM8993_HPOUT1L_DLY |
353					    WM8993_HPOUT1R_DLY);
354			break;
355		default:
356			dev_err(codec->dev, "Unknown HP startup mode %d\n",
357				hubs->hp_startup_mode);
358			break;
359		}
360
361	case SND_SOC_DAPM_PRE_PMD:
362		snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
363				    WM8993_CP_ENA, 0);
364		break;
365	}
366
367	return 0;
368}
369
370static int hp_event(struct snd_soc_dapm_widget *w,
371		    struct snd_kcontrol *kcontrol, int event)
372{
373	struct snd_soc_codec *codec = w->codec;
374	unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0);
375
376	switch (event) {
377	case SND_SOC_DAPM_POST_PMU:
378		snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
379				    WM8993_CP_ENA, WM8993_CP_ENA);
380
381		msleep(5);
382
383		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
384				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
385				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
386
387		reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
388		snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
389
390		/* Smallest supported update interval */
391		snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
392				    WM8993_DCS_TIMER_PERIOD_01_MASK, 1);
393
394		calibrate_dc_servo(codec);
395
396		reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
397			WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
398		snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
399		break;
400
401	case SND_SOC_DAPM_PRE_PMD:
402		snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
403				    WM8993_HPOUT1L_OUTP |
404				    WM8993_HPOUT1R_OUTP |
405				    WM8993_HPOUT1L_RMV_SHORT |
406				    WM8993_HPOUT1R_RMV_SHORT, 0);
407
408		snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
409				    WM8993_HPOUT1L_DLY |
410				    WM8993_HPOUT1R_DLY, 0);
411
412		snd_soc_write(codec, WM8993_DC_SERVO_0, 0);
413
414		snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
415				    WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
416				    0);
417		break;
418	}
419
420	return 0;
421}
422
423static int earpiece_event(struct snd_soc_dapm_widget *w,
424			  struct snd_kcontrol *control, int event)
425{
426	struct snd_soc_codec *codec = w->codec;
427	u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
428
429	switch (event) {
430	case SND_SOC_DAPM_PRE_PMU:
431		reg |= WM8993_HPOUT2_IN_ENA;
432		snd_soc_write(codec, WM8993_ANTIPOP1, reg);
433		udelay(50);
434		break;
435
436	case SND_SOC_DAPM_POST_PMD:
437		snd_soc_write(codec, WM8993_ANTIPOP1, reg);
438		break;
439
440	default:
441		BUG();
442		break;
443	}
444
445	return 0;
446}
447
448static const struct snd_kcontrol_new in1l_pga[] = {
449SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
450SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
451};
452
453static const struct snd_kcontrol_new in1r_pga[] = {
454SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
455SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
456};
457
458static const struct snd_kcontrol_new in2l_pga[] = {
459SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
460SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
461};
462
463static const struct snd_kcontrol_new in2r_pga[] = {
464SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
465SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
466};
467
468static const struct snd_kcontrol_new mixinl[] = {
469SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
470SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
471};
472
473static const struct snd_kcontrol_new mixinr[] = {
474SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
475SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
476};
477
478static const struct snd_kcontrol_new left_output_mixer[] = {
479SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
480SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
481SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
482SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
483SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
484SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
485SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
486SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
487};
488
489static const struct snd_kcontrol_new right_output_mixer[] = {
490SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
491SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
492SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
493SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
494SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
495SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
496SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
497SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
498};
499
500static const struct snd_kcontrol_new earpiece_mixer[] = {
501SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
502SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
503SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
504};
505
506static const struct snd_kcontrol_new left_speaker_boost[] = {
507SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
508SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
509SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
510};
511
512static const struct snd_kcontrol_new right_speaker_boost[] = {
513SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
514SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
515SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
516};
517
518static const struct snd_kcontrol_new line1_mix[] = {
519SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
520SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
521SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
522};
523
524static const struct snd_kcontrol_new line1n_mix[] = {
525SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
526SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
527};
528
529static const struct snd_kcontrol_new line1p_mix[] = {
530SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
531};
532
533static const struct snd_kcontrol_new line2_mix[] = {
534SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0),
535SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0),
536SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
537};
538
539static const struct snd_kcontrol_new line2n_mix[] = {
540SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
541SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
542};
543
544static const struct snd_kcontrol_new line2p_mix[] = {
545SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
546};
547
548static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = {
549SND_SOC_DAPM_INPUT("IN1LN"),
550SND_SOC_DAPM_INPUT("IN1LP"),
551SND_SOC_DAPM_INPUT("IN2LN"),
552SND_SOC_DAPM_INPUT("IN2LP:VXRN"),
553SND_SOC_DAPM_INPUT("IN1RN"),
554SND_SOC_DAPM_INPUT("IN1RP"),
555SND_SOC_DAPM_INPUT("IN2RN"),
556SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
557
558SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0),
559SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0),
560
561SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
562		   in1l_pga, ARRAY_SIZE(in1l_pga)),
563SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
564		   in1r_pga, ARRAY_SIZE(in1r_pga)),
565
566SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
567		   in2l_pga, ARRAY_SIZE(in2l_pga)),
568SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
569		   in2r_pga, ARRAY_SIZE(in2r_pga)),
570
571/* Dummy widgets to represent differential paths */
572SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
573
574SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
575		   mixinl, ARRAY_SIZE(mixinl)),
576SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
577		   mixinr, ARRAY_SIZE(mixinr)),
578
579SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
580		   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
581SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
582		   right_output_mixer, ARRAY_SIZE(right_output_mixer)),
583
584SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
585SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
586
587SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event,
588		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
589SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0,
590		   NULL, 0,
591		   hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
592
593SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
594		   earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
595SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
596		   NULL, 0, earpiece_event,
597		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
598
599SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
600		   left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
601SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
602		   right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
603
604SND_SOC_DAPM_PGA("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
605		 NULL, 0),
606SND_SOC_DAPM_PGA("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
607		 NULL, 0),
608
609SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
610		   line1_mix, ARRAY_SIZE(line1_mix)),
611SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
612		   line2_mix, ARRAY_SIZE(line2_mix)),
613
614SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
615		   line1n_mix, ARRAY_SIZE(line1n_mix)),
616SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
617		   line1p_mix, ARRAY_SIZE(line1p_mix)),
618SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
619		   line2n_mix, ARRAY_SIZE(line2n_mix)),
620SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
621		   line2p_mix, ARRAY_SIZE(line2p_mix)),
622
623SND_SOC_DAPM_PGA("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
624		 NULL, 0),
625SND_SOC_DAPM_PGA("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
626		 NULL, 0),
627SND_SOC_DAPM_PGA("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
628		 NULL, 0),
629SND_SOC_DAPM_PGA("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
630		 NULL, 0),
631
632SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
633SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
634SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
635SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
636SND_SOC_DAPM_OUTPUT("HPOUT1L"),
637SND_SOC_DAPM_OUTPUT("HPOUT1R"),
638SND_SOC_DAPM_OUTPUT("HPOUT2P"),
639SND_SOC_DAPM_OUTPUT("HPOUT2N"),
640SND_SOC_DAPM_OUTPUT("LINEOUT1P"),
641SND_SOC_DAPM_OUTPUT("LINEOUT1N"),
642SND_SOC_DAPM_OUTPUT("LINEOUT2P"),
643SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
644};
645
646static const struct snd_soc_dapm_route analogue_routes[] = {
647	{ "IN1L PGA", "IN1LP Switch", "IN1LP" },
648	{ "IN1L PGA", "IN1LN Switch", "IN1LN" },
649
650	{ "IN1R PGA", "IN1RP Switch", "IN1RP" },
651	{ "IN1R PGA", "IN1RN Switch", "IN1RN" },
652
653	{ "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" },
654	{ "IN2L PGA", "IN2LN Switch", "IN2LN" },
655
656	{ "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" },
657	{ "IN2R PGA", "IN2RN Switch", "IN2RN" },
658
659	{ "Direct Voice", NULL, "IN2LP:VXRN" },
660	{ "Direct Voice", NULL, "IN2RP:VXRP" },
661
662	{ "MIXINL", "IN1L Switch", "IN1L PGA" },
663	{ "MIXINL", "IN2L Switch", "IN2L PGA" },
664	{ "MIXINL", NULL, "Direct Voice" },
665	{ "MIXINL", NULL, "IN1LP" },
666	{ "MIXINL", NULL, "Left Output Mixer" },
667
668	{ "MIXINR", "IN1R Switch", "IN1R PGA" },
669	{ "MIXINR", "IN2R Switch", "IN2R PGA" },
670	{ "MIXINR", NULL, "Direct Voice" },
671	{ "MIXINR", NULL, "IN1RP" },
672	{ "MIXINR", NULL, "Right Output Mixer" },
673
674	{ "ADCL", NULL, "MIXINL" },
675	{ "ADCR", NULL, "MIXINR" },
676
677	{ "Left Output Mixer", "Left Input Switch", "MIXINL" },
678	{ "Left Output Mixer", "Right Input Switch", "MIXINR" },
679	{ "Left Output Mixer", "IN2RN Switch", "IN2RN" },
680	{ "Left Output Mixer", "IN2LN Switch", "IN2LN" },
681	{ "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" },
682	{ "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
683	{ "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
684
685	{ "Right Output Mixer", "Left Input Switch", "MIXINL" },
686	{ "Right Output Mixer", "Right Input Switch", "MIXINR" },
687	{ "Right Output Mixer", "IN2LN Switch", "IN2LN" },
688	{ "Right Output Mixer", "IN2RN Switch", "IN2RN" },
689	{ "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" },
690	{ "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
691	{ "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
692
693	{ "Left Output PGA", NULL, "Left Output Mixer" },
694	{ "Left Output PGA", NULL, "TOCLK" },
695
696	{ "Right Output PGA", NULL, "Right Output Mixer" },
697	{ "Right Output PGA", NULL, "TOCLK" },
698
699	{ "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
700	{ "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
701	{ "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
702
703	{ "Earpiece Driver", NULL, "Earpiece Mixer" },
704	{ "HPOUT2N", NULL, "Earpiece Driver" },
705	{ "HPOUT2P", NULL, "Earpiece Driver" },
706
707	{ "SPKL", "Input Switch", "MIXINL" },
708	{ "SPKL", "IN1LP Switch", "IN1LP" },
709	{ "SPKL", "Output Switch", "Left Output Mixer" },
710	{ "SPKL", NULL, "TOCLK" },
711
712	{ "SPKR", "Input Switch", "MIXINR" },
713	{ "SPKR", "IN1RP Switch", "IN1RP" },
714	{ "SPKR", "Output Switch", "Right Output Mixer" },
715	{ "SPKR", NULL, "TOCLK" },
716
717	{ "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
718	{ "SPKL Boost", "SPKL Switch", "SPKL" },
719	{ "SPKL Boost", "SPKR Switch", "SPKR" },
720
721	{ "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
722	{ "SPKR Boost", "SPKR Switch", "SPKR" },
723	{ "SPKR Boost", "SPKL Switch", "SPKL" },
724
725	{ "SPKL Driver", NULL, "SPKL Boost" },
726	{ "SPKL Driver", NULL, "CLK_SYS" },
727
728	{ "SPKR Driver", NULL, "SPKR Boost" },
729	{ "SPKR Driver", NULL, "CLK_SYS" },
730
731	{ "SPKOUTLP", NULL, "SPKL Driver" },
732	{ "SPKOUTLN", NULL, "SPKL Driver" },
733	{ "SPKOUTRP", NULL, "SPKR Driver" },
734	{ "SPKOUTRN", NULL, "SPKR Driver" },
735
736	{ "Left Headphone Mux", "Mixer", "Left Output Mixer" },
737	{ "Right Headphone Mux", "Mixer", "Right Output Mixer" },
738
739	{ "Headphone PGA", NULL, "Left Headphone Mux" },
740	{ "Headphone PGA", NULL, "Right Headphone Mux" },
741	{ "Headphone PGA", NULL, "CLK_SYS" },
742	{ "Headphone PGA", NULL, "Headphone Supply" },
743
744	{ "HPOUT1L", NULL, "Headphone PGA" },
745	{ "HPOUT1R", NULL, "Headphone PGA" },
746
747	{ "LINEOUT1N", NULL, "LINEOUT1N Driver" },
748	{ "LINEOUT1P", NULL, "LINEOUT1P Driver" },
749	{ "LINEOUT2N", NULL, "LINEOUT2N Driver" },
750	{ "LINEOUT2P", NULL, "LINEOUT2P Driver" },
751};
752
753static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
754	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
755	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
756	{ "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" },
757
758	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
759	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
760};
761
762static const struct snd_soc_dapm_route lineout1_se_routes[] = {
763	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" },
764	{ "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" },
765
766	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" },
767
768	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
769	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
770};
771
772static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
773	{ "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
774	{ "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
775	{ "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" },
776
777	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
778	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
779};
780
781static const struct snd_soc_dapm_route lineout2_se_routes[] = {
782	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" },
783	{ "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" },
784
785	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" },
786
787	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
788	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
789};
790
791int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
792{
793	/* Latch volume update bits & default ZC on */
794	snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
795			    WM8993_IN1_VU, WM8993_IN1_VU);
796	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
797			    WM8993_IN1_VU, WM8993_IN1_VU);
798	snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
799			    WM8993_IN2_VU, WM8993_IN2_VU);
800	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
801			    WM8993_IN2_VU, WM8993_IN2_VU);
802
803	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
804			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
805
806	snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
807			    WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC);
808	snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
809			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
810			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
811
812	snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
813			    WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC);
814	snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
815			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
816			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
817
818	snd_soc_add_controls(codec, analogue_snd_controls,
819			     ARRAY_SIZE(analogue_snd_controls));
820
821	snd_soc_dapm_new_controls(codec, analogue_dapm_widgets,
822				  ARRAY_SIZE(analogue_dapm_widgets));
823	return 0;
824}
825EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
826
827int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
828				int lineout1_diff, int lineout2_diff)
829{
830	snd_soc_dapm_add_routes(codec, analogue_routes,
831				ARRAY_SIZE(analogue_routes));
832
833	if (lineout1_diff)
834		snd_soc_dapm_add_routes(codec,
835					lineout1_diff_routes,
836					ARRAY_SIZE(lineout1_diff_routes));
837	else
838		snd_soc_dapm_add_routes(codec,
839					lineout1_se_routes,
840					ARRAY_SIZE(lineout1_se_routes));
841
842	if (lineout2_diff)
843		snd_soc_dapm_add_routes(codec,
844					lineout2_diff_routes,
845					ARRAY_SIZE(lineout2_diff_routes));
846	else
847		snd_soc_dapm_add_routes(codec,
848					lineout2_se_routes,
849					ARRAY_SIZE(lineout2_se_routes));
850
851	return 0;
852}
853EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
854
855int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
856				  int lineout1_diff, int lineout2_diff,
857				  int lineout1fb, int lineout2fb,
858				  int jd_scthr, int jd_thr, int micbias1_lvl,
859				  int micbias2_lvl)
860{
861	if (!lineout1_diff)
862		snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
863				    WM8993_LINEOUT1_MODE,
864				    WM8993_LINEOUT1_MODE);
865	if (!lineout2_diff)
866		snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
867				    WM8993_LINEOUT2_MODE,
868				    WM8993_LINEOUT2_MODE);
869
870	/* If the line outputs are differential then we aren't presenting
871	 * VMID as an output and can disable it.
872	 */
873	if (lineout1_diff && lineout2_diff)
874		codec->idle_bias_off = 1;
875
876	if (lineout1fb)
877		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
878				    WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
879
880	if (lineout2fb)
881		snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
882				    WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
883
884	snd_soc_update_bits(codec, WM8993_MICBIAS,
885			    WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
886			    WM8993_MICB1_LVL | WM8993_MICB2_LVL,
887			    jd_scthr << WM8993_JD_SCTHR_SHIFT |
888			    jd_thr << WM8993_JD_THR_SHIFT |
889			    micbias1_lvl |
890			    micbias2_lvl << WM8993_MICB2_LVL_SHIFT);
891
892	return 0;
893}
894EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
895
896MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
897MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
898MODULE_LICENSE("GPL");
899