xref: /openbmc/linux/sound/soc/codecs/wm2200.c (revision e10f8711)
1d5315a23SMark Brown /*
2d5315a23SMark Brown  * wm2200.c  --  WM2200 ALSA SoC Audio driver
3d5315a23SMark Brown  *
4d5315a23SMark Brown  * Copyright 2012 Wolfson Microelectronics plc
5d5315a23SMark Brown  *
6d5315a23SMark Brown  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7d5315a23SMark Brown  *
8d5315a23SMark Brown  * This program is free software; you can redistribute it and/or modify
9d5315a23SMark Brown  * it under the terms of the GNU General Public License version 2 as
10d5315a23SMark Brown  * published by the Free Software Foundation.
11d5315a23SMark Brown  */
12d5315a23SMark Brown 
13d5315a23SMark Brown #include <linux/module.h>
14d5315a23SMark Brown #include <linux/moduleparam.h>
15d5315a23SMark Brown #include <linux/init.h>
16d5315a23SMark Brown #include <linux/delay.h>
17d5315a23SMark Brown #include <linux/pm.h>
18e10f8711SMark Brown #include <linux/firmware.h>
19d5315a23SMark Brown #include <linux/gcd.h>
20d5315a23SMark Brown #include <linux/gpio.h>
21d5315a23SMark Brown #include <linux/i2c.h>
22d5315a23SMark Brown #include <linux/pm_runtime.h>
23d5315a23SMark Brown #include <linux/regulator/consumer.h>
24d5315a23SMark Brown #include <linux/regulator/fixed.h>
25d5315a23SMark Brown #include <linux/slab.h>
26d5315a23SMark Brown #include <sound/core.h>
27d5315a23SMark Brown #include <sound/pcm.h>
28d5315a23SMark Brown #include <sound/pcm_params.h>
29d5315a23SMark Brown #include <sound/soc.h>
30d5315a23SMark Brown #include <sound/jack.h>
31d5315a23SMark Brown #include <sound/initval.h>
32d5315a23SMark Brown #include <sound/tlv.h>
33d5315a23SMark Brown #include <sound/wm2200.h>
34d5315a23SMark Brown 
35d5315a23SMark Brown #include "wm2200.h"
36e10f8711SMark Brown #include "wmfw.h"
37e10f8711SMark Brown 
38e10f8711SMark Brown #define WM2200_DSP_CONTROL_1                   0x00
39e10f8711SMark Brown #define WM2200_DSP_CONTROL_2                   0x02
40e10f8711SMark Brown #define WM2200_DSP_CONTROL_3                   0x03
41e10f8711SMark Brown #define WM2200_DSP_CONTROL_4                   0x04
42e10f8711SMark Brown #define WM2200_DSP_CONTROL_5                   0x06
43e10f8711SMark Brown #define WM2200_DSP_CONTROL_6                   0x07
44e10f8711SMark Brown #define WM2200_DSP_CONTROL_7                   0x08
45e10f8711SMark Brown #define WM2200_DSP_CONTROL_8                   0x09
46e10f8711SMark Brown #define WM2200_DSP_CONTROL_9                   0x0A
47e10f8711SMark Brown #define WM2200_DSP_CONTROL_10                  0x0B
48e10f8711SMark Brown #define WM2200_DSP_CONTROL_11                  0x0C
49e10f8711SMark Brown #define WM2200_DSP_CONTROL_12                  0x0D
50e10f8711SMark Brown #define WM2200_DSP_CONTROL_13                  0x0F
51e10f8711SMark Brown #define WM2200_DSP_CONTROL_14                  0x10
52e10f8711SMark Brown #define WM2200_DSP_CONTROL_15                  0x11
53e10f8711SMark Brown #define WM2200_DSP_CONTROL_16                  0x12
54e10f8711SMark Brown #define WM2200_DSP_CONTROL_17                  0x13
55e10f8711SMark Brown #define WM2200_DSP_CONTROL_18                  0x14
56e10f8711SMark Brown #define WM2200_DSP_CONTROL_19                  0x16
57e10f8711SMark Brown #define WM2200_DSP_CONTROL_20                  0x17
58e10f8711SMark Brown #define WM2200_DSP_CONTROL_21                  0x18
59e10f8711SMark Brown #define WM2200_DSP_CONTROL_22                  0x1A
60e10f8711SMark Brown #define WM2200_DSP_CONTROL_23                  0x1B
61e10f8711SMark Brown #define WM2200_DSP_CONTROL_24                  0x1C
62e10f8711SMark Brown #define WM2200_DSP_CONTROL_25                  0x1E
63e10f8711SMark Brown #define WM2200_DSP_CONTROL_26                  0x20
64e10f8711SMark Brown #define WM2200_DSP_CONTROL_27                  0x21
65e10f8711SMark Brown #define WM2200_DSP_CONTROL_28                  0x22
66e10f8711SMark Brown #define WM2200_DSP_CONTROL_29                  0x23
67e10f8711SMark Brown #define WM2200_DSP_CONTROL_30                  0x24
68e10f8711SMark Brown #define WM2200_DSP_CONTROL_31                  0x26
69d5315a23SMark Brown 
70d5315a23SMark Brown /* The code assumes DCVDD is generated internally */
71d5315a23SMark Brown #define WM2200_NUM_CORE_SUPPLIES 2
72d5315a23SMark Brown static const char *wm2200_core_supply_names[WM2200_NUM_CORE_SUPPLIES] = {
73d5315a23SMark Brown 	"DBVDD",
74d5315a23SMark Brown 	"LDOVDD",
75d5315a23SMark Brown };
76d5315a23SMark Brown 
77d5315a23SMark Brown struct wm2200_fll {
78d5315a23SMark Brown 	int fref;
79d5315a23SMark Brown 	int fout;
80d5315a23SMark Brown 	int src;
81d5315a23SMark Brown 	struct completion lock;
82d5315a23SMark Brown };
83d5315a23SMark Brown 
84d5315a23SMark Brown /* codec private data */
85d5315a23SMark Brown struct wm2200_priv {
86d5315a23SMark Brown 	struct regmap *regmap;
87d5315a23SMark Brown 	struct device *dev;
88d5315a23SMark Brown 	struct snd_soc_codec *codec;
89d5315a23SMark Brown 	struct wm2200_pdata pdata;
90d5315a23SMark Brown 	struct regulator_bulk_data core_supplies[WM2200_NUM_CORE_SUPPLIES];
91d5315a23SMark Brown 
92d5315a23SMark Brown 	struct completion fll_lock;
93d5315a23SMark Brown 	int fll_fout;
94d5315a23SMark Brown 	int fll_fref;
95d5315a23SMark Brown 	int fll_src;
96d5315a23SMark Brown 
97d5315a23SMark Brown 	int rev;
98d5315a23SMark Brown 	int sysclk;
99d5315a23SMark Brown };
100d5315a23SMark Brown 
101eae2328dSMark Brown #define WM2200_DSP_RANGE_BASE (WM2200_MAX_REGISTER + 1)
102eae2328dSMark Brown #define WM2200_DSP_SPACING 12288
103eae2328dSMark Brown 
104eae2328dSMark Brown #define WM2200_DSP1_DM_BASE (WM2200_DSP_RANGE_BASE + (0 * WM2200_DSP_SPACING))
105eae2328dSMark Brown #define WM2200_DSP1_PM_BASE (WM2200_DSP_RANGE_BASE + (1 * WM2200_DSP_SPACING))
106eae2328dSMark Brown #define WM2200_DSP1_ZM_BASE (WM2200_DSP_RANGE_BASE + (2 * WM2200_DSP_SPACING))
107eae2328dSMark Brown #define WM2200_DSP2_DM_BASE (WM2200_DSP_RANGE_BASE + (3 * WM2200_DSP_SPACING))
108eae2328dSMark Brown #define WM2200_DSP2_PM_BASE (WM2200_DSP_RANGE_BASE + (4 * WM2200_DSP_SPACING))
109eae2328dSMark Brown #define WM2200_DSP2_ZM_BASE (WM2200_DSP_RANGE_BASE + (5 * WM2200_DSP_SPACING))
110eae2328dSMark Brown 
111eae2328dSMark Brown static const struct regmap_range_cfg wm2200_ranges[] = {
112eae2328dSMark Brown 	/* DSP1 DM */
113eae2328dSMark Brown 	{ .range_min = WM2200_DSP1_DM_BASE,
114eae2328dSMark Brown 	  .range_max = WM2200_DSP1_DM_BASE + 12287,
115eae2328dSMark Brown 	  .selector_reg = WM2200_DSP1_CONTROL_3,
116eae2328dSMark Brown 	  .selector_mask = WM2200_DSP1_PAGE_BASE_DM_0_MASK,
117eae2328dSMark Brown 	  .selector_shift = WM2200_DSP1_PAGE_BASE_DM_0_SHIFT,
118eae2328dSMark Brown 	  .window_start = WM2200_DSP1_DM_0, .window_len = 2048, },
119eae2328dSMark Brown 
120eae2328dSMark Brown 	/* DSP1 PM */
121eae2328dSMark Brown 	{ .range_min = WM2200_DSP1_PM_BASE,
122eae2328dSMark Brown 	  .range_max = WM2200_DSP1_PM_BASE + 12287,
123eae2328dSMark Brown 	  .selector_reg = WM2200_DSP1_CONTROL_2,
124eae2328dSMark Brown 	  .selector_mask = WM2200_DSP1_PAGE_BASE_PM_0_MASK,
125eae2328dSMark Brown 	  .selector_shift = WM2200_DSP1_PAGE_BASE_PM_0_SHIFT,
126eae2328dSMark Brown 	  .window_start = WM2200_DSP1_PM_0, .window_len = 768, },
127eae2328dSMark Brown 
128eae2328dSMark Brown 	/* DSP1 ZM */
129eae2328dSMark Brown 	{ .range_min = WM2200_DSP1_ZM_BASE,
130eae2328dSMark Brown 	  .range_max = WM2200_DSP1_ZM_BASE + 2047,
131eae2328dSMark Brown 	  .selector_reg = WM2200_DSP1_CONTROL_4,
132eae2328dSMark Brown 	  .selector_mask = WM2200_DSP1_PAGE_BASE_ZM_0_MASK,
133eae2328dSMark Brown 	  .selector_shift = WM2200_DSP1_PAGE_BASE_ZM_0_SHIFT,
134eae2328dSMark Brown 	  .window_start = WM2200_DSP1_ZM_0, .window_len = 1024, },
135eae2328dSMark Brown 
136eae2328dSMark Brown 	/* DSP2 DM */
137eae2328dSMark Brown 	{ .range_min = WM2200_DSP2_DM_BASE,
138eae2328dSMark Brown 	  .range_max = WM2200_DSP2_DM_BASE + 4095,
139eae2328dSMark Brown 	  .selector_reg = WM2200_DSP2_CONTROL_3,
140eae2328dSMark Brown 	  .selector_mask = WM2200_DSP2_PAGE_BASE_DM_0_MASK,
141eae2328dSMark Brown 	  .selector_shift = WM2200_DSP2_PAGE_BASE_DM_0_SHIFT,
142eae2328dSMark Brown 	  .window_start = WM2200_DSP2_DM_0, .window_len = 2048, },
143eae2328dSMark Brown 
144eae2328dSMark Brown 	/* DSP2 PM */
145eae2328dSMark Brown 	{ .range_min = WM2200_DSP2_PM_BASE,
146eae2328dSMark Brown 	  .range_max = WM2200_DSP2_PM_BASE + 11287,
147eae2328dSMark Brown 	  .selector_reg = WM2200_DSP2_CONTROL_2,
148eae2328dSMark Brown 	  .selector_mask = WM2200_DSP2_PAGE_BASE_PM_0_MASK,
149eae2328dSMark Brown 	  .selector_shift = WM2200_DSP2_PAGE_BASE_PM_0_SHIFT,
150eae2328dSMark Brown 	  .window_start = WM2200_DSP2_PM_0, .window_len = 768, },
151eae2328dSMark Brown 
152eae2328dSMark Brown 	/* DSP2 ZM */
153eae2328dSMark Brown 	{ .range_min = WM2200_DSP2_ZM_BASE,
154eae2328dSMark Brown 	  .range_max = WM2200_DSP2_ZM_BASE + 2047,
155eae2328dSMark Brown 	  .selector_reg = WM2200_DSP2_CONTROL_4,
156eae2328dSMark Brown 	  .selector_mask = WM2200_DSP2_PAGE_BASE_ZM_0_MASK,
157eae2328dSMark Brown 	  .selector_shift = WM2200_DSP2_PAGE_BASE_ZM_0_SHIFT,
158eae2328dSMark Brown 	  .window_start = WM2200_DSP2_ZM_0, .window_len = 1024, },
159eae2328dSMark Brown };
160eae2328dSMark Brown 
161d5315a23SMark Brown static struct reg_default wm2200_reg_defaults[] = {
162d5315a23SMark Brown 	{ 0x000B, 0x0000 },   /* R11    - Tone Generator 1 */
163d5315a23SMark Brown 	{ 0x0102, 0x0000 },   /* R258   - Clocking 3 */
164d5315a23SMark Brown 	{ 0x0103, 0x0011 },   /* R259   - Clocking 4 */
165d5315a23SMark Brown 	{ 0x0111, 0x0000 },   /* R273   - FLL Control 1 */
166d5315a23SMark Brown 	{ 0x0112, 0x0000 },   /* R274   - FLL Control 2 */
167d5315a23SMark Brown 	{ 0x0113, 0x0000 },   /* R275   - FLL Control 3 */
168d5315a23SMark Brown 	{ 0x0114, 0x0000 },   /* R276   - FLL Control 4 */
169d5315a23SMark Brown 	{ 0x0116, 0x0177 },   /* R278   - FLL Control 6 */
170d5315a23SMark Brown 	{ 0x0117, 0x0004 },   /* R279   - FLL Control 7 */
171d5315a23SMark Brown 	{ 0x0119, 0x0000 },   /* R281   - FLL EFS 1 */
172d5315a23SMark Brown 	{ 0x011A, 0x0002 },   /* R282   - FLL EFS 2 */
173d5315a23SMark Brown 	{ 0x0200, 0x0000 },   /* R512   - Mic Charge Pump 1 */
174d5315a23SMark Brown 	{ 0x0201, 0x03FF },   /* R513   - Mic Charge Pump 2 */
175d5315a23SMark Brown 	{ 0x0202, 0x9BDE },   /* R514   - DM Charge Pump 1 */
176d5315a23SMark Brown 	{ 0x020C, 0x0000 },   /* R524   - Mic Bias Ctrl 1 */
177d5315a23SMark Brown 	{ 0x020D, 0x0000 },   /* R525   - Mic Bias Ctrl 2 */
178d5315a23SMark Brown 	{ 0x020F, 0x0000 },   /* R527   - Ear Piece Ctrl 1 */
179d5315a23SMark Brown 	{ 0x0210, 0x0000 },   /* R528   - Ear Piece Ctrl 2 */
180d5315a23SMark Brown 	{ 0x0301, 0x0000 },   /* R769   - Input Enables */
181d5315a23SMark Brown 	{ 0x0302, 0x2240 },   /* R770   - IN1L Control */
182d5315a23SMark Brown 	{ 0x0303, 0x0040 },   /* R771   - IN1R Control */
183d5315a23SMark Brown 	{ 0x0304, 0x2240 },   /* R772   - IN2L Control */
184d5315a23SMark Brown 	{ 0x0305, 0x0040 },   /* R773   - IN2R Control */
185d5315a23SMark Brown 	{ 0x0306, 0x2240 },   /* R774   - IN3L Control */
186d5315a23SMark Brown 	{ 0x0307, 0x0040 },   /* R775   - IN3R Control */
187d5315a23SMark Brown 	{ 0x030A, 0x0000 },   /* R778   - RXANC_SRC */
188d5315a23SMark Brown 	{ 0x030B, 0x0022 },   /* R779   - Input Volume Ramp */
189d5315a23SMark Brown 	{ 0x030C, 0x0180 },   /* R780   - ADC Digital Volume 1L */
190d5315a23SMark Brown 	{ 0x030D, 0x0180 },   /* R781   - ADC Digital Volume 1R */
191d5315a23SMark Brown 	{ 0x030E, 0x0180 },   /* R782   - ADC Digital Volume 2L */
192d5315a23SMark Brown 	{ 0x030F, 0x0180 },   /* R783   - ADC Digital Volume 2R */
193d5315a23SMark Brown 	{ 0x0310, 0x0180 },   /* R784   - ADC Digital Volume 3L */
194d5315a23SMark Brown 	{ 0x0311, 0x0180 },   /* R785   - ADC Digital Volume 3R */
195d5315a23SMark Brown 	{ 0x0400, 0x0000 },   /* R1024  - Output Enables */
196d5315a23SMark Brown 	{ 0x0401, 0x0000 },   /* R1025  - DAC Volume Limit 1L */
197d5315a23SMark Brown 	{ 0x0402, 0x0000 },   /* R1026  - DAC Volume Limit 1R */
198d5315a23SMark Brown 	{ 0x0403, 0x0000 },   /* R1027  - DAC Volume Limit 2L */
199d5315a23SMark Brown 	{ 0x0404, 0x0000 },   /* R1028  - DAC Volume Limit 2R */
200d5315a23SMark Brown 	{ 0x0409, 0x0000 },   /* R1033  - DAC AEC Control 1 */
201d5315a23SMark Brown 	{ 0x040A, 0x0022 },   /* R1034  - Output Volume Ramp */
202d5315a23SMark Brown 	{ 0x040B, 0x0180 },   /* R1035  - DAC Digital Volume 1L */
203d5315a23SMark Brown 	{ 0x040C, 0x0180 },   /* R1036  - DAC Digital Volume 1R */
204d5315a23SMark Brown 	{ 0x040D, 0x0180 },   /* R1037  - DAC Digital Volume 2L */
205d5315a23SMark Brown 	{ 0x040E, 0x0180 },   /* R1038  - DAC Digital Volume 2R */
206d5315a23SMark Brown 	{ 0x0417, 0x0069 },   /* R1047  - PDM 1 */
207d5315a23SMark Brown 	{ 0x0418, 0x0000 },   /* R1048  - PDM 2 */
208d5315a23SMark Brown 	{ 0x0500, 0x0000 },   /* R1280  - Audio IF 1_1 */
209d5315a23SMark Brown 	{ 0x0501, 0x0008 },   /* R1281  - Audio IF 1_2 */
210d5315a23SMark Brown 	{ 0x0502, 0x0000 },   /* R1282  - Audio IF 1_3 */
211d5315a23SMark Brown 	{ 0x0503, 0x0000 },   /* R1283  - Audio IF 1_4 */
212d5315a23SMark Brown 	{ 0x0504, 0x0000 },   /* R1284  - Audio IF 1_5 */
213d5315a23SMark Brown 	{ 0x0505, 0x0001 },   /* R1285  - Audio IF 1_6 */
214d5315a23SMark Brown 	{ 0x0506, 0x0001 },   /* R1286  - Audio IF 1_7 */
215d5315a23SMark Brown 	{ 0x0507, 0x0000 },   /* R1287  - Audio IF 1_8 */
216d5315a23SMark Brown 	{ 0x0508, 0x0000 },   /* R1288  - Audio IF 1_9 */
217d5315a23SMark Brown 	{ 0x0509, 0x0000 },   /* R1289  - Audio IF 1_10 */
218d5315a23SMark Brown 	{ 0x050A, 0x0000 },   /* R1290  - Audio IF 1_11 */
219d5315a23SMark Brown 	{ 0x050B, 0x0000 },   /* R1291  - Audio IF 1_12 */
220d5315a23SMark Brown 	{ 0x050C, 0x0000 },   /* R1292  - Audio IF 1_13 */
221d5315a23SMark Brown 	{ 0x050D, 0x0000 },   /* R1293  - Audio IF 1_14 */
222d5315a23SMark Brown 	{ 0x050E, 0x0000 },   /* R1294  - Audio IF 1_15 */
223d5315a23SMark Brown 	{ 0x050F, 0x0000 },   /* R1295  - Audio IF 1_16 */
224d5315a23SMark Brown 	{ 0x0510, 0x0000 },   /* R1296  - Audio IF 1_17 */
225d5315a23SMark Brown 	{ 0x0511, 0x0000 },   /* R1297  - Audio IF 1_18 */
226d5315a23SMark Brown 	{ 0x0512, 0x0000 },   /* R1298  - Audio IF 1_19 */
227d5315a23SMark Brown 	{ 0x0513, 0x0000 },   /* R1299  - Audio IF 1_20 */
228d5315a23SMark Brown 	{ 0x0514, 0x0000 },   /* R1300  - Audio IF 1_21 */
229d5315a23SMark Brown 	{ 0x0515, 0x0001 },   /* R1301  - Audio IF 1_22 */
230d5315a23SMark Brown 	{ 0x0600, 0x0000 },   /* R1536  - OUT1LMIX Input 1 Source */
231d5315a23SMark Brown 	{ 0x0601, 0x0080 },   /* R1537  - OUT1LMIX Input 1 Volume */
232d5315a23SMark Brown 	{ 0x0602, 0x0000 },   /* R1538  - OUT1LMIX Input 2 Source */
233d5315a23SMark Brown 	{ 0x0603, 0x0080 },   /* R1539  - OUT1LMIX Input 2 Volume */
234d5315a23SMark Brown 	{ 0x0604, 0x0000 },   /* R1540  - OUT1LMIX Input 3 Source */
235d5315a23SMark Brown 	{ 0x0605, 0x0080 },   /* R1541  - OUT1LMIX Input 3 Volume */
236d5315a23SMark Brown 	{ 0x0606, 0x0000 },   /* R1542  - OUT1LMIX Input 4 Source */
237d5315a23SMark Brown 	{ 0x0607, 0x0080 },   /* R1543  - OUT1LMIX Input 4 Volume */
238d5315a23SMark Brown 	{ 0x0608, 0x0000 },   /* R1544  - OUT1RMIX Input 1 Source */
239d5315a23SMark Brown 	{ 0x0609, 0x0080 },   /* R1545  - OUT1RMIX Input 1 Volume */
240d5315a23SMark Brown 	{ 0x060A, 0x0000 },   /* R1546  - OUT1RMIX Input 2 Source */
241d5315a23SMark Brown 	{ 0x060B, 0x0080 },   /* R1547  - OUT1RMIX Input 2 Volume */
242d5315a23SMark Brown 	{ 0x060C, 0x0000 },   /* R1548  - OUT1RMIX Input 3 Source */
243d5315a23SMark Brown 	{ 0x060D, 0x0080 },   /* R1549  - OUT1RMIX Input 3 Volume */
244d5315a23SMark Brown 	{ 0x060E, 0x0000 },   /* R1550  - OUT1RMIX Input 4 Source */
245d5315a23SMark Brown 	{ 0x060F, 0x0080 },   /* R1551  - OUT1RMIX Input 4 Volume */
246d5315a23SMark Brown 	{ 0x0610, 0x0000 },   /* R1552  - OUT2LMIX Input 1 Source */
247d5315a23SMark Brown 	{ 0x0611, 0x0080 },   /* R1553  - OUT2LMIX Input 1 Volume */
248d5315a23SMark Brown 	{ 0x0612, 0x0000 },   /* R1554  - OUT2LMIX Input 2 Source */
249d5315a23SMark Brown 	{ 0x0613, 0x0080 },   /* R1555  - OUT2LMIX Input 2 Volume */
250d5315a23SMark Brown 	{ 0x0614, 0x0000 },   /* R1556  - OUT2LMIX Input 3 Source */
251d5315a23SMark Brown 	{ 0x0615, 0x0080 },   /* R1557  - OUT2LMIX Input 3 Volume */
252d5315a23SMark Brown 	{ 0x0616, 0x0000 },   /* R1558  - OUT2LMIX Input 4 Source */
253d5315a23SMark Brown 	{ 0x0617, 0x0080 },   /* R1559  - OUT2LMIX Input 4 Volume */
254d5315a23SMark Brown 	{ 0x0618, 0x0000 },   /* R1560  - OUT2RMIX Input 1 Source */
255d5315a23SMark Brown 	{ 0x0619, 0x0080 },   /* R1561  - OUT2RMIX Input 1 Volume */
256d5315a23SMark Brown 	{ 0x061A, 0x0000 },   /* R1562  - OUT2RMIX Input 2 Source */
257d5315a23SMark Brown 	{ 0x061B, 0x0080 },   /* R1563  - OUT2RMIX Input 2 Volume */
258d5315a23SMark Brown 	{ 0x061C, 0x0000 },   /* R1564  - OUT2RMIX Input 3 Source */
259d5315a23SMark Brown 	{ 0x061D, 0x0080 },   /* R1565  - OUT2RMIX Input 3 Volume */
260d5315a23SMark Brown 	{ 0x061E, 0x0000 },   /* R1566  - OUT2RMIX Input 4 Source */
261d5315a23SMark Brown 	{ 0x061F, 0x0080 },   /* R1567  - OUT2RMIX Input 4 Volume */
262d5315a23SMark Brown 	{ 0x0620, 0x0000 },   /* R1568  - AIF1TX1MIX Input 1 Source */
263d5315a23SMark Brown 	{ 0x0621, 0x0080 },   /* R1569  - AIF1TX1MIX Input 1 Volume */
264d5315a23SMark Brown 	{ 0x0622, 0x0000 },   /* R1570  - AIF1TX1MIX Input 2 Source */
265d5315a23SMark Brown 	{ 0x0623, 0x0080 },   /* R1571  - AIF1TX1MIX Input 2 Volume */
266d5315a23SMark Brown 	{ 0x0624, 0x0000 },   /* R1572  - AIF1TX1MIX Input 3 Source */
267d5315a23SMark Brown 	{ 0x0625, 0x0080 },   /* R1573  - AIF1TX1MIX Input 3 Volume */
268d5315a23SMark Brown 	{ 0x0626, 0x0000 },   /* R1574  - AIF1TX1MIX Input 4 Source */
269d5315a23SMark Brown 	{ 0x0627, 0x0080 },   /* R1575  - AIF1TX1MIX Input 4 Volume */
270d5315a23SMark Brown 	{ 0x0628, 0x0000 },   /* R1576  - AIF1TX2MIX Input 1 Source */
271d5315a23SMark Brown 	{ 0x0629, 0x0080 },   /* R1577  - AIF1TX2MIX Input 1 Volume */
272d5315a23SMark Brown 	{ 0x062A, 0x0000 },   /* R1578  - AIF1TX2MIX Input 2 Source */
273d5315a23SMark Brown 	{ 0x062B, 0x0080 },   /* R1579  - AIF1TX2MIX Input 2 Volume */
274d5315a23SMark Brown 	{ 0x062C, 0x0000 },   /* R1580  - AIF1TX2MIX Input 3 Source */
275d5315a23SMark Brown 	{ 0x062D, 0x0080 },   /* R1581  - AIF1TX2MIX Input 3 Volume */
276d5315a23SMark Brown 	{ 0x062E, 0x0000 },   /* R1582  - AIF1TX2MIX Input 4 Source */
277d5315a23SMark Brown 	{ 0x062F, 0x0080 },   /* R1583  - AIF1TX2MIX Input 4 Volume */
278d5315a23SMark Brown 	{ 0x0630, 0x0000 },   /* R1584  - AIF1TX3MIX Input 1 Source */
279d5315a23SMark Brown 	{ 0x0631, 0x0080 },   /* R1585  - AIF1TX3MIX Input 1 Volume */
280d5315a23SMark Brown 	{ 0x0632, 0x0000 },   /* R1586  - AIF1TX3MIX Input 2 Source */
281d5315a23SMark Brown 	{ 0x0633, 0x0080 },   /* R1587  - AIF1TX3MIX Input 2 Volume */
282d5315a23SMark Brown 	{ 0x0634, 0x0000 },   /* R1588  - AIF1TX3MIX Input 3 Source */
283d5315a23SMark Brown 	{ 0x0635, 0x0080 },   /* R1589  - AIF1TX3MIX Input 3 Volume */
284d5315a23SMark Brown 	{ 0x0636, 0x0000 },   /* R1590  - AIF1TX3MIX Input 4 Source */
285d5315a23SMark Brown 	{ 0x0637, 0x0080 },   /* R1591  - AIF1TX3MIX Input 4 Volume */
286d5315a23SMark Brown 	{ 0x0638, 0x0000 },   /* R1592  - AIF1TX4MIX Input 1 Source */
287d5315a23SMark Brown 	{ 0x0639, 0x0080 },   /* R1593  - AIF1TX4MIX Input 1 Volume */
288d5315a23SMark Brown 	{ 0x063A, 0x0000 },   /* R1594  - AIF1TX4MIX Input 2 Source */
289d5315a23SMark Brown 	{ 0x063B, 0x0080 },   /* R1595  - AIF1TX4MIX Input 2 Volume */
290d5315a23SMark Brown 	{ 0x063C, 0x0000 },   /* R1596  - AIF1TX4MIX Input 3 Source */
291d5315a23SMark Brown 	{ 0x063D, 0x0080 },   /* R1597  - AIF1TX4MIX Input 3 Volume */
292d5315a23SMark Brown 	{ 0x063E, 0x0000 },   /* R1598  - AIF1TX4MIX Input 4 Source */
293d5315a23SMark Brown 	{ 0x063F, 0x0080 },   /* R1599  - AIF1TX4MIX Input 4 Volume */
294d5315a23SMark Brown 	{ 0x0640, 0x0000 },   /* R1600  - AIF1TX5MIX Input 1 Source */
295d5315a23SMark Brown 	{ 0x0641, 0x0080 },   /* R1601  - AIF1TX5MIX Input 1 Volume */
296d5315a23SMark Brown 	{ 0x0642, 0x0000 },   /* R1602  - AIF1TX5MIX Input 2 Source */
297d5315a23SMark Brown 	{ 0x0643, 0x0080 },   /* R1603  - AIF1TX5MIX Input 2 Volume */
298d5315a23SMark Brown 	{ 0x0644, 0x0000 },   /* R1604  - AIF1TX5MIX Input 3 Source */
299d5315a23SMark Brown 	{ 0x0645, 0x0080 },   /* R1605  - AIF1TX5MIX Input 3 Volume */
300d5315a23SMark Brown 	{ 0x0646, 0x0000 },   /* R1606  - AIF1TX5MIX Input 4 Source */
301d5315a23SMark Brown 	{ 0x0647, 0x0080 },   /* R1607  - AIF1TX5MIX Input 4 Volume */
302d5315a23SMark Brown 	{ 0x0648, 0x0000 },   /* R1608  - AIF1TX6MIX Input 1 Source */
303d5315a23SMark Brown 	{ 0x0649, 0x0080 },   /* R1609  - AIF1TX6MIX Input 1 Volume */
304d5315a23SMark Brown 	{ 0x064A, 0x0000 },   /* R1610  - AIF1TX6MIX Input 2 Source */
305d5315a23SMark Brown 	{ 0x064B, 0x0080 },   /* R1611  - AIF1TX6MIX Input 2 Volume */
306d5315a23SMark Brown 	{ 0x064C, 0x0000 },   /* R1612  - AIF1TX6MIX Input 3 Source */
307d5315a23SMark Brown 	{ 0x064D, 0x0080 },   /* R1613  - AIF1TX6MIX Input 3 Volume */
308d5315a23SMark Brown 	{ 0x064E, 0x0000 },   /* R1614  - AIF1TX6MIX Input 4 Source */
309d5315a23SMark Brown 	{ 0x064F, 0x0080 },   /* R1615  - AIF1TX6MIX Input 4 Volume */
310d5315a23SMark Brown 	{ 0x0650, 0x0000 },   /* R1616  - EQLMIX Input 1 Source */
311d5315a23SMark Brown 	{ 0x0651, 0x0080 },   /* R1617  - EQLMIX Input 1 Volume */
312d5315a23SMark Brown 	{ 0x0652, 0x0000 },   /* R1618  - EQLMIX Input 2 Source */
313d5315a23SMark Brown 	{ 0x0653, 0x0080 },   /* R1619  - EQLMIX Input 2 Volume */
314d5315a23SMark Brown 	{ 0x0654, 0x0000 },   /* R1620  - EQLMIX Input 3 Source */
315d5315a23SMark Brown 	{ 0x0655, 0x0080 },   /* R1621  - EQLMIX Input 3 Volume */
316d5315a23SMark Brown 	{ 0x0656, 0x0000 },   /* R1622  - EQLMIX Input 4 Source */
317d5315a23SMark Brown 	{ 0x0657, 0x0080 },   /* R1623  - EQLMIX Input 4 Volume */
318d5315a23SMark Brown 	{ 0x0658, 0x0000 },   /* R1624  - EQRMIX Input 1 Source */
319d5315a23SMark Brown 	{ 0x0659, 0x0080 },   /* R1625  - EQRMIX Input 1 Volume */
320d5315a23SMark Brown 	{ 0x065A, 0x0000 },   /* R1626  - EQRMIX Input 2 Source */
321d5315a23SMark Brown 	{ 0x065B, 0x0080 },   /* R1627  - EQRMIX Input 2 Volume */
322d5315a23SMark Brown 	{ 0x065C, 0x0000 },   /* R1628  - EQRMIX Input 3 Source */
323d5315a23SMark Brown 	{ 0x065D, 0x0080 },   /* R1629  - EQRMIX Input 3 Volume */
324d5315a23SMark Brown 	{ 0x065E, 0x0000 },   /* R1630  - EQRMIX Input 4 Source */
325d5315a23SMark Brown 	{ 0x065F, 0x0080 },   /* R1631  - EQRMIX Input 4 Volume */
326d5315a23SMark Brown 	{ 0x0660, 0x0000 },   /* R1632  - LHPF1MIX Input 1 Source */
327d5315a23SMark Brown 	{ 0x0661, 0x0080 },   /* R1633  - LHPF1MIX Input 1 Volume */
328d5315a23SMark Brown 	{ 0x0662, 0x0000 },   /* R1634  - LHPF1MIX Input 2 Source */
329d5315a23SMark Brown 	{ 0x0663, 0x0080 },   /* R1635  - LHPF1MIX Input 2 Volume */
330d5315a23SMark Brown 	{ 0x0664, 0x0000 },   /* R1636  - LHPF1MIX Input 3 Source */
331d5315a23SMark Brown 	{ 0x0665, 0x0080 },   /* R1637  - LHPF1MIX Input 3 Volume */
332d5315a23SMark Brown 	{ 0x0666, 0x0000 },   /* R1638  - LHPF1MIX Input 4 Source */
333d5315a23SMark Brown 	{ 0x0667, 0x0080 },   /* R1639  - LHPF1MIX Input 4 Volume */
334d5315a23SMark Brown 	{ 0x0668, 0x0000 },   /* R1640  - LHPF2MIX Input 1 Source */
335d5315a23SMark Brown 	{ 0x0669, 0x0080 },   /* R1641  - LHPF2MIX Input 1 Volume */
336d5315a23SMark Brown 	{ 0x066A, 0x0000 },   /* R1642  - LHPF2MIX Input 2 Source */
337d5315a23SMark Brown 	{ 0x066B, 0x0080 },   /* R1643  - LHPF2MIX Input 2 Volume */
338d5315a23SMark Brown 	{ 0x066C, 0x0000 },   /* R1644  - LHPF2MIX Input 3 Source */
339d5315a23SMark Brown 	{ 0x066D, 0x0080 },   /* R1645  - LHPF2MIX Input 3 Volume */
340d5315a23SMark Brown 	{ 0x066E, 0x0000 },   /* R1646  - LHPF2MIX Input 4 Source */
341d5315a23SMark Brown 	{ 0x066F, 0x0080 },   /* R1647  - LHPF2MIX Input 4 Volume */
342d5315a23SMark Brown 	{ 0x0670, 0x0000 },   /* R1648  - DSP1LMIX Input 1 Source */
343d5315a23SMark Brown 	{ 0x0671, 0x0080 },   /* R1649  - DSP1LMIX Input 1 Volume */
344d5315a23SMark Brown 	{ 0x0672, 0x0000 },   /* R1650  - DSP1LMIX Input 2 Source */
345d5315a23SMark Brown 	{ 0x0673, 0x0080 },   /* R1651  - DSP1LMIX Input 2 Volume */
346d5315a23SMark Brown 	{ 0x0674, 0x0000 },   /* R1652  - DSP1LMIX Input 3 Source */
347d5315a23SMark Brown 	{ 0x0675, 0x0080 },   /* R1653  - DSP1LMIX Input 3 Volume */
348d5315a23SMark Brown 	{ 0x0676, 0x0000 },   /* R1654  - DSP1LMIX Input 4 Source */
349d5315a23SMark Brown 	{ 0x0677, 0x0080 },   /* R1655  - DSP1LMIX Input 4 Volume */
350d5315a23SMark Brown 	{ 0x0678, 0x0000 },   /* R1656  - DSP1RMIX Input 1 Source */
351d5315a23SMark Brown 	{ 0x0679, 0x0080 },   /* R1657  - DSP1RMIX Input 1 Volume */
352d5315a23SMark Brown 	{ 0x067A, 0x0000 },   /* R1658  - DSP1RMIX Input 2 Source */
353d5315a23SMark Brown 	{ 0x067B, 0x0080 },   /* R1659  - DSP1RMIX Input 2 Volume */
354d5315a23SMark Brown 	{ 0x067C, 0x0000 },   /* R1660  - DSP1RMIX Input 3 Source */
355d5315a23SMark Brown 	{ 0x067D, 0x0080 },   /* R1661  - DSP1RMIX Input 3 Volume */
356d5315a23SMark Brown 	{ 0x067E, 0x0000 },   /* R1662  - DSP1RMIX Input 4 Source */
357d5315a23SMark Brown 	{ 0x067F, 0x0080 },   /* R1663  - DSP1RMIX Input 4 Volume */
358d5315a23SMark Brown 	{ 0x0680, 0x0000 },   /* R1664  - DSP1AUX1MIX Input 1 Source */
359d5315a23SMark Brown 	{ 0x0681, 0x0000 },   /* R1665  - DSP1AUX2MIX Input 1 Source */
360d5315a23SMark Brown 	{ 0x0682, 0x0000 },   /* R1666  - DSP1AUX3MIX Input 1 Source */
361d5315a23SMark Brown 	{ 0x0683, 0x0000 },   /* R1667  - DSP1AUX4MIX Input 1 Source */
362d5315a23SMark Brown 	{ 0x0684, 0x0000 },   /* R1668  - DSP1AUX5MIX Input 1 Source */
363d5315a23SMark Brown 	{ 0x0685, 0x0000 },   /* R1669  - DSP1AUX6MIX Input 1 Source */
364d5315a23SMark Brown 	{ 0x0686, 0x0000 },   /* R1670  - DSP2LMIX Input 1 Source */
365d5315a23SMark Brown 	{ 0x0687, 0x0080 },   /* R1671  - DSP2LMIX Input 1 Volume */
366d5315a23SMark Brown 	{ 0x0688, 0x0000 },   /* R1672  - DSP2LMIX Input 2 Source */
367d5315a23SMark Brown 	{ 0x0689, 0x0080 },   /* R1673  - DSP2LMIX Input 2 Volume */
368d5315a23SMark Brown 	{ 0x068A, 0x0000 },   /* R1674  - DSP2LMIX Input 3 Source */
369d5315a23SMark Brown 	{ 0x068B, 0x0080 },   /* R1675  - DSP2LMIX Input 3 Volume */
370d5315a23SMark Brown 	{ 0x068C, 0x0000 },   /* R1676  - DSP2LMIX Input 4 Source */
371d5315a23SMark Brown 	{ 0x068D, 0x0080 },   /* R1677  - DSP2LMIX Input 4 Volume */
372d5315a23SMark Brown 	{ 0x068E, 0x0000 },   /* R1678  - DSP2RMIX Input 1 Source */
373d5315a23SMark Brown 	{ 0x068F, 0x0080 },   /* R1679  - DSP2RMIX Input 1 Volume */
374d5315a23SMark Brown 	{ 0x0690, 0x0000 },   /* R1680  - DSP2RMIX Input 2 Source */
375d5315a23SMark Brown 	{ 0x0691, 0x0080 },   /* R1681  - DSP2RMIX Input 2 Volume */
376d5315a23SMark Brown 	{ 0x0692, 0x0000 },   /* R1682  - DSP2RMIX Input 3 Source */
377d5315a23SMark Brown 	{ 0x0693, 0x0080 },   /* R1683  - DSP2RMIX Input 3 Volume */
378d5315a23SMark Brown 	{ 0x0694, 0x0000 },   /* R1684  - DSP2RMIX Input 4 Source */
379d5315a23SMark Brown 	{ 0x0695, 0x0080 },   /* R1685  - DSP2RMIX Input 4 Volume */
380d5315a23SMark Brown 	{ 0x0696, 0x0000 },   /* R1686  - DSP2AUX1MIX Input 1 Source */
381d5315a23SMark Brown 	{ 0x0697, 0x0000 },   /* R1687  - DSP2AUX2MIX Input 1 Source */
382d5315a23SMark Brown 	{ 0x0698, 0x0000 },   /* R1688  - DSP2AUX3MIX Input 1 Source */
383d5315a23SMark Brown 	{ 0x0699, 0x0000 },   /* R1689  - DSP2AUX4MIX Input 1 Source */
384d5315a23SMark Brown 	{ 0x069A, 0x0000 },   /* R1690  - DSP2AUX5MIX Input 1 Source */
385d5315a23SMark Brown 	{ 0x069B, 0x0000 },   /* R1691  - DSP2AUX6MIX Input 1 Source */
386d5315a23SMark Brown 	{ 0x0700, 0xA101 },   /* R1792  - GPIO CTRL 1 */
387d5315a23SMark Brown 	{ 0x0701, 0xA101 },   /* R1793  - GPIO CTRL 2 */
388d5315a23SMark Brown 	{ 0x0702, 0xA101 },   /* R1794  - GPIO CTRL 3 */
389d5315a23SMark Brown 	{ 0x0703, 0xA101 },   /* R1795  - GPIO CTRL 4 */
390d5315a23SMark Brown 	{ 0x0709, 0x0000 },   /* R1801  - Misc Pad Ctrl 1 */
391d5315a23SMark Brown 	{ 0x0801, 0x00FF },   /* R2049  - Interrupt Status 1 Mask */
392d5315a23SMark Brown 	{ 0x0804, 0xFFFF },   /* R2052  - Interrupt Status 2 Mask */
393d5315a23SMark Brown 	{ 0x0808, 0x0000 },   /* R2056  - Interrupt Control */
394d5315a23SMark Brown 	{ 0x0900, 0x0000 },   /* R2304  - EQL_1 */
395d5315a23SMark Brown 	{ 0x0901, 0x0000 },   /* R2305  - EQL_2 */
396d5315a23SMark Brown 	{ 0x0902, 0x0000 },   /* R2306  - EQL_3 */
397d5315a23SMark Brown 	{ 0x0903, 0x0000 },   /* R2307  - EQL_4 */
398d5315a23SMark Brown 	{ 0x0904, 0x0000 },   /* R2308  - EQL_5 */
399d5315a23SMark Brown 	{ 0x0905, 0x0000 },   /* R2309  - EQL_6 */
400d5315a23SMark Brown 	{ 0x0906, 0x0000 },   /* R2310  - EQL_7 */
401d5315a23SMark Brown 	{ 0x0907, 0x0000 },   /* R2311  - EQL_8 */
402d5315a23SMark Brown 	{ 0x0908, 0x0000 },   /* R2312  - EQL_9 */
403d5315a23SMark Brown 	{ 0x0909, 0x0000 },   /* R2313  - EQL_10 */
404d5315a23SMark Brown 	{ 0x090A, 0x0000 },   /* R2314  - EQL_11 */
405d5315a23SMark Brown 	{ 0x090B, 0x0000 },   /* R2315  - EQL_12 */
406d5315a23SMark Brown 	{ 0x090C, 0x0000 },   /* R2316  - EQL_13 */
407d5315a23SMark Brown 	{ 0x090D, 0x0000 },   /* R2317  - EQL_14 */
408d5315a23SMark Brown 	{ 0x090E, 0x0000 },   /* R2318  - EQL_15 */
409d5315a23SMark Brown 	{ 0x090F, 0x0000 },   /* R2319  - EQL_16 */
410d5315a23SMark Brown 	{ 0x0910, 0x0000 },   /* R2320  - EQL_17 */
411d5315a23SMark Brown 	{ 0x0911, 0x0000 },   /* R2321  - EQL_18 */
412d5315a23SMark Brown 	{ 0x0912, 0x0000 },   /* R2322  - EQL_19 */
413d5315a23SMark Brown 	{ 0x0913, 0x0000 },   /* R2323  - EQL_20 */
414d5315a23SMark Brown 	{ 0x0916, 0x0000 },   /* R2326  - EQR_1 */
415d5315a23SMark Brown 	{ 0x0917, 0x0000 },   /* R2327  - EQR_2 */
416d5315a23SMark Brown 	{ 0x0918, 0x0000 },   /* R2328  - EQR_3 */
417d5315a23SMark Brown 	{ 0x0919, 0x0000 },   /* R2329  - EQR_4 */
418d5315a23SMark Brown 	{ 0x091A, 0x0000 },   /* R2330  - EQR_5 */
419d5315a23SMark Brown 	{ 0x091B, 0x0000 },   /* R2331  - EQR_6 */
420d5315a23SMark Brown 	{ 0x091C, 0x0000 },   /* R2332  - EQR_7 */
421d5315a23SMark Brown 	{ 0x091D, 0x0000 },   /* R2333  - EQR_8 */
422d5315a23SMark Brown 	{ 0x091E, 0x0000 },   /* R2334  - EQR_9 */
423d5315a23SMark Brown 	{ 0x091F, 0x0000 },   /* R2335  - EQR_10 */
424d5315a23SMark Brown 	{ 0x0920, 0x0000 },   /* R2336  - EQR_11 */
425d5315a23SMark Brown 	{ 0x0921, 0x0000 },   /* R2337  - EQR_12 */
426d5315a23SMark Brown 	{ 0x0922, 0x0000 },   /* R2338  - EQR_13 */
427d5315a23SMark Brown 	{ 0x0923, 0x0000 },   /* R2339  - EQR_14 */
428d5315a23SMark Brown 	{ 0x0924, 0x0000 },   /* R2340  - EQR_15 */
429d5315a23SMark Brown 	{ 0x0925, 0x0000 },   /* R2341  - EQR_16 */
430d5315a23SMark Brown 	{ 0x0926, 0x0000 },   /* R2342  - EQR_17 */
431d5315a23SMark Brown 	{ 0x0927, 0x0000 },   /* R2343  - EQR_18 */
432d5315a23SMark Brown 	{ 0x0928, 0x0000 },   /* R2344  - EQR_19 */
433d5315a23SMark Brown 	{ 0x0929, 0x0000 },   /* R2345  - EQR_20 */
434d5315a23SMark Brown 	{ 0x093E, 0x0000 },   /* R2366  - HPLPF1_1 */
435d5315a23SMark Brown 	{ 0x093F, 0x0000 },   /* R2367  - HPLPF1_2 */
436d5315a23SMark Brown 	{ 0x0942, 0x0000 },   /* R2370  - HPLPF2_1 */
437d5315a23SMark Brown 	{ 0x0943, 0x0000 },   /* R2371  - HPLPF2_2 */
438d5315a23SMark Brown 	{ 0x0A00, 0x0000 },   /* R2560  - DSP1 Control 1 */
439d5315a23SMark Brown 	{ 0x0A02, 0x0000 },   /* R2562  - DSP1 Control 2 */
440d5315a23SMark Brown 	{ 0x0A03, 0x0000 },   /* R2563  - DSP1 Control 3 */
441d5315a23SMark Brown 	{ 0x0A04, 0x0000 },   /* R2564  - DSP1 Control 4 */
442d5315a23SMark Brown 	{ 0x0A06, 0x0000 },   /* R2566  - DSP1 Control 5 */
443d5315a23SMark Brown 	{ 0x0A07, 0x0000 },   /* R2567  - DSP1 Control 6 */
444d5315a23SMark Brown 	{ 0x0A08, 0x0000 },   /* R2568  - DSP1 Control 7 */
445d5315a23SMark Brown 	{ 0x0A09, 0x0000 },   /* R2569  - DSP1 Control 8 */
446d5315a23SMark Brown 	{ 0x0A0A, 0x0000 },   /* R2570  - DSP1 Control 9 */
447d5315a23SMark Brown 	{ 0x0A0B, 0x0000 },   /* R2571  - DSP1 Control 10 */
448d5315a23SMark Brown 	{ 0x0A0C, 0x0000 },   /* R2572  - DSP1 Control 11 */
449d5315a23SMark Brown 	{ 0x0A0D, 0x0000 },   /* R2573  - DSP1 Control 12 */
450d5315a23SMark Brown 	{ 0x0A0F, 0x0000 },   /* R2575  - DSP1 Control 13 */
451d5315a23SMark Brown 	{ 0x0A10, 0x0000 },   /* R2576  - DSP1 Control 14 */
452d5315a23SMark Brown 	{ 0x0A11, 0x0000 },   /* R2577  - DSP1 Control 15 */
453d5315a23SMark Brown 	{ 0x0A12, 0x0000 },   /* R2578  - DSP1 Control 16 */
454d5315a23SMark Brown 	{ 0x0A13, 0x0000 },   /* R2579  - DSP1 Control 17 */
455d5315a23SMark Brown 	{ 0x0A14, 0x0000 },   /* R2580  - DSP1 Control 18 */
456d5315a23SMark Brown 	{ 0x0A16, 0x0000 },   /* R2582  - DSP1 Control 19 */
457d5315a23SMark Brown 	{ 0x0A17, 0x0000 },   /* R2583  - DSP1 Control 20 */
458d5315a23SMark Brown 	{ 0x0A18, 0x0000 },   /* R2584  - DSP1 Control 21 */
459d5315a23SMark Brown 	{ 0x0A1A, 0x1800 },   /* R2586  - DSP1 Control 22 */
460d5315a23SMark Brown 	{ 0x0A1B, 0x1000 },   /* R2587  - DSP1 Control 23 */
461d5315a23SMark Brown 	{ 0x0A1C, 0x0400 },   /* R2588  - DSP1 Control 24 */
462d5315a23SMark Brown 	{ 0x0A1E, 0x0000 },   /* R2590  - DSP1 Control 25 */
463d5315a23SMark Brown 	{ 0x0A20, 0x0000 },   /* R2592  - DSP1 Control 26 */
464d5315a23SMark Brown 	{ 0x0A21, 0x0000 },   /* R2593  - DSP1 Control 27 */
465d5315a23SMark Brown 	{ 0x0A22, 0x0000 },   /* R2594  - DSP1 Control 28 */
466d5315a23SMark Brown 	{ 0x0A23, 0x0000 },   /* R2595  - DSP1 Control 29 */
467d5315a23SMark Brown 	{ 0x0A24, 0x0000 },   /* R2596  - DSP1 Control 30 */
468d5315a23SMark Brown 	{ 0x0A26, 0x0000 },   /* R2598  - DSP1 Control 31 */
469d5315a23SMark Brown 	{ 0x0B00, 0x0000 },   /* R2816  - DSP2 Control 1 */
470d5315a23SMark Brown 	{ 0x0B02, 0x0000 },   /* R2818  - DSP2 Control 2 */
471d5315a23SMark Brown 	{ 0x0B03, 0x0000 },   /* R2819  - DSP2 Control 3 */
472d5315a23SMark Brown 	{ 0x0B04, 0x0000 },   /* R2820  - DSP2 Control 4 */
473d5315a23SMark Brown 	{ 0x0B06, 0x0000 },   /* R2822  - DSP2 Control 5 */
474d5315a23SMark Brown 	{ 0x0B07, 0x0000 },   /* R2823  - DSP2 Control 6 */
475d5315a23SMark Brown 	{ 0x0B08, 0x0000 },   /* R2824  - DSP2 Control 7 */
476d5315a23SMark Brown 	{ 0x0B09, 0x0000 },   /* R2825  - DSP2 Control 8 */
477d5315a23SMark Brown 	{ 0x0B0A, 0x0000 },   /* R2826  - DSP2 Control 9 */
478d5315a23SMark Brown 	{ 0x0B0B, 0x0000 },   /* R2827  - DSP2 Control 10 */
479d5315a23SMark Brown 	{ 0x0B0C, 0x0000 },   /* R2828  - DSP2 Control 11 */
480d5315a23SMark Brown 	{ 0x0B0D, 0x0000 },   /* R2829  - DSP2 Control 12 */
481d5315a23SMark Brown 	{ 0x0B0F, 0x0000 },   /* R2831  - DSP2 Control 13 */
482d5315a23SMark Brown 	{ 0x0B10, 0x0000 },   /* R2832  - DSP2 Control 14 */
483d5315a23SMark Brown 	{ 0x0B11, 0x0000 },   /* R2833  - DSP2 Control 15 */
484d5315a23SMark Brown 	{ 0x0B12, 0x0000 },   /* R2834  - DSP2 Control 16 */
485d5315a23SMark Brown 	{ 0x0B13, 0x0000 },   /* R2835  - DSP2 Control 17 */
486d5315a23SMark Brown 	{ 0x0B14, 0x0000 },   /* R2836  - DSP2 Control 18 */
487d5315a23SMark Brown 	{ 0x0B16, 0x0000 },   /* R2838  - DSP2 Control 19 */
488d5315a23SMark Brown 	{ 0x0B17, 0x0000 },   /* R2839  - DSP2 Control 20 */
489d5315a23SMark Brown 	{ 0x0B18, 0x0000 },   /* R2840  - DSP2 Control 21 */
490d5315a23SMark Brown 	{ 0x0B1A, 0x0800 },   /* R2842  - DSP2 Control 22 */
491d5315a23SMark Brown 	{ 0x0B1B, 0x1000 },   /* R2843  - DSP2 Control 23 */
492d5315a23SMark Brown 	{ 0x0B1C, 0x0400 },   /* R2844  - DSP2 Control 24 */
493d5315a23SMark Brown 	{ 0x0B1E, 0x0000 },   /* R2846  - DSP2 Control 25 */
494d5315a23SMark Brown 	{ 0x0B20, 0x0000 },   /* R2848  - DSP2 Control 26 */
495d5315a23SMark Brown 	{ 0x0B21, 0x0000 },   /* R2849  - DSP2 Control 27 */
496d5315a23SMark Brown 	{ 0x0B22, 0x0000 },   /* R2850  - DSP2 Control 28 */
497d5315a23SMark Brown 	{ 0x0B23, 0x0000 },   /* R2851  - DSP2 Control 29 */
498d5315a23SMark Brown 	{ 0x0B24, 0x0000 },   /* R2852  - DSP2 Control 30 */
499d5315a23SMark Brown 	{ 0x0B26, 0x0000 },   /* R2854  - DSP2 Control 31 */
500d5315a23SMark Brown };
501d5315a23SMark Brown 
502d5315a23SMark Brown static bool wm2200_volatile_register(struct device *dev, unsigned int reg)
503d5315a23SMark Brown {
504eae2328dSMark Brown 	int i;
505eae2328dSMark Brown 
506eae2328dSMark Brown 	for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++)
507eae2328dSMark Brown 		if ((reg >= wm2200_ranges[i].window_start &&
508eae2328dSMark Brown 		     reg <= wm2200_ranges[i].window_start +
509eae2328dSMark Brown 		     wm2200_ranges[i].window_len) ||
510eae2328dSMark Brown 		    (reg >= wm2200_ranges[i].range_min &&
511eae2328dSMark Brown 		     reg <= wm2200_ranges[i].range_max))
512eae2328dSMark Brown 			return true;
513eae2328dSMark Brown 
514d5315a23SMark Brown 	switch (reg) {
515d5315a23SMark Brown 	case WM2200_SOFTWARE_RESET:
516d5315a23SMark Brown 	case WM2200_DEVICE_REVISION:
517d5315a23SMark Brown 	case WM2200_ADPS1_IRQ0:
518d5315a23SMark Brown 	case WM2200_ADPS1_IRQ1:
519d5315a23SMark Brown 	case WM2200_INTERRUPT_STATUS_1:
520d5315a23SMark Brown 	case WM2200_INTERRUPT_STATUS_2:
521d5315a23SMark Brown 	case WM2200_INTERRUPT_RAW_STATUS_2:
522d5315a23SMark Brown 		return true;
523d5315a23SMark Brown 	default:
524d5315a23SMark Brown 		return false;
525d5315a23SMark Brown 	}
526d5315a23SMark Brown }
527d5315a23SMark Brown 
528d5315a23SMark Brown static bool wm2200_readable_register(struct device *dev, unsigned int reg)
529d5315a23SMark Brown {
530eae2328dSMark Brown 	int i;
531eae2328dSMark Brown 
532eae2328dSMark Brown 	for (i = 0; i < ARRAY_SIZE(wm2200_ranges); i++)
533eae2328dSMark Brown 		if ((reg >= wm2200_ranges[i].window_start &&
534eae2328dSMark Brown 		     reg <= wm2200_ranges[i].window_start +
535eae2328dSMark Brown 		     wm2200_ranges[i].window_len) ||
536eae2328dSMark Brown 		    (reg >= wm2200_ranges[i].range_min &&
537eae2328dSMark Brown 		     reg <= wm2200_ranges[i].range_max))
538eae2328dSMark Brown 			return true;
539eae2328dSMark Brown 
540d5315a23SMark Brown 	switch (reg) {
541d5315a23SMark Brown 	case WM2200_SOFTWARE_RESET:
542d5315a23SMark Brown 	case WM2200_DEVICE_REVISION:
543d5315a23SMark Brown 	case WM2200_TONE_GENERATOR_1:
544d5315a23SMark Brown 	case WM2200_CLOCKING_3:
545d5315a23SMark Brown 	case WM2200_CLOCKING_4:
546d5315a23SMark Brown 	case WM2200_FLL_CONTROL_1:
547d5315a23SMark Brown 	case WM2200_FLL_CONTROL_2:
548d5315a23SMark Brown 	case WM2200_FLL_CONTROL_3:
549d5315a23SMark Brown 	case WM2200_FLL_CONTROL_4:
550d5315a23SMark Brown 	case WM2200_FLL_CONTROL_6:
551d5315a23SMark Brown 	case WM2200_FLL_CONTROL_7:
552d5315a23SMark Brown 	case WM2200_FLL_EFS_1:
553d5315a23SMark Brown 	case WM2200_FLL_EFS_2:
554d5315a23SMark Brown 	case WM2200_MIC_CHARGE_PUMP_1:
555d5315a23SMark Brown 	case WM2200_MIC_CHARGE_PUMP_2:
556d5315a23SMark Brown 	case WM2200_DM_CHARGE_PUMP_1:
557d5315a23SMark Brown 	case WM2200_MIC_BIAS_CTRL_1:
558d5315a23SMark Brown 	case WM2200_MIC_BIAS_CTRL_2:
559d5315a23SMark Brown 	case WM2200_EAR_PIECE_CTRL_1:
560d5315a23SMark Brown 	case WM2200_EAR_PIECE_CTRL_2:
561d5315a23SMark Brown 	case WM2200_INPUT_ENABLES:
562d5315a23SMark Brown 	case WM2200_IN1L_CONTROL:
563d5315a23SMark Brown 	case WM2200_IN1R_CONTROL:
564d5315a23SMark Brown 	case WM2200_IN2L_CONTROL:
565d5315a23SMark Brown 	case WM2200_IN2R_CONTROL:
566d5315a23SMark Brown 	case WM2200_IN3L_CONTROL:
567d5315a23SMark Brown 	case WM2200_IN3R_CONTROL:
568d5315a23SMark Brown 	case WM2200_RXANC_SRC:
569d5315a23SMark Brown 	case WM2200_INPUT_VOLUME_RAMP:
570d5315a23SMark Brown 	case WM2200_ADC_DIGITAL_VOLUME_1L:
571d5315a23SMark Brown 	case WM2200_ADC_DIGITAL_VOLUME_1R:
572d5315a23SMark Brown 	case WM2200_ADC_DIGITAL_VOLUME_2L:
573d5315a23SMark Brown 	case WM2200_ADC_DIGITAL_VOLUME_2R:
574d5315a23SMark Brown 	case WM2200_ADC_DIGITAL_VOLUME_3L:
575d5315a23SMark Brown 	case WM2200_ADC_DIGITAL_VOLUME_3R:
576d5315a23SMark Brown 	case WM2200_OUTPUT_ENABLES:
577d5315a23SMark Brown 	case WM2200_DAC_VOLUME_LIMIT_1L:
578d5315a23SMark Brown 	case WM2200_DAC_VOLUME_LIMIT_1R:
579d5315a23SMark Brown 	case WM2200_DAC_VOLUME_LIMIT_2L:
580d5315a23SMark Brown 	case WM2200_DAC_VOLUME_LIMIT_2R:
581d5315a23SMark Brown 	case WM2200_DAC_AEC_CONTROL_1:
582d5315a23SMark Brown 	case WM2200_OUTPUT_VOLUME_RAMP:
583d5315a23SMark Brown 	case WM2200_DAC_DIGITAL_VOLUME_1L:
584d5315a23SMark Brown 	case WM2200_DAC_DIGITAL_VOLUME_1R:
585d5315a23SMark Brown 	case WM2200_DAC_DIGITAL_VOLUME_2L:
586d5315a23SMark Brown 	case WM2200_DAC_DIGITAL_VOLUME_2R:
587d5315a23SMark Brown 	case WM2200_PDM_1:
588d5315a23SMark Brown 	case WM2200_PDM_2:
589d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_1:
590d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_2:
591d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_3:
592d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_4:
593d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_5:
594d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_6:
595d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_7:
596d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_8:
597d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_9:
598d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_10:
599d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_11:
600d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_12:
601d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_13:
602d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_14:
603d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_15:
604d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_16:
605d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_17:
606d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_18:
607d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_19:
608d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_20:
609d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_21:
610d5315a23SMark Brown 	case WM2200_AUDIO_IF_1_22:
611d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_1_SOURCE:
612d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_1_VOLUME:
613d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_2_SOURCE:
614d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_2_VOLUME:
615d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_3_SOURCE:
616d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_3_VOLUME:
617d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_4_SOURCE:
618d5315a23SMark Brown 	case WM2200_OUT1LMIX_INPUT_4_VOLUME:
619d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_1_SOURCE:
620d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_1_VOLUME:
621d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_2_SOURCE:
622d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_2_VOLUME:
623d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_3_SOURCE:
624d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_3_VOLUME:
625d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_4_SOURCE:
626d5315a23SMark Brown 	case WM2200_OUT1RMIX_INPUT_4_VOLUME:
627d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_1_SOURCE:
628d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_1_VOLUME:
629d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_2_SOURCE:
630d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_2_VOLUME:
631d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_3_SOURCE:
632d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_3_VOLUME:
633d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_4_SOURCE:
634d5315a23SMark Brown 	case WM2200_OUT2LMIX_INPUT_4_VOLUME:
635d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_1_SOURCE:
636d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_1_VOLUME:
637d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_2_SOURCE:
638d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_2_VOLUME:
639d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_3_SOURCE:
640d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_3_VOLUME:
641d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_4_SOURCE:
642d5315a23SMark Brown 	case WM2200_OUT2RMIX_INPUT_4_VOLUME:
643d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_1_SOURCE:
644d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_1_VOLUME:
645d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_2_SOURCE:
646d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_2_VOLUME:
647d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_3_SOURCE:
648d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_3_VOLUME:
649d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_4_SOURCE:
650d5315a23SMark Brown 	case WM2200_AIF1TX1MIX_INPUT_4_VOLUME:
651d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_1_SOURCE:
652d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_1_VOLUME:
653d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_2_SOURCE:
654d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_2_VOLUME:
655d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_3_SOURCE:
656d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_3_VOLUME:
657d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_4_SOURCE:
658d5315a23SMark Brown 	case WM2200_AIF1TX2MIX_INPUT_4_VOLUME:
659d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_1_SOURCE:
660d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_1_VOLUME:
661d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_2_SOURCE:
662d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_2_VOLUME:
663d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_3_SOURCE:
664d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_3_VOLUME:
665d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_4_SOURCE:
666d5315a23SMark Brown 	case WM2200_AIF1TX3MIX_INPUT_4_VOLUME:
667d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_1_SOURCE:
668d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_1_VOLUME:
669d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_2_SOURCE:
670d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_2_VOLUME:
671d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_3_SOURCE:
672d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_3_VOLUME:
673d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_4_SOURCE:
674d5315a23SMark Brown 	case WM2200_AIF1TX4MIX_INPUT_4_VOLUME:
675d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_1_SOURCE:
676d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_1_VOLUME:
677d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_2_SOURCE:
678d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_2_VOLUME:
679d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_3_SOURCE:
680d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_3_VOLUME:
681d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_4_SOURCE:
682d5315a23SMark Brown 	case WM2200_AIF1TX5MIX_INPUT_4_VOLUME:
683d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_1_SOURCE:
684d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_1_VOLUME:
685d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_2_SOURCE:
686d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_2_VOLUME:
687d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_3_SOURCE:
688d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_3_VOLUME:
689d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_4_SOURCE:
690d5315a23SMark Brown 	case WM2200_AIF1TX6MIX_INPUT_4_VOLUME:
691d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_1_SOURCE:
692d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_1_VOLUME:
693d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_2_SOURCE:
694d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_2_VOLUME:
695d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_3_SOURCE:
696d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_3_VOLUME:
697d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_4_SOURCE:
698d5315a23SMark Brown 	case WM2200_EQLMIX_INPUT_4_VOLUME:
699d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_1_SOURCE:
700d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_1_VOLUME:
701d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_2_SOURCE:
702d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_2_VOLUME:
703d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_3_SOURCE:
704d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_3_VOLUME:
705d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_4_SOURCE:
706d5315a23SMark Brown 	case WM2200_EQRMIX_INPUT_4_VOLUME:
707d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_1_SOURCE:
708d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_1_VOLUME:
709d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_2_SOURCE:
710d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_2_VOLUME:
711d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_3_SOURCE:
712d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_3_VOLUME:
713d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_4_SOURCE:
714d5315a23SMark Brown 	case WM2200_LHPF1MIX_INPUT_4_VOLUME:
715d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_1_SOURCE:
716d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_1_VOLUME:
717d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_2_SOURCE:
718d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_2_VOLUME:
719d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_3_SOURCE:
720d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_3_VOLUME:
721d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_4_SOURCE:
722d5315a23SMark Brown 	case WM2200_LHPF2MIX_INPUT_4_VOLUME:
723d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_1_SOURCE:
724d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_1_VOLUME:
725d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_2_SOURCE:
726d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_2_VOLUME:
727d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_3_SOURCE:
728d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_3_VOLUME:
729d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_4_SOURCE:
730d5315a23SMark Brown 	case WM2200_DSP1LMIX_INPUT_4_VOLUME:
731d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_1_SOURCE:
732d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_1_VOLUME:
733d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_2_SOURCE:
734d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_2_VOLUME:
735d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_3_SOURCE:
736d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_3_VOLUME:
737d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_4_SOURCE:
738d5315a23SMark Brown 	case WM2200_DSP1RMIX_INPUT_4_VOLUME:
739d5315a23SMark Brown 	case WM2200_DSP1AUX1MIX_INPUT_1_SOURCE:
740d5315a23SMark Brown 	case WM2200_DSP1AUX2MIX_INPUT_1_SOURCE:
741d5315a23SMark Brown 	case WM2200_DSP1AUX3MIX_INPUT_1_SOURCE:
742d5315a23SMark Brown 	case WM2200_DSP1AUX4MIX_INPUT_1_SOURCE:
743d5315a23SMark Brown 	case WM2200_DSP1AUX5MIX_INPUT_1_SOURCE:
744d5315a23SMark Brown 	case WM2200_DSP1AUX6MIX_INPUT_1_SOURCE:
745d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_1_SOURCE:
746d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_1_VOLUME:
747d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_2_SOURCE:
748d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_2_VOLUME:
749d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_3_SOURCE:
750d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_3_VOLUME:
751d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_4_SOURCE:
752d5315a23SMark Brown 	case WM2200_DSP2LMIX_INPUT_4_VOLUME:
753d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_1_SOURCE:
754d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_1_VOLUME:
755d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_2_SOURCE:
756d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_2_VOLUME:
757d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_3_SOURCE:
758d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_3_VOLUME:
759d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_4_SOURCE:
760d5315a23SMark Brown 	case WM2200_DSP2RMIX_INPUT_4_VOLUME:
761d5315a23SMark Brown 	case WM2200_DSP2AUX1MIX_INPUT_1_SOURCE:
762d5315a23SMark Brown 	case WM2200_DSP2AUX2MIX_INPUT_1_SOURCE:
763d5315a23SMark Brown 	case WM2200_DSP2AUX3MIX_INPUT_1_SOURCE:
764d5315a23SMark Brown 	case WM2200_DSP2AUX4MIX_INPUT_1_SOURCE:
765d5315a23SMark Brown 	case WM2200_DSP2AUX5MIX_INPUT_1_SOURCE:
766d5315a23SMark Brown 	case WM2200_DSP2AUX6MIX_INPUT_1_SOURCE:
767d5315a23SMark Brown 	case WM2200_GPIO_CTRL_1:
768d5315a23SMark Brown 	case WM2200_GPIO_CTRL_2:
769d5315a23SMark Brown 	case WM2200_GPIO_CTRL_3:
770d5315a23SMark Brown 	case WM2200_GPIO_CTRL_4:
771d5315a23SMark Brown 	case WM2200_ADPS1_IRQ0:
772d5315a23SMark Brown 	case WM2200_ADPS1_IRQ1:
773d5315a23SMark Brown 	case WM2200_MISC_PAD_CTRL_1:
774d5315a23SMark Brown 	case WM2200_INTERRUPT_STATUS_1:
775d5315a23SMark Brown 	case WM2200_INTERRUPT_STATUS_1_MASK:
776d5315a23SMark Brown 	case WM2200_INTERRUPT_STATUS_2:
777d5315a23SMark Brown 	case WM2200_INTERRUPT_RAW_STATUS_2:
778d5315a23SMark Brown 	case WM2200_INTERRUPT_STATUS_2_MASK:
779d5315a23SMark Brown 	case WM2200_INTERRUPT_CONTROL:
780d5315a23SMark Brown 	case WM2200_EQL_1:
781d5315a23SMark Brown 	case WM2200_EQL_2:
782d5315a23SMark Brown 	case WM2200_EQL_3:
783d5315a23SMark Brown 	case WM2200_EQL_4:
784d5315a23SMark Brown 	case WM2200_EQL_5:
785d5315a23SMark Brown 	case WM2200_EQL_6:
786d5315a23SMark Brown 	case WM2200_EQL_7:
787d5315a23SMark Brown 	case WM2200_EQL_8:
788d5315a23SMark Brown 	case WM2200_EQL_9:
789d5315a23SMark Brown 	case WM2200_EQL_10:
790d5315a23SMark Brown 	case WM2200_EQL_11:
791d5315a23SMark Brown 	case WM2200_EQL_12:
792d5315a23SMark Brown 	case WM2200_EQL_13:
793d5315a23SMark Brown 	case WM2200_EQL_14:
794d5315a23SMark Brown 	case WM2200_EQL_15:
795d5315a23SMark Brown 	case WM2200_EQL_16:
796d5315a23SMark Brown 	case WM2200_EQL_17:
797d5315a23SMark Brown 	case WM2200_EQL_18:
798d5315a23SMark Brown 	case WM2200_EQL_19:
799d5315a23SMark Brown 	case WM2200_EQL_20:
800d5315a23SMark Brown 	case WM2200_EQR_1:
801d5315a23SMark Brown 	case WM2200_EQR_2:
802d5315a23SMark Brown 	case WM2200_EQR_3:
803d5315a23SMark Brown 	case WM2200_EQR_4:
804d5315a23SMark Brown 	case WM2200_EQR_5:
805d5315a23SMark Brown 	case WM2200_EQR_6:
806d5315a23SMark Brown 	case WM2200_EQR_7:
807d5315a23SMark Brown 	case WM2200_EQR_8:
808d5315a23SMark Brown 	case WM2200_EQR_9:
809d5315a23SMark Brown 	case WM2200_EQR_10:
810d5315a23SMark Brown 	case WM2200_EQR_11:
811d5315a23SMark Brown 	case WM2200_EQR_12:
812d5315a23SMark Brown 	case WM2200_EQR_13:
813d5315a23SMark Brown 	case WM2200_EQR_14:
814d5315a23SMark Brown 	case WM2200_EQR_15:
815d5315a23SMark Brown 	case WM2200_EQR_16:
816d5315a23SMark Brown 	case WM2200_EQR_17:
817d5315a23SMark Brown 	case WM2200_EQR_18:
818d5315a23SMark Brown 	case WM2200_EQR_19:
819d5315a23SMark Brown 	case WM2200_EQR_20:
820d5315a23SMark Brown 	case WM2200_HPLPF1_1:
821d5315a23SMark Brown 	case WM2200_HPLPF1_2:
822d5315a23SMark Brown 	case WM2200_HPLPF2_1:
823d5315a23SMark Brown 	case WM2200_HPLPF2_2:
824d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_1:
825d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_2:
826d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_3:
827d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_4:
828d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_5:
829d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_6:
830d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_7:
831d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_8:
832d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_9:
833d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_10:
834d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_11:
835d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_12:
836d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_13:
837d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_14:
838d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_15:
839d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_16:
840d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_17:
841d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_18:
842d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_19:
843d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_20:
844d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_21:
845d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_22:
846d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_23:
847d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_24:
848d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_25:
849d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_26:
850d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_27:
851d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_28:
852d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_29:
853d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_30:
854d5315a23SMark Brown 	case WM2200_DSP1_CONTROL_31:
855d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_1:
856d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_2:
857d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_3:
858d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_4:
859d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_5:
860d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_6:
861d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_7:
862d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_8:
863d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_9:
864d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_10:
865d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_11:
866d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_12:
867d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_13:
868d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_14:
869d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_15:
870d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_16:
871d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_17:
872d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_18:
873d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_19:
874d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_20:
875d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_21:
876d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_22:
877d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_23:
878d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_24:
879d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_25:
880d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_26:
881d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_27:
882d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_28:
883d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_29:
884d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_30:
885d5315a23SMark Brown 	case WM2200_DSP2_CONTROL_31:
886d5315a23SMark Brown 		return true;
887d5315a23SMark Brown 	default:
888d5315a23SMark Brown 		return false;
889d5315a23SMark Brown 	}
890d5315a23SMark Brown }
891d5315a23SMark Brown 
892d5315a23SMark Brown static const struct reg_default wm2200_reva_patch[] = {
893d5315a23SMark Brown 	{ 0x07, 0x0003 },
894d5315a23SMark Brown 	{ 0x102, 0x0200 },
895d5315a23SMark Brown 	{ 0x203, 0x0084 },
896d5315a23SMark Brown 	{ 0x201, 0x83FF },
897d5315a23SMark Brown 	{ 0x20C, 0x0062 },
898d5315a23SMark Brown 	{ 0x20D, 0x0062 },
899d5315a23SMark Brown 	{ 0x207, 0x2002 },
900d5315a23SMark Brown 	{ 0x208, 0x20C0 },
901d5315a23SMark Brown 	{ 0x21D, 0x01C0 },
902d5315a23SMark Brown 	{ 0x50A, 0x0001 },
903d5315a23SMark Brown 	{ 0x50B, 0x0002 },
904d5315a23SMark Brown 	{ 0x50C, 0x0003 },
905d5315a23SMark Brown 	{ 0x50D, 0x0004 },
906d5315a23SMark Brown 	{ 0x50E, 0x0005 },
907d5315a23SMark Brown 	{ 0x510, 0x0001 },
908d5315a23SMark Brown 	{ 0x511, 0x0002 },
909d5315a23SMark Brown 	{ 0x512, 0x0003 },
910d5315a23SMark Brown 	{ 0x513, 0x0004 },
911d5315a23SMark Brown 	{ 0x514, 0x0005 },
912d5315a23SMark Brown 	{ 0x515, 0x0000 },
913d5315a23SMark Brown 	{ 0x201, 0x8084 },
914d5315a23SMark Brown 	{ 0x202, 0xBBDE },
915d5315a23SMark Brown 	{ 0x203, 0x00EC },
916d5315a23SMark Brown 	{ 0x500, 0x8000 },
917d5315a23SMark Brown 	{ 0x507, 0x1820 },
918d5315a23SMark Brown 	{ 0x508, 0x1820 },
919d5315a23SMark Brown 	{ 0x505, 0x0300 },
920d5315a23SMark Brown 	{ 0x506, 0x0300 },
921d5315a23SMark Brown 	{ 0x302, 0x2280 },
922d5315a23SMark Brown 	{ 0x303, 0x0080 },
923d5315a23SMark Brown 	{ 0x304, 0x2280 },
924d5315a23SMark Brown 	{ 0x305, 0x0080 },
925d5315a23SMark Brown 	{ 0x306, 0x2280 },
926d5315a23SMark Brown 	{ 0x307, 0x0080 },
927d5315a23SMark Brown 	{ 0x401, 0x0080 },
928d5315a23SMark Brown 	{ 0x402, 0x0080 },
929d5315a23SMark Brown 	{ 0x417, 0x3069 },
930d5315a23SMark Brown 	{ 0x900, 0x6318 },
931d5315a23SMark Brown 	{ 0x901, 0x6300 },
932d5315a23SMark Brown 	{ 0x902, 0x0FC8 },
933d5315a23SMark Brown 	{ 0x903, 0x03FE },
934d5315a23SMark Brown 	{ 0x904, 0x00E0 },
935d5315a23SMark Brown 	{ 0x905, 0x1EC4 },
936d5315a23SMark Brown 	{ 0x906, 0xF136 },
937d5315a23SMark Brown 	{ 0x907, 0x0409 },
938d5315a23SMark Brown 	{ 0x908, 0x04CC },
939d5315a23SMark Brown 	{ 0x909, 0x1C9B },
940d5315a23SMark Brown 	{ 0x90A, 0xF337 },
941d5315a23SMark Brown 	{ 0x90B, 0x040B },
942d5315a23SMark Brown 	{ 0x90C, 0x0CBB },
943d5315a23SMark Brown 	{ 0x90D, 0x16F8 },
944d5315a23SMark Brown 	{ 0x90E, 0xF7D9 },
945d5315a23SMark Brown 	{ 0x90F, 0x040A },
946d5315a23SMark Brown 	{ 0x910, 0x1F14 },
947d5315a23SMark Brown 	{ 0x911, 0x058C },
948d5315a23SMark Brown 	{ 0x912, 0x0563 },
949d5315a23SMark Brown 	{ 0x913, 0x4000 },
950d5315a23SMark Brown 	{ 0x916, 0x6318 },
951d5315a23SMark Brown 	{ 0x917, 0x6300 },
952d5315a23SMark Brown 	{ 0x918, 0x0FC8 },
953d5315a23SMark Brown 	{ 0x919, 0x03FE },
954d5315a23SMark Brown 	{ 0x91A, 0x00E0 },
955d5315a23SMark Brown 	{ 0x91B, 0x1EC4 },
956d5315a23SMark Brown 	{ 0x91C, 0xF136 },
957d5315a23SMark Brown 	{ 0x91D, 0x0409 },
958d5315a23SMark Brown 	{ 0x91E, 0x04CC },
959d5315a23SMark Brown 	{ 0x91F, 0x1C9B },
960d5315a23SMark Brown 	{ 0x920, 0xF337 },
961d5315a23SMark Brown 	{ 0x921, 0x040B },
962d5315a23SMark Brown 	{ 0x922, 0x0CBB },
963d5315a23SMark Brown 	{ 0x923, 0x16F8 },
964d5315a23SMark Brown 	{ 0x924, 0xF7D9 },
965d5315a23SMark Brown 	{ 0x925, 0x040A },
966d5315a23SMark Brown 	{ 0x926, 0x1F14 },
967d5315a23SMark Brown 	{ 0x927, 0x058C },
968d5315a23SMark Brown 	{ 0x928, 0x0563 },
969d5315a23SMark Brown 	{ 0x929, 0x4000 },
970d5315a23SMark Brown 	{ 0x709, 0x2000 },
971d5315a23SMark Brown 	{ 0x207, 0x200E },
972d5315a23SMark Brown 	{ 0x208, 0x20D4 },
973d5315a23SMark Brown 	{ 0x20A, 0x0080 },
974d5315a23SMark Brown 	{ 0x07, 0x0000 },
975d5315a23SMark Brown };
976d5315a23SMark Brown 
977d5315a23SMark Brown static int wm2200_reset(struct wm2200_priv *wm2200)
978d5315a23SMark Brown {
979d5315a23SMark Brown 	if (wm2200->pdata.reset) {
980d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
981d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.reset, 1);
982d5315a23SMark Brown 
983d5315a23SMark Brown 		return 0;
984d5315a23SMark Brown 	} else {
985d5315a23SMark Brown 		return regmap_write(wm2200->regmap, WM2200_SOFTWARE_RESET,
986d5315a23SMark Brown 				    0x2200);
987d5315a23SMark Brown 	}
988d5315a23SMark Brown }
989d5315a23SMark Brown 
990e10f8711SMark Brown static int wm2200_dsp_load(struct snd_soc_codec *codec, int base)
991e10f8711SMark Brown {
992e10f8711SMark Brown 	const struct firmware *firmware;
993e10f8711SMark Brown 	struct regmap *regmap = codec->control_data;
994e10f8711SMark Brown 	unsigned int pos = 0;
995e10f8711SMark Brown 	const struct wmfw_header *header;
996e10f8711SMark Brown 	const struct wmfw_adsp1_sizes *adsp1_sizes;
997e10f8711SMark Brown 	const struct wmfw_footer *footer;
998e10f8711SMark Brown 	const struct wmfw_region *region;
999e10f8711SMark Brown 	const char *file, *region_name;
1000e10f8711SMark Brown 	char *text;
1001e10f8711SMark Brown 	unsigned int dm, pm, zm, reg;
1002e10f8711SMark Brown 	int regions = 0;
1003e10f8711SMark Brown 	int ret, offset, type;
1004e10f8711SMark Brown 
1005e10f8711SMark Brown 	switch (base) {
1006e10f8711SMark Brown 	case WM2200_DSP1_CONTROL_1:
1007e10f8711SMark Brown 		file = "wm2200-dsp1.wmfw";
1008e10f8711SMark Brown 		dm = WM2200_DSP1_DM_BASE;
1009e10f8711SMark Brown 		pm = WM2200_DSP1_PM_BASE;
1010e10f8711SMark Brown 		zm = WM2200_DSP1_ZM_BASE;
1011e10f8711SMark Brown 		break;
1012e10f8711SMark Brown 	case WM2200_DSP2_CONTROL_1:
1013e10f8711SMark Brown 		file = "wm2200-dsp2.wmfw";
1014e10f8711SMark Brown 		dm = WM2200_DSP2_DM_BASE;
1015e10f8711SMark Brown 		pm = WM2200_DSP2_PM_BASE;
1016e10f8711SMark Brown 		zm = WM2200_DSP2_ZM_BASE;
1017e10f8711SMark Brown 		break;
1018e10f8711SMark Brown 	default:
1019e10f8711SMark Brown 		dev_err(codec->dev, "BASE %x\n", base);
1020e10f8711SMark Brown 		BUG_ON(1);
1021e10f8711SMark Brown 		return -EINVAL;
1022e10f8711SMark Brown 	}
1023e10f8711SMark Brown 
1024e10f8711SMark Brown 	ret = request_firmware(&firmware, file, codec->dev);
1025e10f8711SMark Brown 	if (ret != 0) {
1026e10f8711SMark Brown 		dev_err(codec->dev, "Failed to request '%s'\n", file);
1027e10f8711SMark Brown 		return ret;
1028e10f8711SMark Brown 	}
1029e10f8711SMark Brown 
1030e10f8711SMark Brown 	pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
1031e10f8711SMark Brown 	if (pos >= firmware->size) {
1032e10f8711SMark Brown 		dev_err(codec->dev, "%s: file too short, %d bytes\n",
1033e10f8711SMark Brown 			file, firmware->size);
1034e10f8711SMark Brown 		return -EINVAL;
1035e10f8711SMark Brown 	}
1036e10f8711SMark Brown 
1037e10f8711SMark Brown 	header = (void*)&firmware->data[0];
1038e10f8711SMark Brown 
1039e10f8711SMark Brown 	if (memcmp(&header->magic[0], "WMFW", 4) != 0) {
1040e10f8711SMark Brown 		dev_err(codec->dev, "%s: invalid magic\n", file);
1041e10f8711SMark Brown 		return -EINVAL;
1042e10f8711SMark Brown 	}
1043e10f8711SMark Brown 
1044e10f8711SMark Brown 	if (header->ver != 0) {
1045e10f8711SMark Brown 		dev_err(codec->dev, "%s: unknown file format %d\n",
1046e10f8711SMark Brown 			file, header->ver);
1047e10f8711SMark Brown 		return -EINVAL;
1048e10f8711SMark Brown 	}
1049e10f8711SMark Brown 
1050e10f8711SMark Brown 	if (le32_to_cpu(header->len) != sizeof(*header) +
1051e10f8711SMark Brown 	    sizeof(*adsp1_sizes) + sizeof(*footer)) {
1052e10f8711SMark Brown 		dev_err(codec->dev, "%s: unexpected header length %d\n",
1053e10f8711SMark Brown 			file, le32_to_cpu(header->len));
1054e10f8711SMark Brown 		return -EINVAL;
1055e10f8711SMark Brown 	}
1056e10f8711SMark Brown 
1057e10f8711SMark Brown 	if (header->core != WMFW_ADSP1) {
1058e10f8711SMark Brown 		dev_err(codec->dev, "%s: invalid core %d\n",
1059e10f8711SMark Brown 			file, header->core);
1060e10f8711SMark Brown 		return -EINVAL;
1061e10f8711SMark Brown 	}
1062e10f8711SMark Brown 
1063e10f8711SMark Brown 	adsp1_sizes = (void *)&(header[1]);
1064e10f8711SMark Brown 	footer = (void *)&(adsp1_sizes[1]);
1065e10f8711SMark Brown 
1066e10f8711SMark Brown 	dev_dbg(codec->dev, "%s: %d DM, %d PM, %d ZM\n",
1067e10f8711SMark Brown 		file, le32_to_cpu(adsp1_sizes->dm),
1068e10f8711SMark Brown 		le32_to_cpu(adsp1_sizes->pm), le32_to_cpu(adsp1_sizes->zm));
1069e10f8711SMark Brown 
1070e10f8711SMark Brown 	dev_dbg(codec->dev, "%s: timestamp %llu\n", file,
1071e10f8711SMark Brown 		le64_to_cpu(footer->timestamp));
1072e10f8711SMark Brown 
1073e10f8711SMark Brown 	while (pos < firmware->size &&
1074e10f8711SMark Brown 	       pos - firmware->size > sizeof(*region)) {
1075e10f8711SMark Brown 		region = (void *)&(firmware->data[pos]);
1076e10f8711SMark Brown 		region_name = "Unknown";
1077e10f8711SMark Brown 		reg = 0;
1078e10f8711SMark Brown 		text = NULL;
1079e10f8711SMark Brown 		offset = le32_to_cpu(region->offset) & 0xffffff;
1080e10f8711SMark Brown 		type = be32_to_cpu(region->type) & 0xff;
1081e10f8711SMark Brown 
1082e10f8711SMark Brown 		switch (type) {
1083e10f8711SMark Brown 		case WMFW_NAME_TEXT:
1084e10f8711SMark Brown 			region_name = "Firmware name";
1085e10f8711SMark Brown 			text = kzalloc(le32_to_cpu(region->len) + 1,
1086e10f8711SMark Brown 				       GFP_KERNEL);
1087e10f8711SMark Brown 			break;
1088e10f8711SMark Brown 		case WMFW_INFO_TEXT:
1089e10f8711SMark Brown 			region_name = "Information";
1090e10f8711SMark Brown 			text = kzalloc(le32_to_cpu(region->len) + 1,
1091e10f8711SMark Brown 				       GFP_KERNEL);
1092e10f8711SMark Brown 			break;
1093e10f8711SMark Brown 		case WMFW_ABSOLUTE:
1094e10f8711SMark Brown 			region_name = "Absolute";
1095e10f8711SMark Brown 			reg = offset;
1096e10f8711SMark Brown 			break;
1097e10f8711SMark Brown 		case WMFW_ADSP1_PM:
1098e10f8711SMark Brown 			region_name = "PM";
1099e10f8711SMark Brown 			reg = pm + (offset * 3);
1100e10f8711SMark Brown 			break;
1101e10f8711SMark Brown 		case WMFW_ADSP1_DM:
1102e10f8711SMark Brown 			region_name = "DM";
1103e10f8711SMark Brown 			reg = dm + (offset * 2);
1104e10f8711SMark Brown 			break;
1105e10f8711SMark Brown 		case WMFW_ADSP1_ZM:
1106e10f8711SMark Brown 			region_name = "ZM";
1107e10f8711SMark Brown 			reg = zm + (offset * 2);
1108e10f8711SMark Brown 			break;
1109e10f8711SMark Brown 		default:
1110e10f8711SMark Brown 			dev_warn(codec->dev,
1111e10f8711SMark Brown 				 "%s.%d: Unknown region type %x at %d(%x)\n",
1112e10f8711SMark Brown 				 file, regions, type, pos, pos);
1113e10f8711SMark Brown 			break;
1114e10f8711SMark Brown 		}
1115e10f8711SMark Brown 
1116e10f8711SMark Brown 		dev_dbg(codec->dev, "%s.%d: %d bytes at %d in %s\n", file,
1117e10f8711SMark Brown 			regions, le32_to_cpu(region->len), offset,
1118e10f8711SMark Brown 			region_name);
1119e10f8711SMark Brown 
1120e10f8711SMark Brown 		if (text) {
1121e10f8711SMark Brown 			memcpy(text, region->data, le32_to_cpu(region->len));
1122e10f8711SMark Brown 			dev_info(codec->dev, "%s: %s\n", file, text);
1123e10f8711SMark Brown 			kfree(text);
1124e10f8711SMark Brown 		}
1125e10f8711SMark Brown 
1126e10f8711SMark Brown 		if (reg) {
1127e10f8711SMark Brown 			ret = regmap_raw_write(regmap, reg, region->data,
1128e10f8711SMark Brown 					       le32_to_cpu(region->len));
1129e10f8711SMark Brown 			if (ret != 0) {
1130e10f8711SMark Brown 				dev_err(codec->dev,
1131e10f8711SMark Brown 					"%s.%d: Failed to write %d bytes at %d in %s: %d\n",
1132e10f8711SMark Brown 					file, regions,
1133e10f8711SMark Brown 					le32_to_cpu(region->len), offset,
1134e10f8711SMark Brown 					region_name, ret);
1135e10f8711SMark Brown 				goto out;
1136e10f8711SMark Brown 			}
1137e10f8711SMark Brown 		}
1138e10f8711SMark Brown 
1139e10f8711SMark Brown 		pos += le32_to_cpu(region->len) + sizeof(*region);
1140e10f8711SMark Brown 		regions++;
1141e10f8711SMark Brown 	}
1142e10f8711SMark Brown 
1143e10f8711SMark Brown 	if (pos > firmware->size)
1144e10f8711SMark Brown 		dev_warn(codec->dev, "%s.%d: %d bytes at end of file\n",
1145e10f8711SMark Brown 			 file, regions, pos - firmware->size);
1146e10f8711SMark Brown 
1147e10f8711SMark Brown out:
1148e10f8711SMark Brown 	release_firmware(firmware);
1149e10f8711SMark Brown 
1150e10f8711SMark Brown 	return ret;
1151e10f8711SMark Brown }
1152e10f8711SMark Brown 
1153e10f8711SMark Brown static int wm2200_dsp_ev(struct snd_soc_dapm_widget *w,
1154e10f8711SMark Brown 			 struct snd_kcontrol *kcontrol,
1155e10f8711SMark Brown 			 int event)
1156e10f8711SMark Brown {
1157e10f8711SMark Brown 	struct snd_soc_codec *codec = w->codec;
1158e10f8711SMark Brown 	int base = w->reg - WM2200_DSP_CONTROL_30;
1159e10f8711SMark Brown 	int ret;
1160e10f8711SMark Brown 
1161e10f8711SMark Brown 	switch (event) {
1162e10f8711SMark Brown 	case SND_SOC_DAPM_POST_PMU:
1163e10f8711SMark Brown 		ret = wm2200_dsp_load(codec, base);
1164e10f8711SMark Brown 		if (ret != 0)
1165e10f8711SMark Brown 			return ret;
1166e10f8711SMark Brown 
1167e10f8711SMark Brown 		/* Start the core running */
1168e10f8711SMark Brown 		snd_soc_update_bits(codec, w->reg,
1169e10f8711SMark Brown 				    WM2200_DSP1_CORE_ENA | WM2200_DSP1_START,
1170e10f8711SMark Brown 				    WM2200_DSP1_CORE_ENA | WM2200_DSP1_START);
1171e10f8711SMark Brown 		break;
1172e10f8711SMark Brown 
1173e10f8711SMark Brown 	case SND_SOC_DAPM_PRE_PMD:
1174e10f8711SMark Brown 		/* Halt the core */
1175e10f8711SMark Brown 		snd_soc_update_bits(codec, w->reg,
1176e10f8711SMark Brown 				    WM2200_DSP1_CORE_ENA | WM2200_DSP1_START,
1177e10f8711SMark Brown 				    0);
1178e10f8711SMark Brown 
1179e10f8711SMark Brown 		snd_soc_update_bits(codec, base + WM2200_DSP_CONTROL_19,
1180e10f8711SMark Brown 				    WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK, 0);
1181e10f8711SMark Brown 		break;
1182e10f8711SMark Brown 
1183e10f8711SMark Brown 	default:
1184e10f8711SMark Brown 		break;
1185e10f8711SMark Brown 	}
1186e10f8711SMark Brown 
1187e10f8711SMark Brown 	return 0;
1188e10f8711SMark Brown }
1189e10f8711SMark Brown 
1190d5315a23SMark Brown static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
1191d5315a23SMark Brown static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
1192d5315a23SMark Brown static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
1193d5315a23SMark Brown 
1194d5315a23SMark Brown static const char *wm2200_mixer_texts[] = {
1195d5315a23SMark Brown 	"None",
1196d5315a23SMark Brown 	"Tone Generator",
1197999e068eSMark Brown 	"AEC Loopback",
1198d5315a23SMark Brown 	"IN1L",
1199d5315a23SMark Brown 	"IN1R",
1200d5315a23SMark Brown 	"IN2L",
1201d5315a23SMark Brown 	"IN2R",
1202d5315a23SMark Brown 	"IN3L",
1203d5315a23SMark Brown 	"IN3R",
1204d5315a23SMark Brown 	"AIF1RX1",
1205d5315a23SMark Brown 	"AIF1RX2",
1206d5315a23SMark Brown 	"AIF1RX3",
1207d5315a23SMark Brown 	"AIF1RX4",
1208d5315a23SMark Brown 	"AIF1RX5",
1209d5315a23SMark Brown 	"AIF1RX6",
1210d5315a23SMark Brown 	"EQL",
1211d5315a23SMark Brown 	"EQR",
1212d5315a23SMark Brown 	"LHPF1",
1213d5315a23SMark Brown 	"LHPF2",
1214d5315a23SMark Brown 	"LHPF3",
1215d5315a23SMark Brown 	"LHPF4",
1216d5315a23SMark Brown 	"DSP1.1",
1217d5315a23SMark Brown 	"DSP1.2",
1218d5315a23SMark Brown 	"DSP1.3",
1219d5315a23SMark Brown 	"DSP1.4",
1220d5315a23SMark Brown 	"DSP1.5",
1221d5315a23SMark Brown 	"DSP1.6",
1222d5315a23SMark Brown 	"DSP2.1",
1223d5315a23SMark Brown 	"DSP2.2",
1224d5315a23SMark Brown 	"DSP2.3",
1225d5315a23SMark Brown 	"DSP2.4",
1226d5315a23SMark Brown 	"DSP2.5",
1227d5315a23SMark Brown 	"DSP2.6",
1228d5315a23SMark Brown };
1229d5315a23SMark Brown 
1230d5315a23SMark Brown static int wm2200_mixer_values[] = {
1231d5315a23SMark Brown 	0x00,
1232d5315a23SMark Brown 	0x04,   /* Tone */
1233d5315a23SMark Brown 	0x08,   /* AEC */
1234d5315a23SMark Brown 	0x10,   /* Input */
1235d5315a23SMark Brown 	0x11,
1236d5315a23SMark Brown 	0x12,
1237d5315a23SMark Brown 	0x13,
1238d5315a23SMark Brown 	0x14,
1239d5315a23SMark Brown 	0x15,
1240d5315a23SMark Brown 	0x20,   /* AIF */
1241d5315a23SMark Brown 	0x21,
1242d5315a23SMark Brown 	0x22,
1243d5315a23SMark Brown 	0x23,
1244d5315a23SMark Brown 	0x24,
1245d5315a23SMark Brown 	0x25,
1246d5315a23SMark Brown 	0x50,   /* EQ */
1247d5315a23SMark Brown 	0x51,
1248d5315a23SMark Brown 	0x52,
1249d5315a23SMark Brown 	0x60,   /* LHPF1 */
1250d5315a23SMark Brown 	0x61,   /* LHPF2 */
1251d5315a23SMark Brown 	0x68,   /* DSP1 */
1252d5315a23SMark Brown 	0x69,
1253d5315a23SMark Brown 	0x6a,
1254d5315a23SMark Brown 	0x6b,
1255d5315a23SMark Brown 	0x6c,
1256d5315a23SMark Brown 	0x6d,
1257d5315a23SMark Brown 	0x70,   /* DSP2 */
1258d5315a23SMark Brown 	0x71,
1259d5315a23SMark Brown 	0x72,
1260d5315a23SMark Brown 	0x73,
1261d5315a23SMark Brown 	0x74,
1262d5315a23SMark Brown 	0x75,
1263d5315a23SMark Brown };
1264d5315a23SMark Brown 
1265d5315a23SMark Brown #define WM2200_MIXER_CONTROLS(name, base) \
1266d5315a23SMark Brown 	SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
1267d5315a23SMark Brown 		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
1268d5315a23SMark Brown 	SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
1269d5315a23SMark Brown 		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
1270d5315a23SMark Brown 	SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
1271d5315a23SMark Brown 		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
1272d5315a23SMark Brown 	SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
1273d5315a23SMark Brown 		       WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
1274d5315a23SMark Brown 
1275d5315a23SMark Brown #define WM2200_MUX_ENUM_DECL(name, reg) \
1276d5315a23SMark Brown 	SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, 			\
1277d5315a23SMark Brown 				   wm2200_mixer_texts, wm2200_mixer_values)
1278d5315a23SMark Brown 
1279d5315a23SMark Brown #define WM2200_MUX_CTL_DECL(name) \
1280d5315a23SMark Brown 	const struct snd_kcontrol_new name##_mux =	\
1281d5315a23SMark Brown 		SOC_DAPM_VALUE_ENUM("Route", name##_enum)
1282d5315a23SMark Brown 
1283d5315a23SMark Brown #define WM2200_MIXER_ENUMS(name, base_reg) \
1284d5315a23SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg);	     \
1285d5315a23SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2);  \
1286d5315a23SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4);  \
1287d5315a23SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6);  \
1288d5315a23SMark Brown 	static WM2200_MUX_CTL_DECL(name##_in1); \
1289d5315a23SMark Brown 	static WM2200_MUX_CTL_DECL(name##_in2); \
1290d5315a23SMark Brown 	static WM2200_MUX_CTL_DECL(name##_in3); \
1291d5315a23SMark Brown 	static WM2200_MUX_CTL_DECL(name##_in4)
1292d5315a23SMark Brown 
129309d5d588SMark Brown #define WM2200_DSP_ENUMS(name, base_reg) \
129409d5d588SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_aux1_enum, base_reg);     \
129509d5d588SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_aux2_enum, base_reg + 1); \
129609d5d588SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_aux3_enum, base_reg + 2); \
129709d5d588SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_aux4_enum, base_reg + 3); \
129809d5d588SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_aux5_enum, base_reg + 4); \
129909d5d588SMark Brown 	static WM2200_MUX_ENUM_DECL(name##_aux6_enum, base_reg + 5); \
130009d5d588SMark Brown 	static WM2200_MUX_CTL_DECL(name##_aux1); \
130109d5d588SMark Brown 	static WM2200_MUX_CTL_DECL(name##_aux2); \
130209d5d588SMark Brown 	static WM2200_MUX_CTL_DECL(name##_aux3); \
130309d5d588SMark Brown 	static WM2200_MUX_CTL_DECL(name##_aux4); \
130409d5d588SMark Brown 	static WM2200_MUX_CTL_DECL(name##_aux5); \
130509d5d588SMark Brown 	static WM2200_MUX_CTL_DECL(name##_aux6);
130609d5d588SMark Brown 
1307d5315a23SMark Brown static const struct snd_kcontrol_new wm2200_snd_controls[] = {
1308d5315a23SMark Brown SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
1309d5315a23SMark Brown 	   WM2200_IN1_OSR_SHIFT, 1, 0),
1310d5315a23SMark Brown SOC_SINGLE("IN2 High Performance Switch", WM2200_IN2L_CONTROL,
1311d5315a23SMark Brown 	   WM2200_IN2_OSR_SHIFT, 1, 0),
1312d5315a23SMark Brown SOC_SINGLE("IN3 High Performance Switch", WM2200_IN3L_CONTROL,
1313d5315a23SMark Brown 	   WM2200_IN3_OSR_SHIFT, 1, 0),
1314d5315a23SMark Brown 
1315d5315a23SMark Brown SOC_DOUBLE_R_TLV("IN1 Volume", WM2200_IN1L_CONTROL, WM2200_IN1R_CONTROL,
1316d5315a23SMark Brown 		 WM2200_IN1L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
1317d5315a23SMark Brown SOC_DOUBLE_R_TLV("IN2 Volume", WM2200_IN2L_CONTROL, WM2200_IN2R_CONTROL,
1318d5315a23SMark Brown 		 WM2200_IN2L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
1319d5315a23SMark Brown SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
1320d5315a23SMark Brown 		 WM2200_IN3L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
1321d5315a23SMark Brown 
1322d5315a23SMark Brown SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
1323d5315a23SMark Brown 	     WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
1324d5315a23SMark Brown SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
1325d5315a23SMark Brown 	     WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
1326d5315a23SMark Brown SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
1327d5315a23SMark Brown 	     WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
1328d5315a23SMark Brown 
1329d5315a23SMark Brown SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
1330d5315a23SMark Brown 		 WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_DIG_VOL_SHIFT,
1331d5315a23SMark Brown 		 0xbf, 0, digital_tlv),
1332d5315a23SMark Brown SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_2L,
1333d5315a23SMark Brown 		 WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_DIG_VOL_SHIFT,
1334d5315a23SMark Brown 		 0xbf, 0, digital_tlv),
1335d5315a23SMark Brown SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
1336d5315a23SMark Brown 		 WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT,
1337d5315a23SMark Brown 		 0xbf, 0, digital_tlv),
1338d5315a23SMark Brown 
1339d5315a23SMark Brown SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
1340d5315a23SMark Brown 	   WM2200_OUT1_OSR_SHIFT, 1, 0),
1341d5315a23SMark Brown SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
1342d5315a23SMark Brown 	   WM2200_OUT2_OSR_SHIFT, 1, 0),
1343d5315a23SMark Brown 
1344d5315a23SMark Brown SOC_DOUBLE_R("OUT1 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
1345d5315a23SMark Brown 	     WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_MUTE_SHIFT, 1, 1),
1346d5315a23SMark Brown SOC_DOUBLE_R_TLV("OUT1 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_1L,
1347d5315a23SMark Brown 		 WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_VOL_SHIFT, 0x9f, 0,
1348d5315a23SMark Brown 		 digital_tlv),
1349d5315a23SMark Brown SOC_DOUBLE_R_TLV("OUT1 Volume", WM2200_DAC_VOLUME_LIMIT_1L,
1350d5315a23SMark Brown 		 WM2200_DAC_VOLUME_LIMIT_1R, WM2200_OUT1L_PGA_VOL_SHIFT,
1351d5315a23SMark Brown 		 0x46, 0, out_tlv),
1352d5315a23SMark Brown 
1353d5315a23SMark Brown SOC_DOUBLE_R("OUT2 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
1354d5315a23SMark Brown 	     WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_MUTE_SHIFT, 1, 1),
1355d5315a23SMark Brown SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
1356d5315a23SMark Brown 		 WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0,
1357d5315a23SMark Brown 		 digital_tlv),
1358d5315a23SMark Brown SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
1359a1b98e12SMark Brown 	   WM2200_SPK1R_MUTE_SHIFT, 1, 1),
1360d5315a23SMark Brown };
1361d5315a23SMark Brown 
1362d5315a23SMark Brown WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
1363d5315a23SMark Brown WM2200_MIXER_ENUMS(OUT1R, WM2200_OUT1RMIX_INPUT_1_SOURCE);
1364d5315a23SMark Brown WM2200_MIXER_ENUMS(OUT2L, WM2200_OUT2LMIX_INPUT_1_SOURCE);
1365d5315a23SMark Brown WM2200_MIXER_ENUMS(OUT2R, WM2200_OUT2RMIX_INPUT_1_SOURCE);
1366d5315a23SMark Brown 
1367d5315a23SMark Brown WM2200_MIXER_ENUMS(AIF1TX1, WM2200_AIF1TX1MIX_INPUT_1_SOURCE);
1368d5315a23SMark Brown WM2200_MIXER_ENUMS(AIF1TX2, WM2200_AIF1TX2MIX_INPUT_1_SOURCE);
1369d5315a23SMark Brown WM2200_MIXER_ENUMS(AIF1TX3, WM2200_AIF1TX3MIX_INPUT_1_SOURCE);
1370d5315a23SMark Brown WM2200_MIXER_ENUMS(AIF1TX4, WM2200_AIF1TX4MIX_INPUT_1_SOURCE);
1371d5315a23SMark Brown WM2200_MIXER_ENUMS(AIF1TX5, WM2200_AIF1TX5MIX_INPUT_1_SOURCE);
1372d5315a23SMark Brown WM2200_MIXER_ENUMS(AIF1TX6, WM2200_AIF1TX6MIX_INPUT_1_SOURCE);
1373d5315a23SMark Brown 
1374d5315a23SMark Brown WM2200_MIXER_ENUMS(EQL, WM2200_EQLMIX_INPUT_1_SOURCE);
1375d5315a23SMark Brown WM2200_MIXER_ENUMS(EQR, WM2200_EQRMIX_INPUT_1_SOURCE);
1376d5315a23SMark Brown 
1377d5315a23SMark Brown WM2200_MIXER_ENUMS(DSP1L, WM2200_DSP1LMIX_INPUT_1_SOURCE);
1378d5315a23SMark Brown WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE);
1379d5315a23SMark Brown WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE);
1380d5315a23SMark Brown WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE);
1381d5315a23SMark Brown 
138209d5d588SMark Brown WM2200_DSP_ENUMS(DSP1, WM2200_DSP1AUX1MIX_INPUT_1_SOURCE);
138309d5d588SMark Brown WM2200_DSP_ENUMS(DSP2, WM2200_DSP2AUX1MIX_INPUT_1_SOURCE);
138409d5d588SMark Brown 
1385d5315a23SMark Brown WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
1386d5315a23SMark Brown WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
1387d5315a23SMark Brown 
1388d5315a23SMark Brown #define WM2200_MUX(name, ctrl) \
1389d5315a23SMark Brown 	SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
1390d5315a23SMark Brown 
1391d5315a23SMark Brown #define WM2200_MIXER_WIDGETS(name, name_str)	\
1392d5315a23SMark Brown 	WM2200_MUX(name_str " Input 1", &name##_in1_mux), \
1393d5315a23SMark Brown 	WM2200_MUX(name_str " Input 2", &name##_in2_mux), \
1394d5315a23SMark Brown 	WM2200_MUX(name_str " Input 3", &name##_in3_mux), \
1395d5315a23SMark Brown 	WM2200_MUX(name_str " Input 4", &name##_in4_mux), \
1396d5315a23SMark Brown 	SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
1397d5315a23SMark Brown 
139809d5d588SMark Brown #define WM2200_DSP_WIDGETS(name, name_str) \
139909d5d588SMark Brown 	WM2200_MIXER_WIDGETS(name##L, name_str "L"), \
140009d5d588SMark Brown 	WM2200_MIXER_WIDGETS(name##R, name_str "R"), \
140109d5d588SMark Brown 	WM2200_MUX(name_str " Aux 1", &name##_aux1_mux), \
140209d5d588SMark Brown 	WM2200_MUX(name_str " Aux 2", &name##_aux2_mux), \
140309d5d588SMark Brown 	WM2200_MUX(name_str " Aux 3", &name##_aux3_mux), \
140409d5d588SMark Brown 	WM2200_MUX(name_str " Aux 4", &name##_aux4_mux), \
140509d5d588SMark Brown 	WM2200_MUX(name_str " Aux 5", &name##_aux5_mux), \
140609d5d588SMark Brown 	WM2200_MUX(name_str " Aux 6", &name##_aux6_mux)
140709d5d588SMark Brown 
1408d5315a23SMark Brown #define WM2200_MIXER_INPUT_ROUTES(name)	\
1409d5315a23SMark Brown 	{ name, "Tone Generator", "Tone Generator" }, \
1410999e068eSMark Brown 	{ name, "AEC Loopback", "AEC Loopback" }, \
1411d5315a23SMark Brown         { name, "IN1L", "IN1L PGA" }, \
1412d5315a23SMark Brown         { name, "IN1R", "IN1R PGA" }, \
1413d5315a23SMark Brown         { name, "IN2L", "IN2L PGA" }, \
1414d5315a23SMark Brown         { name, "IN2R", "IN2R PGA" }, \
1415d5315a23SMark Brown         { name, "IN3L", "IN3L PGA" }, \
1416d5315a23SMark Brown         { name, "IN3R", "IN3R PGA" }, \
1417d5315a23SMark Brown         { name, "DSP1.1", "DSP1" }, \
1418d5315a23SMark Brown         { name, "DSP1.2", "DSP1" }, \
1419d5315a23SMark Brown         { name, "DSP1.3", "DSP1" }, \
1420d5315a23SMark Brown         { name, "DSP1.4", "DSP1" }, \
1421d5315a23SMark Brown         { name, "DSP1.5", "DSP1" }, \
1422d5315a23SMark Brown         { name, "DSP1.6", "DSP1" }, \
1423d5315a23SMark Brown         { name, "DSP2.1", "DSP2" }, \
1424d5315a23SMark Brown         { name, "DSP2.2", "DSP2" }, \
1425d5315a23SMark Brown         { name, "DSP2.3", "DSP2" }, \
1426d5315a23SMark Brown         { name, "DSP2.4", "DSP2" }, \
1427d5315a23SMark Brown         { name, "DSP2.5", "DSP2" }, \
1428d5315a23SMark Brown         { name, "DSP2.6", "DSP2" }, \
1429d5315a23SMark Brown         { name, "AIF1RX1", "AIF1RX1" }, \
1430d5315a23SMark Brown         { name, "AIF1RX2", "AIF1RX2" }, \
1431d5315a23SMark Brown         { name, "AIF1RX3", "AIF1RX3" }, \
1432d5315a23SMark Brown         { name, "AIF1RX4", "AIF1RX4" }, \
1433d5315a23SMark Brown         { name, "AIF1RX5", "AIF1RX5" }, \
1434d5315a23SMark Brown         { name, "AIF1RX6", "AIF1RX6" }, \
1435d5315a23SMark Brown         { name, "EQL", "EQL" }, \
1436d5315a23SMark Brown         { name, "EQR", "EQR" }, \
1437d5315a23SMark Brown         { name, "LHPF1", "LHPF1" }, \
1438d5315a23SMark Brown         { name, "LHPF2", "LHPF2" }
1439d5315a23SMark Brown 
1440d5315a23SMark Brown #define WM2200_MIXER_ROUTES(widget, name) \
1441d5315a23SMark Brown 	{ widget, NULL, name " Mixer" },         \
1442d5315a23SMark Brown 	{ name " Mixer", NULL, name " Input 1" }, \
1443d5315a23SMark Brown 	{ name " Mixer", NULL, name " Input 2" }, \
1444d5315a23SMark Brown 	{ name " Mixer", NULL, name " Input 3" }, \
1445d5315a23SMark Brown 	{ name " Mixer", NULL, name " Input 4" }, \
1446d5315a23SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Input 1"), \
1447d5315a23SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Input 2"), \
1448d5315a23SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \
1449d5315a23SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Input 4")
1450d5315a23SMark Brown 
145109d5d588SMark Brown #define WM2200_DSP_AUX_ROUTES(name) \
145209d5d588SMark Brown 	{ name, NULL, name " Aux 1" }, \
145309d5d588SMark Brown 	{ name, NULL, name " Aux 2" }, \
145409d5d588SMark Brown 	{ name, NULL, name " Aux 3" }, \
145509d5d588SMark Brown 	{ name, NULL, name " Aux 4" }, \
145609d5d588SMark Brown 	{ name, NULL, name " Aux 5" }, \
145709d5d588SMark Brown 	{ name, NULL, name " Aux 6" }, \
145809d5d588SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Aux 1"), \
145909d5d588SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Aux 2"), \
146009d5d588SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Aux 3"), \
146109d5d588SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Aux 4"), \
146209d5d588SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Aux 5"), \
146309d5d588SMark Brown 	WM2200_MIXER_INPUT_ROUTES(name " Aux 6")
1464999e068eSMark Brown 
1465999e068eSMark Brown static const char *wm2200_aec_loopback_texts[] = {
1466999e068eSMark Brown 	"OUT1L", "OUT1R", "OUT2L", "OUT2R",
1467999e068eSMark Brown };
1468999e068eSMark Brown 
1469999e068eSMark Brown static const struct soc_enum wm2200_aec_loopback =
1470999e068eSMark Brown 	SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1,
1471999e068eSMark Brown 			WM2200_AEC_LOOPBACK_SRC_SHIFT,
1472999e068eSMark Brown 			ARRAY_SIZE(wm2200_aec_loopback_texts),
1473999e068eSMark Brown 			wm2200_aec_loopback_texts);
1474999e068eSMark Brown 
1475999e068eSMark Brown static const struct snd_kcontrol_new wm2200_aec_loopback_mux =
1476999e068eSMark Brown 	SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback);
1477999e068eSMark Brown 
1478d5315a23SMark Brown static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = {
1479d5315a23SMark Brown SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0,
1480d5315a23SMark Brown 		    NULL, 0),
1481d5315a23SMark Brown SND_SOC_DAPM_SUPPLY("CP1", WM2200_DM_CHARGE_PUMP_1, WM2200_CPDM_ENA_SHIFT, 0,
1482d5315a23SMark Brown 		    NULL, 0),
1483d5315a23SMark Brown SND_SOC_DAPM_SUPPLY("CP2", WM2200_MIC_CHARGE_PUMP_1, WM2200_CPMIC_ENA_SHIFT, 0,
1484d5315a23SMark Brown 		    NULL, 0),
1485d5315a23SMark Brown SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT,
1486d5315a23SMark Brown 		    0, NULL, 0),
1487d5315a23SMark Brown SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT,
1488d5315a23SMark Brown 		    0, NULL, 0),
1489822b4b8dSMark Brown SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
1490822b4b8dSMark Brown SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20, 0),
1491d5315a23SMark Brown 
1492d5315a23SMark Brown SND_SOC_DAPM_INPUT("IN1L"),
1493d5315a23SMark Brown SND_SOC_DAPM_INPUT("IN1R"),
1494d5315a23SMark Brown SND_SOC_DAPM_INPUT("IN2L"),
1495d5315a23SMark Brown SND_SOC_DAPM_INPUT("IN2R"),
1496d5315a23SMark Brown SND_SOC_DAPM_INPUT("IN3L"),
1497d5315a23SMark Brown SND_SOC_DAPM_INPUT("IN3R"),
1498d5315a23SMark Brown 
1499d5315a23SMark Brown SND_SOC_DAPM_SIGGEN("TONE"),
1500d5315a23SMark Brown SND_SOC_DAPM_PGA("Tone Generator", WM2200_TONE_GENERATOR_1,
1501d5315a23SMark Brown 		 WM2200_TONE_ENA_SHIFT, 0, NULL, 0),
1502d5315a23SMark Brown 
1503d5315a23SMark Brown SND_SOC_DAPM_PGA("IN1L PGA", WM2200_INPUT_ENABLES, WM2200_IN1L_ENA_SHIFT, 0,
1504d5315a23SMark Brown 		 NULL, 0),
1505d5315a23SMark Brown SND_SOC_DAPM_PGA("IN1R PGA", WM2200_INPUT_ENABLES, WM2200_IN1R_ENA_SHIFT, 0,
1506d5315a23SMark Brown 		 NULL, 0),
1507d5315a23SMark Brown SND_SOC_DAPM_PGA("IN2L PGA", WM2200_INPUT_ENABLES, WM2200_IN2L_ENA_SHIFT, 0,
1508d5315a23SMark Brown 		 NULL, 0),
1509d5315a23SMark Brown SND_SOC_DAPM_PGA("IN2R PGA", WM2200_INPUT_ENABLES, WM2200_IN2R_ENA_SHIFT, 0,
1510d5315a23SMark Brown 		 NULL, 0),
1511d5315a23SMark Brown SND_SOC_DAPM_PGA("IN3L PGA", WM2200_INPUT_ENABLES, WM2200_IN3L_ENA_SHIFT, 0,
1512d5315a23SMark Brown 		 NULL, 0),
1513d5315a23SMark Brown SND_SOC_DAPM_PGA("IN3R PGA", WM2200_INPUT_ENABLES, WM2200_IN3R_ENA_SHIFT, 0,
1514d5315a23SMark Brown 		 NULL, 0),
1515d5315a23SMark Brown 
1516d5315a23SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX1", "Playback", 0,
1517d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX1_ENA_SHIFT, 0),
1518d5315a23SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX2", "Playback", 1,
1519d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX2_ENA_SHIFT, 0),
1520d5315a23SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX3", "Playback", 2,
1521d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX3_ENA_SHIFT, 0),
1522d5315a23SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX4", "Playback", 3,
1523d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX4_ENA_SHIFT, 0),
1524d5315a23SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX5", "Playback", 4,
1525d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX5_ENA_SHIFT, 0),
1526d5315a23SMark Brown SND_SOC_DAPM_AIF_IN("AIF1RX6", "Playback", 5,
1527d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1RX6_ENA_SHIFT, 0),
1528d5315a23SMark Brown 
1529d5315a23SMark Brown SND_SOC_DAPM_PGA("EQL", WM2200_EQL_1, WM2200_EQL_ENA_SHIFT, 0, NULL, 0),
1530d5315a23SMark Brown SND_SOC_DAPM_PGA("EQR", WM2200_EQR_1, WM2200_EQR_ENA_SHIFT, 0, NULL, 0),
1531d5315a23SMark Brown 
1532d5315a23SMark Brown SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0,
1533d5315a23SMark Brown 		 NULL, 0),
1534d5315a23SMark Brown SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0,
1535d5315a23SMark Brown 		 NULL, 0),
1536d5315a23SMark Brown 
153709d5d588SMark Brown SND_SOC_DAPM_PGA_E("DSP1", WM2200_DSP1_CONTROL_30, WM2200_DSP1_SYS_ENA_SHIFT,
1538e10f8711SMark Brown 		   0, NULL, 0, wm2200_dsp_ev,
1539e10f8711SMark Brown 		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
154009d5d588SMark Brown SND_SOC_DAPM_PGA_E("DSP2", WM2200_DSP2_CONTROL_30, WM2200_DSP2_SYS_ENA_SHIFT,
1541e10f8711SMark Brown 		   0, NULL, 0, wm2200_dsp_ev,
1542e10f8711SMark Brown 		   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1543d5315a23SMark Brown 
1544d5315a23SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
1545d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
1546d5315a23SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 1,
1547d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX2_ENA_SHIFT, 0),
1548d5315a23SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 2,
1549d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX3_ENA_SHIFT, 0),
1550d5315a23SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 3,
1551d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX4_ENA_SHIFT, 0),
1552d5315a23SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4,
1553d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX5_ENA_SHIFT, 0),
1554d5315a23SMark Brown SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5,
1555d5315a23SMark Brown 		    WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0),
1556d5315a23SMark Brown 
1557999e068eSMark Brown SND_SOC_DAPM_MUX("AEC Loopback", WM2200_DAC_AEC_CONTROL_1,
1558999e068eSMark Brown 		 WM2200_AEC_LOOPBACK_ENA_SHIFT, 0, &wm2200_aec_loopback_mux),
1559999e068eSMark Brown 
1560d5315a23SMark Brown SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES,
1561d5315a23SMark Brown 		   WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0),
1562d5315a23SMark Brown SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES,
1563d5315a23SMark Brown 		   WM2200_OUT1R_ENA_SHIFT, 0, NULL, 0),
1564d5315a23SMark Brown 
1565d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_LP", 1, WM2200_EAR_PIECE_CTRL_1,
1566d5315a23SMark Brown 		   WM2200_EPD_LP_ENA_SHIFT, 0, NULL, 0),
1567d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_OUTP_LP", 1, WM2200_EAR_PIECE_CTRL_1,
1568d5315a23SMark Brown 		   WM2200_EPD_OUTP_LP_ENA_SHIFT, 0, NULL, 0),
1569d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LP", 1, WM2200_EAR_PIECE_CTRL_1,
1570d5315a23SMark Brown 		   WM2200_EPD_RMV_SHRT_LP_SHIFT, 0, NULL, 0),
1571d5315a23SMark Brown 
1572d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_LN", 1, WM2200_EAR_PIECE_CTRL_1,
1573d5315a23SMark Brown 		   WM2200_EPD_LN_ENA_SHIFT, 0, NULL, 0),
1574d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_OUTP_LN", 1, WM2200_EAR_PIECE_CTRL_1,
1575d5315a23SMark Brown 		   WM2200_EPD_OUTP_LN_ENA_SHIFT, 0, NULL, 0),
1576d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LN", 1, WM2200_EAR_PIECE_CTRL_1,
1577d5315a23SMark Brown 		   WM2200_EPD_RMV_SHRT_LN_SHIFT, 0, NULL, 0),
1578d5315a23SMark Brown 
1579d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_RP", 1, WM2200_EAR_PIECE_CTRL_2,
1580d5315a23SMark Brown 		   WM2200_EPD_RP_ENA_SHIFT, 0, NULL, 0),
1581d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_OUTP_RP", 1, WM2200_EAR_PIECE_CTRL_2,
1582d5315a23SMark Brown 		   WM2200_EPD_OUTP_RP_ENA_SHIFT, 0, NULL, 0),
1583d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RP", 1, WM2200_EAR_PIECE_CTRL_2,
1584d5315a23SMark Brown 		   WM2200_EPD_RMV_SHRT_RP_SHIFT, 0, NULL, 0),
1585d5315a23SMark Brown 
1586d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_RN", 1, WM2200_EAR_PIECE_CTRL_2,
1587d5315a23SMark Brown 		   WM2200_EPD_RN_ENA_SHIFT, 0, NULL, 0),
1588d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_OUTP_RN", 1, WM2200_EAR_PIECE_CTRL_2,
1589d5315a23SMark Brown 		   WM2200_EPD_OUTP_RN_ENA_SHIFT, 0, NULL, 0),
1590d5315a23SMark Brown SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RN", 1, WM2200_EAR_PIECE_CTRL_2,
1591d5315a23SMark Brown 		   WM2200_EPD_RMV_SHRT_RN_SHIFT, 0, NULL, 0),
1592d5315a23SMark Brown 
1593d5315a23SMark Brown SND_SOC_DAPM_PGA("OUT2L", WM2200_OUTPUT_ENABLES, WM2200_OUT2L_ENA_SHIFT,
1594d5315a23SMark Brown 		 0, NULL, 0),
1595d5315a23SMark Brown SND_SOC_DAPM_PGA("OUT2R", WM2200_OUTPUT_ENABLES, WM2200_OUT2R_ENA_SHIFT,
1596d5315a23SMark Brown 		 0, NULL, 0),
1597d5315a23SMark Brown 
1598d5315a23SMark Brown SND_SOC_DAPM_OUTPUT("EPOUTLN"),
1599d5315a23SMark Brown SND_SOC_DAPM_OUTPUT("EPOUTLP"),
1600d5315a23SMark Brown SND_SOC_DAPM_OUTPUT("EPOUTRN"),
1601d5315a23SMark Brown SND_SOC_DAPM_OUTPUT("EPOUTRP"),
1602d5315a23SMark Brown SND_SOC_DAPM_OUTPUT("SPK"),
1603d5315a23SMark Brown 
1604d5315a23SMark Brown WM2200_MIXER_WIDGETS(EQL, "EQL"),
1605d5315a23SMark Brown WM2200_MIXER_WIDGETS(EQR, "EQR"),
1606d5315a23SMark Brown 
1607d5315a23SMark Brown WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"),
1608d5315a23SMark Brown WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"),
1609d5315a23SMark Brown 
161009d5d588SMark Brown WM2200_DSP_WIDGETS(DSP1, "DSP1"),
161109d5d588SMark Brown WM2200_DSP_WIDGETS(DSP2, "DSP2"),
1612d5315a23SMark Brown 
1613d5315a23SMark Brown WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
1614d5315a23SMark Brown WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
1615d5315a23SMark Brown WM2200_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
1616d5315a23SMark Brown WM2200_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
1617d5315a23SMark Brown WM2200_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
1618d5315a23SMark Brown WM2200_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
1619d5315a23SMark Brown 
1620d5315a23SMark Brown WM2200_MIXER_WIDGETS(OUT1L, "OUT1L"),
1621d5315a23SMark Brown WM2200_MIXER_WIDGETS(OUT1R, "OUT1R"),
1622d5315a23SMark Brown WM2200_MIXER_WIDGETS(OUT2L, "OUT2L"),
1623d5315a23SMark Brown WM2200_MIXER_WIDGETS(OUT2R, "OUT2R"),
1624d5315a23SMark Brown };
1625d5315a23SMark Brown 
1626d5315a23SMark Brown static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
1627d5315a23SMark Brown 	/* Everything needs SYSCLK but only hook up things on the edge
1628d5315a23SMark Brown 	 * of the chip */
1629d5315a23SMark Brown 	{ "IN1L", NULL, "SYSCLK" },
1630d5315a23SMark Brown 	{ "IN1R", NULL, "SYSCLK" },
1631d5315a23SMark Brown 	{ "IN2L", NULL, "SYSCLK" },
1632d5315a23SMark Brown 	{ "IN2R", NULL, "SYSCLK" },
1633d5315a23SMark Brown 	{ "IN3L", NULL, "SYSCLK" },
1634d5315a23SMark Brown 	{ "IN3R", NULL, "SYSCLK" },
1635d5315a23SMark Brown 	{ "OUT1L", NULL, "SYSCLK" },
1636d5315a23SMark Brown 	{ "OUT1R", NULL, "SYSCLK" },
1637d5315a23SMark Brown 	{ "OUT2L", NULL, "SYSCLK" },
1638d5315a23SMark Brown 	{ "OUT2R", NULL, "SYSCLK" },
1639d5315a23SMark Brown 	{ "AIF1RX1", NULL, "SYSCLK" },
1640d5315a23SMark Brown 	{ "AIF1RX2", NULL, "SYSCLK" },
1641d5315a23SMark Brown 	{ "AIF1RX3", NULL, "SYSCLK" },
1642d5315a23SMark Brown 	{ "AIF1RX4", NULL, "SYSCLK" },
1643d5315a23SMark Brown 	{ "AIF1RX5", NULL, "SYSCLK" },
1644d5315a23SMark Brown 	{ "AIF1RX6", NULL, "SYSCLK" },
1645d5315a23SMark Brown 	{ "AIF1TX1", NULL, "SYSCLK" },
1646d5315a23SMark Brown 	{ "AIF1TX2", NULL, "SYSCLK" },
1647d5315a23SMark Brown 	{ "AIF1TX3", NULL, "SYSCLK" },
1648d5315a23SMark Brown 	{ "AIF1TX4", NULL, "SYSCLK" },
1649d5315a23SMark Brown 	{ "AIF1TX5", NULL, "SYSCLK" },
1650d5315a23SMark Brown 	{ "AIF1TX6", NULL, "SYSCLK" },
1651d5315a23SMark Brown 
1652d5315a23SMark Brown 	{ "IN1L", NULL, "AVDD" },
1653d5315a23SMark Brown 	{ "IN1R", NULL, "AVDD" },
1654d5315a23SMark Brown 	{ "IN2L", NULL, "AVDD" },
1655d5315a23SMark Brown 	{ "IN2R", NULL, "AVDD" },
1656d5315a23SMark Brown 	{ "IN3L", NULL, "AVDD" },
1657d5315a23SMark Brown 	{ "IN3R", NULL, "AVDD" },
1658d5315a23SMark Brown 	{ "OUT1L", NULL, "AVDD" },
1659d5315a23SMark Brown 	{ "OUT1R", NULL, "AVDD" },
1660d5315a23SMark Brown 
1661d5315a23SMark Brown 	{ "IN1L PGA", NULL, "IN1L" },
1662d5315a23SMark Brown 	{ "IN1R PGA", NULL, "IN1R" },
1663d5315a23SMark Brown 	{ "IN2L PGA", NULL, "IN2L" },
1664d5315a23SMark Brown 	{ "IN2R PGA", NULL, "IN2R" },
1665d5315a23SMark Brown 	{ "IN3L PGA", NULL, "IN3L" },
1666d5315a23SMark Brown 	{ "IN3R PGA", NULL, "IN3R" },
1667d5315a23SMark Brown 
1668d5315a23SMark Brown 	{ "Tone Generator", NULL, "TONE" },
1669d5315a23SMark Brown 
1670d5315a23SMark Brown 	{ "CP2", NULL, "CPVDD" },
1671d5315a23SMark Brown 	{ "MICBIAS1", NULL, "CP2" },
1672d5315a23SMark Brown 	{ "MICBIAS2", NULL, "CP2" },
1673d5315a23SMark Brown 
1674d5315a23SMark Brown 	{ "CP1", NULL, "CPVDD" },
1675d5315a23SMark Brown 	{ "EPD_LN", NULL, "CP1" },
1676d5315a23SMark Brown 	{ "EPD_LP", NULL, "CP1" },
1677d5315a23SMark Brown 	{ "EPD_RN", NULL, "CP1" },
1678d5315a23SMark Brown 	{ "EPD_RP", NULL, "CP1" },
1679d5315a23SMark Brown 
1680d5315a23SMark Brown 	{ "EPD_LP", NULL, "OUT1L" },
1681d5315a23SMark Brown 	{ "EPD_OUTP_LP", NULL, "EPD_LP" },
1682d5315a23SMark Brown 	{ "EPD_RMV_SHRT_LP", NULL, "EPD_OUTP_LP" },
1683d5315a23SMark Brown 	{ "EPOUTLP", NULL, "EPD_RMV_SHRT_LP" },
1684d5315a23SMark Brown 
1685d5315a23SMark Brown 	{ "EPD_LN", NULL, "OUT1L" },
1686d5315a23SMark Brown 	{ "EPD_OUTP_LN", NULL, "EPD_LN" },
1687d5315a23SMark Brown 	{ "EPD_RMV_SHRT_LN", NULL, "EPD_OUTP_LN" },
1688d5315a23SMark Brown 	{ "EPOUTLN", NULL, "EPD_RMV_SHRT_LN" },
1689d5315a23SMark Brown 
1690d5315a23SMark Brown 	{ "EPD_RP", NULL, "OUT1R" },
1691d5315a23SMark Brown 	{ "EPD_OUTP_RP", NULL, "EPD_RP" },
1692d5315a23SMark Brown 	{ "EPD_RMV_SHRT_RP", NULL, "EPD_OUTP_RP" },
1693d5315a23SMark Brown 	{ "EPOUTRP", NULL, "EPD_RMV_SHRT_RP" },
1694d5315a23SMark Brown 
1695d5315a23SMark Brown 	{ "EPD_RN", NULL, "OUT1R" },
1696d5315a23SMark Brown 	{ "EPD_OUTP_RN", NULL, "EPD_RN" },
1697d5315a23SMark Brown 	{ "EPD_RMV_SHRT_RN", NULL, "EPD_OUTP_RN" },
1698d5315a23SMark Brown 	{ "EPOUTRN", NULL, "EPD_RMV_SHRT_RN" },
1699d5315a23SMark Brown 
1700d5315a23SMark Brown 	{ "SPK", NULL, "OUT2L" },
1701d5315a23SMark Brown 	{ "SPK", NULL, "OUT2R" },
1702d5315a23SMark Brown 
1703999e068eSMark Brown 	{ "AEC Loopback", "OUT1L", "OUT1L" },
1704999e068eSMark Brown 	{ "AEC Loopback", "OUT1R", "OUT1R" },
1705999e068eSMark Brown 	{ "AEC Loopback", "OUT2L", "OUT2L" },
1706999e068eSMark Brown 	{ "AEC Loopback", "OUT2R", "OUT2R" },
1707999e068eSMark Brown 
1708d5315a23SMark Brown 	WM2200_MIXER_ROUTES("DSP1", "DSP1L"),
1709d5315a23SMark Brown 	WM2200_MIXER_ROUTES("DSP1", "DSP1R"),
1710d5315a23SMark Brown 	WM2200_MIXER_ROUTES("DSP2", "DSP2L"),
1711d5315a23SMark Brown 	WM2200_MIXER_ROUTES("DSP2", "DSP2R"),
1712d5315a23SMark Brown 
171309d5d588SMark Brown 	WM2200_DSP_AUX_ROUTES("DSP1"),
171409d5d588SMark Brown 	WM2200_DSP_AUX_ROUTES("DSP2"),
171509d5d588SMark Brown 
1716d5315a23SMark Brown 	WM2200_MIXER_ROUTES("OUT1L", "OUT1L"),
1717d5315a23SMark Brown 	WM2200_MIXER_ROUTES("OUT1R", "OUT1R"),
1718d5315a23SMark Brown 	WM2200_MIXER_ROUTES("OUT2L", "OUT2L"),
1719d5315a23SMark Brown 	WM2200_MIXER_ROUTES("OUT2R", "OUT2R"),
1720d5315a23SMark Brown 
1721d5315a23SMark Brown 	WM2200_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
1722d5315a23SMark Brown 	WM2200_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
1723d5315a23SMark Brown 	WM2200_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
1724d5315a23SMark Brown 	WM2200_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
1725d5315a23SMark Brown 	WM2200_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
1726d5315a23SMark Brown 	WM2200_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
1727d5315a23SMark Brown 
1728d5315a23SMark Brown 	WM2200_MIXER_ROUTES("EQL", "EQL"),
1729d5315a23SMark Brown 	WM2200_MIXER_ROUTES("EQR", "EQR"),
1730d5315a23SMark Brown 
1731d5315a23SMark Brown 	WM2200_MIXER_ROUTES("LHPF1", "LHPF1"),
1732d5315a23SMark Brown 	WM2200_MIXER_ROUTES("LHPF2", "LHPF2"),
1733d5315a23SMark Brown };
1734d5315a23SMark Brown 
1735d5315a23SMark Brown static int wm2200_probe(struct snd_soc_codec *codec)
1736d5315a23SMark Brown {
1737d5315a23SMark Brown 	struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev);
1738d5315a23SMark Brown 	int ret;
1739d5315a23SMark Brown 
1740d5315a23SMark Brown 	wm2200->codec = codec;
1741d5315a23SMark Brown 	codec->control_data = wm2200->regmap;
1742d5315a23SMark Brown 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
1743d5315a23SMark Brown 
1744d5315a23SMark Brown 	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
1745d5315a23SMark Brown 	if (ret != 0) {
1746d5315a23SMark Brown 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
1747d5315a23SMark Brown 		return ret;
1748d5315a23SMark Brown 	}
1749d5315a23SMark Brown 
1750d5315a23SMark Brown 	return ret;
1751d5315a23SMark Brown }
1752d5315a23SMark Brown 
1753d5315a23SMark Brown static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1754d5315a23SMark Brown {
1755d5315a23SMark Brown 	struct snd_soc_codec *codec = dai->codec;
1756d5315a23SMark Brown 	int lrclk, bclk, fmt_val;
1757d5315a23SMark Brown 
1758d5315a23SMark Brown 	lrclk = 0;
1759d5315a23SMark Brown 	bclk = 0;
1760d5315a23SMark Brown 
1761d5315a23SMark Brown 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1762d5315a23SMark Brown 	case SND_SOC_DAIFMT_DSP_A:
1763d5315a23SMark Brown 		fmt_val = 0;
1764d5315a23SMark Brown 		break;
1765d5315a23SMark Brown 	case SND_SOC_DAIFMT_DSP_B:
1766d5315a23SMark Brown 		fmt_val = 1;
1767d5315a23SMark Brown 		break;
1768d5315a23SMark Brown 	case SND_SOC_DAIFMT_I2S:
1769d5315a23SMark Brown 		fmt_val = 2;
1770d5315a23SMark Brown 		break;
1771d5315a23SMark Brown 	case SND_SOC_DAIFMT_LEFT_J:
1772d5315a23SMark Brown 		fmt_val = 3;
1773d5315a23SMark Brown 		break;
1774d5315a23SMark Brown 	default:
1775d5315a23SMark Brown 		dev_err(codec->dev, "Unsupported DAI format %d\n",
1776d5315a23SMark Brown 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1777d5315a23SMark Brown 		return -EINVAL;
1778d5315a23SMark Brown 	}
1779d5315a23SMark Brown 
1780d5315a23SMark Brown 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1781d5315a23SMark Brown 	case SND_SOC_DAIFMT_CBS_CFS:
1782d5315a23SMark Brown 		break;
1783d5315a23SMark Brown 	case SND_SOC_DAIFMT_CBS_CFM:
1784d5315a23SMark Brown 		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
1785d5315a23SMark Brown 		break;
1786d5315a23SMark Brown 	case SND_SOC_DAIFMT_CBM_CFS:
1787d5315a23SMark Brown 		bclk |= WM2200_AIF1_BCLK_MSTR;
1788d5315a23SMark Brown 		break;
1789d5315a23SMark Brown 	case SND_SOC_DAIFMT_CBM_CFM:
1790d5315a23SMark Brown 		lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
1791d5315a23SMark Brown 		bclk |= WM2200_AIF1_BCLK_MSTR;
1792d5315a23SMark Brown 		break;
1793d5315a23SMark Brown 	default:
1794d5315a23SMark Brown 		dev_err(codec->dev, "Unsupported master mode %d\n",
1795d5315a23SMark Brown 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
1796d5315a23SMark Brown 		return -EINVAL;
1797d5315a23SMark Brown 	}
1798d5315a23SMark Brown 
1799d5315a23SMark Brown 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1800d5315a23SMark Brown 	case SND_SOC_DAIFMT_NB_NF:
1801d5315a23SMark Brown 		break;
1802d5315a23SMark Brown 	case SND_SOC_DAIFMT_IB_IF:
1803d5315a23SMark Brown 		bclk |= WM2200_AIF1_BCLK_INV;
1804d5315a23SMark Brown 		lrclk |= WM2200_AIF1TX_LRCLK_INV;
1805d5315a23SMark Brown 		break;
1806d5315a23SMark Brown 	case SND_SOC_DAIFMT_IB_NF:
1807d5315a23SMark Brown 		bclk |= WM2200_AIF1_BCLK_INV;
1808d5315a23SMark Brown 		break;
1809d5315a23SMark Brown 	case SND_SOC_DAIFMT_NB_IF:
1810d5315a23SMark Brown 		lrclk |= WM2200_AIF1TX_LRCLK_INV;
1811d5315a23SMark Brown 		break;
1812d5315a23SMark Brown 	default:
1813d5315a23SMark Brown 		return -EINVAL;
1814d5315a23SMark Brown 	}
1815d5315a23SMark Brown 
1816d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR |
1817d5315a23SMark Brown 			    WM2200_AIF1_BCLK_INV, bclk);
1818d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
1819d5315a23SMark Brown 			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
1820d5315a23SMark Brown 			    lrclk);
1821d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_3,
1822d5315a23SMark Brown 			    WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
1823d5315a23SMark Brown 			    lrclk);
1824d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5,
1825d5315a23SMark Brown 			    WM2200_AIF1_FMT_MASK << 1, fmt_val << 1);
1826d5315a23SMark Brown 
1827d5315a23SMark Brown 	return 0;
1828d5315a23SMark Brown }
1829d5315a23SMark Brown 
1830d5315a23SMark Brown static int wm2200_sr_code[] = {
1831d5315a23SMark Brown 	0,
1832d5315a23SMark Brown 	12000,
1833d5315a23SMark Brown 	24000,
1834d5315a23SMark Brown 	48000,
1835d5315a23SMark Brown 	96000,
1836d5315a23SMark Brown 	192000,
1837d5315a23SMark Brown 	384000,
1838d5315a23SMark Brown 	768000,
1839d5315a23SMark Brown 	0,
1840d5315a23SMark Brown 	11025,
1841d5315a23SMark Brown 	22050,
1842d5315a23SMark Brown 	44100,
1843d5315a23SMark Brown 	88200,
1844d5315a23SMark Brown 	176400,
1845d5315a23SMark Brown 	352800,
1846d5315a23SMark Brown 	705600,
1847d5315a23SMark Brown 	4000,
1848d5315a23SMark Brown 	8000,
1849d5315a23SMark Brown 	16000,
1850d5315a23SMark Brown 	32000,
1851d5315a23SMark Brown 	64000,
1852d5315a23SMark Brown 	128000,
1853d5315a23SMark Brown 	256000,
1854d5315a23SMark Brown 	512000,
1855d5315a23SMark Brown };
1856d5315a23SMark Brown 
1857d5315a23SMark Brown #define WM2200_NUM_BCLK_RATES 12
1858d5315a23SMark Brown 
1859d5315a23SMark Brown static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = {
1860d5315a23SMark Brown 	6144000,
1861d5315a23SMark Brown 	3072000,
1862d5315a23SMark Brown 	2048000,
1863d5315a23SMark Brown 	1536000,
1864d5315a23SMark Brown 	768000,
1865d5315a23SMark Brown 	512000,
1866d5315a23SMark Brown 	384000,
1867d5315a23SMark Brown 	256000,
1868d5315a23SMark Brown 	192000,
1869d5315a23SMark Brown 	128000,
1870d5315a23SMark Brown 	96000,
1871d5315a23SMark Brown 	64000,
1872d5315a23SMark Brown };
1873d5315a23SMark Brown 
1874d5315a23SMark Brown static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
1875d5315a23SMark Brown 	5644800,
1876b0dfa454SMark Brown 	3763200,
1877d5315a23SMark Brown 	2882400,
1878d5315a23SMark Brown 	1881600,
1879d5315a23SMark Brown 	1411200,
1880d5315a23SMark Brown 	705600,
1881d5315a23SMark Brown 	470400,
1882d5315a23SMark Brown 	352800,
1883d5315a23SMark Brown 	176400,
1884d5315a23SMark Brown 	117600,
1885d5315a23SMark Brown 	88200,
1886d5315a23SMark Brown 	58800,
1887d5315a23SMark Brown };
1888d5315a23SMark Brown 
1889d5315a23SMark Brown static int wm2200_hw_params(struct snd_pcm_substream *substream,
1890d5315a23SMark Brown 			    struct snd_pcm_hw_params *params,
1891d5315a23SMark Brown 			    struct snd_soc_dai *dai)
1892d5315a23SMark Brown {
1893d5315a23SMark Brown 	struct snd_soc_codec *codec = dai->codec;
1894d5315a23SMark Brown 	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
1895d5315a23SMark Brown 	int i, bclk, lrclk, wl, fl, sr_code;
1896d5315a23SMark Brown 	int *bclk_rates;
1897d5315a23SMark Brown 
1898d5315a23SMark Brown 	/* Data sizes if not using TDM */
1899d5315a23SMark Brown 	wl = snd_pcm_format_width(params_format(params));
1900d5315a23SMark Brown 	if (wl < 0)
1901d5315a23SMark Brown 		return wl;
1902d5315a23SMark Brown 	fl = snd_soc_params_to_frame_size(params);
1903d5315a23SMark Brown 	if (fl < 0)
1904d5315a23SMark Brown 		return fl;
1905d5315a23SMark Brown 
1906d5315a23SMark Brown 	dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
1907d5315a23SMark Brown 		wl, fl);
1908d5315a23SMark Brown 
1909d5315a23SMark Brown 	/* Target BCLK rate */
1910d5315a23SMark Brown 	bclk = snd_soc_params_to_bclk(params);
1911d5315a23SMark Brown 	if (bclk < 0)
1912d5315a23SMark Brown 		return bclk;
1913d5315a23SMark Brown 
1914d5315a23SMark Brown 	if (!wm2200->sysclk) {
1915d5315a23SMark Brown 		dev_err(codec->dev, "SYSCLK has no rate set\n");
1916d5315a23SMark Brown 		return -EINVAL;
1917d5315a23SMark Brown 	}
1918d5315a23SMark Brown 
1919d5315a23SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm2200_sr_code); i++)
1920d5315a23SMark Brown 		if (wm2200_sr_code[i] == params_rate(params))
1921d5315a23SMark Brown 			break;
1922d5315a23SMark Brown 	if (i == ARRAY_SIZE(wm2200_sr_code)) {
1923d5315a23SMark Brown 		dev_err(codec->dev, "Unsupported sample rate: %dHz\n",
1924d5315a23SMark Brown 			params_rate(params));
1925d5315a23SMark Brown 		return -EINVAL;
1926d5315a23SMark Brown 	}
1927d5315a23SMark Brown 	sr_code = i;
1928d5315a23SMark Brown 
1929d5315a23SMark Brown 	dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n",
1930d5315a23SMark Brown 		bclk, wm2200->sysclk);
1931d5315a23SMark Brown 
1932d5315a23SMark Brown 	if (wm2200->sysclk % 4000)
1933d5315a23SMark Brown 		bclk_rates = wm2200_bclk_rates_cd;
1934d5315a23SMark Brown 	else
1935d5315a23SMark Brown 		bclk_rates = wm2200_bclk_rates_dat;
1936d5315a23SMark Brown 
1937d5315a23SMark Brown 	for (i = 0; i < WM2200_NUM_BCLK_RATES; i++)
1938d5315a23SMark Brown 		if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
1939d5315a23SMark Brown 			break;
1940d5315a23SMark Brown 	if (i == WM2200_NUM_BCLK_RATES) {
1941d5315a23SMark Brown 		dev_err(codec->dev,
1942d5315a23SMark Brown 			"No valid BCLK for %dHz found from %dHz SYSCLK\n",
1943d5315a23SMark Brown 			bclk, wm2200->sysclk);
1944d5315a23SMark Brown 		return -EINVAL;
1945d5315a23SMark Brown 	}
1946d5315a23SMark Brown 
1947d5315a23SMark Brown 	bclk = i;
1948d5315a23SMark Brown 	dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
1949d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1,
1950d5315a23SMark Brown 			    WM2200_AIF1_BCLK_DIV_MASK, bclk);
1951d5315a23SMark Brown 
1952d5315a23SMark Brown 	lrclk = bclk_rates[bclk] / params_rate(params);
1953d5315a23SMark Brown 	dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
1954d5315a23SMark Brown 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
1955d5315a23SMark Brown 	    dai->symmetric_rates)
1956d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7,
1957d5315a23SMark Brown 				    WM2200_AIF1RX_BCPF_MASK, lrclk);
1958d5315a23SMark Brown 	else
1959d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_6,
1960d5315a23SMark Brown 				    WM2200_AIF1TX_BCPF_MASK, lrclk);
1961d5315a23SMark Brown 
1962d5315a23SMark Brown 	i = (wl << WM2200_AIF1TX_WL_SHIFT) | wl;
1963d5315a23SMark Brown 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1964d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_9,
1965d5315a23SMark Brown 				    WM2200_AIF1RX_WL_MASK |
1966d5315a23SMark Brown 				    WM2200_AIF1RX_SLOT_LEN_MASK, i);
1967d5315a23SMark Brown 	else
1968d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_8,
1969d5315a23SMark Brown 				    WM2200_AIF1TX_WL_MASK |
1970d5315a23SMark Brown 				    WM2200_AIF1TX_SLOT_LEN_MASK, i);
1971d5315a23SMark Brown 
1972d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_CLOCKING_4,
1973d5315a23SMark Brown 			    WM2200_SAMPLE_RATE_1_MASK, sr_code);
1974d5315a23SMark Brown 
1975d5315a23SMark Brown 	return 0;
1976d5315a23SMark Brown }
1977d5315a23SMark Brown 
1978d5315a23SMark Brown static const struct snd_soc_dai_ops wm2200_dai_ops = {
1979d5315a23SMark Brown 	.set_fmt = wm2200_set_fmt,
1980d5315a23SMark Brown 	.hw_params = wm2200_hw_params,
1981d5315a23SMark Brown };
1982d5315a23SMark Brown 
1983d5315a23SMark Brown static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1984d5315a23SMark Brown 			     int source, unsigned int freq, int dir)
1985d5315a23SMark Brown {
1986d5315a23SMark Brown 	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
1987d5315a23SMark Brown 	int fval;
1988d5315a23SMark Brown 
1989d5315a23SMark Brown 	switch (clk_id) {
1990d5315a23SMark Brown 	case WM2200_CLK_SYSCLK:
1991d5315a23SMark Brown 		break;
1992d5315a23SMark Brown 
1993d5315a23SMark Brown 	default:
1994d5315a23SMark Brown 		dev_err(codec->dev, "Unknown clock %d\n", clk_id);
1995d5315a23SMark Brown 		return -EINVAL;
1996d5315a23SMark Brown 	}
1997d5315a23SMark Brown 
1998d5315a23SMark Brown 	switch (source) {
1999d5315a23SMark Brown 	case WM2200_CLKSRC_MCLK1:
2000d5315a23SMark Brown 	case WM2200_CLKSRC_MCLK2:
2001d5315a23SMark Brown 	case WM2200_CLKSRC_FLL:
2002d5315a23SMark Brown 	case WM2200_CLKSRC_BCLK1:
2003d5315a23SMark Brown 		break;
2004d5315a23SMark Brown 	default:
2005d5315a23SMark Brown 		dev_err(codec->dev, "Invalid source %d\n", source);
2006d5315a23SMark Brown 		return -EINVAL;
2007d5315a23SMark Brown 	}
2008d5315a23SMark Brown 
2009d5315a23SMark Brown 	switch (freq) {
2010d5315a23SMark Brown 	case 22579200:
2011d5315a23SMark Brown 	case 24576000:
2012d5315a23SMark Brown 		fval = 2;
2013d5315a23SMark Brown 		break;
2014d5315a23SMark Brown 	default:
2015d5315a23SMark Brown 		dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
2016d5315a23SMark Brown 		return -EINVAL;
2017d5315a23SMark Brown 	}
2018d5315a23SMark Brown 
2019d5315a23SMark Brown 	/* TODO: Check if MCLKs are in use and enable/disable pulls to
2020d5315a23SMark Brown 	 * match.
2021d5315a23SMark Brown 	 */
2022d5315a23SMark Brown 
2023d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK |
2024d5315a23SMark Brown 			    WM2200_SYSCLK_SRC_MASK,
2025d5315a23SMark Brown 			    fval << WM2200_SYSCLK_FREQ_SHIFT | source);
2026d5315a23SMark Brown 
2027d5315a23SMark Brown 	wm2200->sysclk = freq;
2028d5315a23SMark Brown 
2029d5315a23SMark Brown 	return 0;
2030d5315a23SMark Brown }
2031d5315a23SMark Brown 
2032d5315a23SMark Brown struct _fll_div {
2033d5315a23SMark Brown 	u16 fll_fratio;
2034d5315a23SMark Brown 	u16 fll_outdiv;
2035d5315a23SMark Brown 	u16 fll_refclk_div;
2036d5315a23SMark Brown 	u16 n;
2037d5315a23SMark Brown 	u16 theta;
2038d5315a23SMark Brown 	u16 lambda;
2039d5315a23SMark Brown };
2040d5315a23SMark Brown 
2041d5315a23SMark Brown static struct {
2042d5315a23SMark Brown 	unsigned int min;
2043d5315a23SMark Brown 	unsigned int max;
2044d5315a23SMark Brown 	u16 fll_fratio;
2045d5315a23SMark Brown 	int ratio;
2046d5315a23SMark Brown } fll_fratios[] = {
2047d5315a23SMark Brown 	{       0,    64000, 4, 16 },
2048d5315a23SMark Brown 	{   64000,   128000, 3,  8 },
2049d5315a23SMark Brown 	{  128000,   256000, 2,  4 },
2050d5315a23SMark Brown 	{  256000,  1000000, 1,  2 },
2051d5315a23SMark Brown 	{ 1000000, 13500000, 0,  1 },
2052d5315a23SMark Brown };
2053d5315a23SMark Brown 
2054d5315a23SMark Brown static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
2055d5315a23SMark Brown 		       unsigned int Fout)
2056d5315a23SMark Brown {
2057d5315a23SMark Brown 	unsigned int target;
2058d5315a23SMark Brown 	unsigned int div;
2059d5315a23SMark Brown 	unsigned int fratio, gcd_fll;
2060d5315a23SMark Brown 	int i;
2061d5315a23SMark Brown 
2062d5315a23SMark Brown 	/* Fref must be <=13.5MHz */
2063d5315a23SMark Brown 	div = 1;
2064d5315a23SMark Brown 	fll_div->fll_refclk_div = 0;
2065d5315a23SMark Brown 	while ((Fref / div) > 13500000) {
2066d5315a23SMark Brown 		div *= 2;
2067d5315a23SMark Brown 		fll_div->fll_refclk_div++;
2068d5315a23SMark Brown 
2069d5315a23SMark Brown 		if (div > 8) {
2070d5315a23SMark Brown 			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
2071d5315a23SMark Brown 			       Fref);
2072d5315a23SMark Brown 			return -EINVAL;
2073d5315a23SMark Brown 		}
2074d5315a23SMark Brown 	}
2075d5315a23SMark Brown 
2076d5315a23SMark Brown 	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
2077d5315a23SMark Brown 
2078d5315a23SMark Brown 	/* Apply the division for our remaining calculations */
2079d5315a23SMark Brown 	Fref /= div;
2080d5315a23SMark Brown 
2081d5315a23SMark Brown 	/* Fvco should be 90-100MHz; don't check the upper bound */
2082d5315a23SMark Brown 	div = 2;
2083d5315a23SMark Brown 	while (Fout * div < 90000000) {
2084d5315a23SMark Brown 		div++;
2085d5315a23SMark Brown 		if (div > 64) {
2086d5315a23SMark Brown 			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
2087d5315a23SMark Brown 			       Fout);
2088d5315a23SMark Brown 			return -EINVAL;
2089d5315a23SMark Brown 		}
2090d5315a23SMark Brown 	}
2091d5315a23SMark Brown 	target = Fout * div;
2092d5315a23SMark Brown 	fll_div->fll_outdiv = div - 1;
2093d5315a23SMark Brown 
2094d5315a23SMark Brown 	pr_debug("FLL Fvco=%dHz\n", target);
2095d5315a23SMark Brown 
2096d5315a23SMark Brown 	/* Find an appropraite FLL_FRATIO and factor it out of the target */
2097d5315a23SMark Brown 	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
2098d5315a23SMark Brown 		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
2099d5315a23SMark Brown 			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
2100d5315a23SMark Brown 			fratio = fll_fratios[i].ratio;
2101d5315a23SMark Brown 			break;
2102d5315a23SMark Brown 		}
2103d5315a23SMark Brown 	}
2104d5315a23SMark Brown 	if (i == ARRAY_SIZE(fll_fratios)) {
2105d5315a23SMark Brown 		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
2106d5315a23SMark Brown 		return -EINVAL;
2107d5315a23SMark Brown 	}
2108d5315a23SMark Brown 
2109d5315a23SMark Brown 	fll_div->n = target / (fratio * Fref);
2110d5315a23SMark Brown 
2111d5315a23SMark Brown 	if (target % Fref == 0) {
2112d5315a23SMark Brown 		fll_div->theta = 0;
2113d5315a23SMark Brown 		fll_div->lambda = 0;
2114d5315a23SMark Brown 	} else {
2115d5315a23SMark Brown 		gcd_fll = gcd(target, fratio * Fref);
2116d5315a23SMark Brown 
2117d5315a23SMark Brown 		fll_div->theta = (target - (fll_div->n * fratio * Fref))
2118d5315a23SMark Brown 			/ gcd_fll;
2119d5315a23SMark Brown 		fll_div->lambda = (fratio * Fref) / gcd_fll;
2120d5315a23SMark Brown 	}
2121d5315a23SMark Brown 
2122d5315a23SMark Brown 	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
2123d5315a23SMark Brown 		 fll_div->n, fll_div->theta, fll_div->lambda);
2124d5315a23SMark Brown 	pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
2125d5315a23SMark Brown 		 fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
2126d5315a23SMark Brown 		 fll_div->fll_refclk_div);
2127d5315a23SMark Brown 
2128d5315a23SMark Brown 	return 0;
2129d5315a23SMark Brown }
2130d5315a23SMark Brown 
2131d5315a23SMark Brown static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
2132d5315a23SMark Brown 			  unsigned int Fref, unsigned int Fout)
2133d5315a23SMark Brown {
2134d5315a23SMark Brown 	struct i2c_client *i2c = to_i2c_client(codec->dev);
2135d5315a23SMark Brown 	struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
2136d5315a23SMark Brown 	struct _fll_div factors;
2137d5315a23SMark Brown 	int ret, i, timeout;
2138d5315a23SMark Brown 
2139d5315a23SMark Brown 	if (!Fout) {
2140d5315a23SMark Brown 		dev_dbg(codec->dev, "FLL disabled");
2141d5315a23SMark Brown 
2142d5315a23SMark Brown 		if (wm2200->fll_fout)
2143d5315a23SMark Brown 			pm_runtime_put(codec->dev);
2144d5315a23SMark Brown 
2145d5315a23SMark Brown 		wm2200->fll_fout = 0;
2146d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
2147d5315a23SMark Brown 				    WM2200_FLL_ENA, 0);
2148d5315a23SMark Brown 		return 0;
2149d5315a23SMark Brown 	}
2150d5315a23SMark Brown 
2151d5315a23SMark Brown 	switch (source) {
2152d5315a23SMark Brown 	case WM2200_FLL_SRC_MCLK1:
2153d5315a23SMark Brown 	case WM2200_FLL_SRC_MCLK2:
2154d5315a23SMark Brown 	case WM2200_FLL_SRC_BCLK:
2155d5315a23SMark Brown 		break;
2156d5315a23SMark Brown 	default:
2157d5315a23SMark Brown 		dev_err(codec->dev, "Invalid FLL source %d\n", source);
2158d5315a23SMark Brown 		return -EINVAL;
2159d5315a23SMark Brown 	}
2160d5315a23SMark Brown 
2161d5315a23SMark Brown 	ret = fll_factors(&factors, Fref, Fout);
2162d5315a23SMark Brown 	if (ret < 0)
2163d5315a23SMark Brown 		return ret;
2164d5315a23SMark Brown 
2165d5315a23SMark Brown 	/* Disable the FLL while we reconfigure */
2166d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0);
2167d5315a23SMark Brown 
2168d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_2,
2169d5315a23SMark Brown 			    WM2200_FLL_OUTDIV_MASK | WM2200_FLL_FRATIO_MASK,
2170d5315a23SMark Brown 			    (factors.fll_outdiv << WM2200_FLL_OUTDIV_SHIFT) |
2171d5315a23SMark Brown 			    factors.fll_fratio);
2172d5315a23SMark Brown 	if (factors.theta) {
2173d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
2174d5315a23SMark Brown 				    WM2200_FLL_FRACN_ENA,
2175d5315a23SMark Brown 				    WM2200_FLL_FRACN_ENA);
2176d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
2177d5315a23SMark Brown 				    WM2200_FLL_EFS_ENA,
2178d5315a23SMark Brown 				    WM2200_FLL_EFS_ENA);
2179d5315a23SMark Brown 	} else {
2180d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
2181d5315a23SMark Brown 				    WM2200_FLL_FRACN_ENA, 0);
2182d5315a23SMark Brown 		snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
2183d5315a23SMark Brown 				    WM2200_FLL_EFS_ENA, 0);
2184d5315a23SMark Brown 	}
2185d5315a23SMark Brown 
2186d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK,
2187d5315a23SMark Brown 			    factors.theta);
2188d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK,
2189d5315a23SMark Brown 			    factors.n);
2190d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_7,
2191d5315a23SMark Brown 			    WM2200_FLL_CLK_REF_DIV_MASK |
2192d5315a23SMark Brown 			    WM2200_FLL_CLK_REF_SRC_MASK,
2193d5315a23SMark Brown 			    (factors.fll_refclk_div
2194d5315a23SMark Brown 			     << WM2200_FLL_CLK_REF_DIV_SHIFT) | source);
2195d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_FLL_EFS_1,
2196d5315a23SMark Brown 			    WM2200_FLL_LAMBDA_MASK, factors.lambda);
2197d5315a23SMark Brown 
2198d5315a23SMark Brown 	/* Clear any pending completions */
2199d5315a23SMark Brown 	try_wait_for_completion(&wm2200->fll_lock);
2200d5315a23SMark Brown 
2201d5315a23SMark Brown 	pm_runtime_get_sync(codec->dev);
2202d5315a23SMark Brown 
2203d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
2204d5315a23SMark Brown 			    WM2200_FLL_ENA, WM2200_FLL_ENA);
2205d5315a23SMark Brown 
2206d5315a23SMark Brown 	if (i2c->irq)
2207d5315a23SMark Brown 		timeout = 2;
2208d5315a23SMark Brown 	else
2209d5315a23SMark Brown 		timeout = 50;
2210d5315a23SMark Brown 
2211d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA,
2212d5315a23SMark Brown 			    WM2200_SYSCLK_ENA);
2213d5315a23SMark Brown 
2214d5315a23SMark Brown 	/* Poll for the lock; will use the interrupt to exit quickly */
2215d5315a23SMark Brown 	for (i = 0; i < timeout; i++) {
2216d5315a23SMark Brown 		if (i2c->irq) {
2217d5315a23SMark Brown 			ret = wait_for_completion_timeout(&wm2200->fll_lock,
2218d5315a23SMark Brown 							  msecs_to_jiffies(25));
2219d5315a23SMark Brown 			if (ret > 0)
2220d5315a23SMark Brown 				break;
2221d5315a23SMark Brown 		} else {
2222d5315a23SMark Brown 			msleep(1);
2223d5315a23SMark Brown 		}
2224d5315a23SMark Brown 
2225d5315a23SMark Brown 		ret = snd_soc_read(codec,
2226d5315a23SMark Brown 				   WM2200_INTERRUPT_RAW_STATUS_2);
2227d5315a23SMark Brown 		if (ret < 0) {
2228d5315a23SMark Brown 			dev_err(codec->dev,
2229d5315a23SMark Brown 				"Failed to read FLL status: %d\n",
2230d5315a23SMark Brown 				ret);
2231d5315a23SMark Brown 			continue;
2232d5315a23SMark Brown 		}
2233d5315a23SMark Brown 		if (ret & WM2200_FLL_LOCK_STS)
2234d5315a23SMark Brown 			break;
2235d5315a23SMark Brown 	}
2236d5315a23SMark Brown 	if (i == timeout) {
2237d5315a23SMark Brown 		dev_err(codec->dev, "FLL lock timed out\n");
2238d5315a23SMark Brown 		pm_runtime_put(codec->dev);
2239d5315a23SMark Brown 		return -ETIMEDOUT;
2240d5315a23SMark Brown 	}
2241d5315a23SMark Brown 
2242d5315a23SMark Brown 	wm2200->fll_src = source;
2243d5315a23SMark Brown 	wm2200->fll_fref = Fref;
2244d5315a23SMark Brown 	wm2200->fll_fout = Fout;
2245d5315a23SMark Brown 
2246d5315a23SMark Brown 	dev_dbg(codec->dev, "FLL running %dHz->%dHz\n", Fref, Fout);
2247d5315a23SMark Brown 
2248d5315a23SMark Brown 	return 0;
2249d5315a23SMark Brown }
2250d5315a23SMark Brown 
2251d5315a23SMark Brown static int wm2200_dai_probe(struct snd_soc_dai *dai)
2252d5315a23SMark Brown {
2253d5315a23SMark Brown 	struct snd_soc_codec *codec = dai->codec;
2254d5315a23SMark Brown 	unsigned int val = 0;
2255d5315a23SMark Brown 	int ret;
2256d5315a23SMark Brown 
2257d5315a23SMark Brown 	ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1);
2258d5315a23SMark Brown 	if (ret >= 0) {
2259d5315a23SMark Brown 		if ((ret & WM2200_GP1_FN_MASK) != 0) {
2260d5315a23SMark Brown 			dai->symmetric_rates = true;
2261d5315a23SMark Brown 			val = WM2200_AIF1TX_LRCLK_SRC;
2262d5315a23SMark Brown 		}
2263d5315a23SMark Brown 	} else {
2264d5315a23SMark Brown 		dev_err(codec->dev, "Failed to read GPIO 1 config: %d\n", ret);
2265d5315a23SMark Brown 	}
2266d5315a23SMark Brown 
2267d5315a23SMark Brown 	snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
2268d5315a23SMark Brown 			    WM2200_AIF1TX_LRCLK_SRC, val);
2269d5315a23SMark Brown 
2270d5315a23SMark Brown 	return 0;
2271d5315a23SMark Brown }
2272d5315a23SMark Brown 
2273d5315a23SMark Brown #define WM2200_RATES SNDRV_PCM_RATE_8000_48000
2274d5315a23SMark Brown 
2275d5315a23SMark Brown #define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
2276d5315a23SMark Brown 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
2277d5315a23SMark Brown 
2278d5315a23SMark Brown static struct snd_soc_dai_driver wm2200_dai = {
2279d5315a23SMark Brown 	.name = "wm2200",
2280d5315a23SMark Brown 	.probe = wm2200_dai_probe,
2281d5315a23SMark Brown 	.playback = {
2282d5315a23SMark Brown 		.stream_name = "Playback",
2283d5315a23SMark Brown 		.channels_min = 2,
2284d5315a23SMark Brown 		.channels_max = 2,
2285d5315a23SMark Brown 		.rates = WM2200_RATES,
2286d5315a23SMark Brown 		.formats = WM2200_FORMATS,
2287d5315a23SMark Brown 	},
2288d5315a23SMark Brown 	.capture = {
2289d5315a23SMark Brown 		 .stream_name = "Capture",
2290d5315a23SMark Brown 		 .channels_min = 2,
2291d5315a23SMark Brown 		 .channels_max = 2,
2292d5315a23SMark Brown 		 .rates = WM2200_RATES,
2293d5315a23SMark Brown 		 .formats = WM2200_FORMATS,
2294d5315a23SMark Brown 	 },
2295d5315a23SMark Brown 	.ops = &wm2200_dai_ops,
2296d5315a23SMark Brown };
2297d5315a23SMark Brown 
2298d5315a23SMark Brown static struct snd_soc_codec_driver soc_codec_wm2200 = {
2299d5315a23SMark Brown 	.probe = wm2200_probe,
2300d5315a23SMark Brown 
2301d5315a23SMark Brown 	.idle_bias_off = true,
230217c0cee9SMark Brown 	.ignore_pmdown_time = true,
2303d5315a23SMark Brown 	.set_sysclk = wm2200_set_sysclk,
2304d5315a23SMark Brown 	.set_pll = wm2200_set_fll,
2305d5315a23SMark Brown 
2306d5315a23SMark Brown 	.controls = wm2200_snd_controls,
2307d5315a23SMark Brown 	.num_controls = ARRAY_SIZE(wm2200_snd_controls),
2308d5315a23SMark Brown 	.dapm_widgets = wm2200_dapm_widgets,
2309d5315a23SMark Brown 	.num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets),
2310d5315a23SMark Brown 	.dapm_routes = wm2200_dapm_routes,
2311d5315a23SMark Brown 	.num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes),
2312d5315a23SMark Brown };
2313d5315a23SMark Brown 
2314d5315a23SMark Brown static irqreturn_t wm2200_irq(int irq, void *data)
2315d5315a23SMark Brown {
2316d5315a23SMark Brown 	struct wm2200_priv *wm2200 = data;
2317d5315a23SMark Brown 	unsigned int val, mask;
2318d5315a23SMark Brown 	int ret;
2319d5315a23SMark Brown 
2320d5315a23SMark Brown 	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, &val);
2321d5315a23SMark Brown 	if (ret != 0) {
2322d5315a23SMark Brown 		dev_err(wm2200->dev, "Failed to read IRQ status: %d\n", ret);
2323d5315a23SMark Brown 		return IRQ_NONE;
2324d5315a23SMark Brown 	}
2325d5315a23SMark Brown 
2326d5315a23SMark Brown 	ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2_MASK,
2327d5315a23SMark Brown 			   &mask);
2328d5315a23SMark Brown 	if (ret != 0) {
2329d5315a23SMark Brown 		dev_warn(wm2200->dev, "Failed to read IRQ mask: %d\n", ret);
2330d5315a23SMark Brown 		mask = 0;
2331d5315a23SMark Brown 	}
2332d5315a23SMark Brown 
2333d5315a23SMark Brown 	val &= ~mask;
2334d5315a23SMark Brown 
2335d5315a23SMark Brown 	if (val & WM2200_FLL_LOCK_EINT) {
2336d5315a23SMark Brown 		dev_dbg(wm2200->dev, "FLL locked\n");
2337d5315a23SMark Brown 		complete(&wm2200->fll_lock);
2338d5315a23SMark Brown 	}
2339d5315a23SMark Brown 
2340d5315a23SMark Brown 	if (val) {
2341d5315a23SMark Brown 		regmap_write(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, val);
2342d5315a23SMark Brown 
2343d5315a23SMark Brown 		return IRQ_HANDLED;
2344d5315a23SMark Brown 	} else {
2345d5315a23SMark Brown 		return IRQ_NONE;
2346d5315a23SMark Brown 	}
2347d5315a23SMark Brown }
2348d5315a23SMark Brown 
2349d5315a23SMark Brown static const struct regmap_config wm2200_regmap = {
2350d5315a23SMark Brown 	.reg_bits = 16,
2351d5315a23SMark Brown 	.val_bits = 16,
2352d5315a23SMark Brown 
2353eae2328dSMark Brown 	.max_register = WM2200_MAX_REGISTER + (ARRAY_SIZE(wm2200_ranges) *
2354eae2328dSMark Brown 					       WM2200_DSP_SPACING),
2355d5315a23SMark Brown 	.reg_defaults = wm2200_reg_defaults,
2356d5315a23SMark Brown 	.num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
2357d5315a23SMark Brown 	.volatile_reg = wm2200_volatile_register,
2358d5315a23SMark Brown 	.readable_reg = wm2200_readable_register,
2359d5315a23SMark Brown 	.cache_type = REGCACHE_RBTREE,
2360eae2328dSMark Brown 	.ranges = wm2200_ranges,
2361eae2328dSMark Brown 	.num_ranges = ARRAY_SIZE(wm2200_ranges),
2362d5315a23SMark Brown };
2363d5315a23SMark Brown 
2364d5315a23SMark Brown static const unsigned int wm2200_dig_vu[] = {
2365d5315a23SMark Brown 	WM2200_DAC_DIGITAL_VOLUME_1L,
2366d5315a23SMark Brown 	WM2200_DAC_DIGITAL_VOLUME_1R,
2367d5315a23SMark Brown 	WM2200_DAC_DIGITAL_VOLUME_2L,
2368d5315a23SMark Brown 	WM2200_DAC_DIGITAL_VOLUME_2R,
2369d5315a23SMark Brown 	WM2200_ADC_DIGITAL_VOLUME_1L,
2370d5315a23SMark Brown 	WM2200_ADC_DIGITAL_VOLUME_1R,
2371d5315a23SMark Brown 	WM2200_ADC_DIGITAL_VOLUME_2L,
2372d5315a23SMark Brown 	WM2200_ADC_DIGITAL_VOLUME_2R,
2373d5315a23SMark Brown 	WM2200_ADC_DIGITAL_VOLUME_3L,
2374d5315a23SMark Brown 	WM2200_ADC_DIGITAL_VOLUME_3R,
2375d5315a23SMark Brown };
2376d5315a23SMark Brown 
2377d5315a23SMark Brown static const unsigned int wm2200_mic_ctrl_reg[] = {
2378d5315a23SMark Brown 	WM2200_IN1L_CONTROL,
2379d5315a23SMark Brown 	WM2200_IN2L_CONTROL,
2380d5315a23SMark Brown 	WM2200_IN3L_CONTROL,
2381d5315a23SMark Brown };
2382d5315a23SMark Brown 
2383d5315a23SMark Brown static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
2384d5315a23SMark Brown 				      const struct i2c_device_id *id)
2385d5315a23SMark Brown {
2386d5315a23SMark Brown 	struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev);
2387d5315a23SMark Brown 	struct wm2200_priv *wm2200;
2388d5315a23SMark Brown 	unsigned int reg;
2389d5315a23SMark Brown 	int ret, i;
2390d5315a23SMark Brown 
2391d5315a23SMark Brown 	wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv),
2392d5315a23SMark Brown 			      GFP_KERNEL);
2393d5315a23SMark Brown 	if (wm2200 == NULL)
2394d5315a23SMark Brown 		return -ENOMEM;
2395d5315a23SMark Brown 
2396d5315a23SMark Brown 	wm2200->dev = &i2c->dev;
2397d5315a23SMark Brown 	init_completion(&wm2200->fll_lock);
2398d5315a23SMark Brown 
239998ad089fSMark Brown 	wm2200->regmap = devm_regmap_init_i2c(i2c, &wm2200_regmap);
2400d5315a23SMark Brown 	if (IS_ERR(wm2200->regmap)) {
2401d5315a23SMark Brown 		ret = PTR_ERR(wm2200->regmap);
2402d5315a23SMark Brown 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
2403d5315a23SMark Brown 			ret);
2404d5315a23SMark Brown 		goto err;
2405d5315a23SMark Brown 	}
2406d5315a23SMark Brown 
2407d5315a23SMark Brown 	if (pdata)
2408d5315a23SMark Brown 		wm2200->pdata = *pdata;
2409d5315a23SMark Brown 
2410d5315a23SMark Brown 	i2c_set_clientdata(i2c, wm2200);
2411d5315a23SMark Brown 
2412d5315a23SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++)
2413d5315a23SMark Brown 		wm2200->core_supplies[i].supply = wm2200_core_supply_names[i];
2414d5315a23SMark Brown 
241598ad089fSMark Brown 	ret = devm_regulator_bulk_get(&i2c->dev,
241698ad089fSMark Brown 				      ARRAY_SIZE(wm2200->core_supplies),
2417d5315a23SMark Brown 				      wm2200->core_supplies);
2418d5315a23SMark Brown 	if (ret != 0) {
2419d5315a23SMark Brown 		dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
2420d5315a23SMark Brown 			ret);
2421d5315a23SMark Brown 		goto err_regmap;
2422d5315a23SMark Brown 	}
2423d5315a23SMark Brown 
2424d5315a23SMark Brown 	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
2425d5315a23SMark Brown 				    wm2200->core_supplies);
2426d5315a23SMark Brown 	if (ret != 0) {
2427d5315a23SMark Brown 		dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
2428d5315a23SMark Brown 			ret);
2429d5315a23SMark Brown 		goto err_core;
2430d5315a23SMark Brown 	}
2431d5315a23SMark Brown 
2432d5315a23SMark Brown 	if (wm2200->pdata.ldo_ena) {
243398ad089fSMark Brown 		ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena,
243498ad089fSMark Brown 					    GPIOF_OUT_INIT_HIGH,
243598ad089fSMark Brown 					    "WM2200 LDOENA");
2436d5315a23SMark Brown 		if (ret < 0) {
2437d5315a23SMark Brown 			dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
2438d5315a23SMark Brown 				wm2200->pdata.ldo_ena, ret);
2439d5315a23SMark Brown 			goto err_enable;
2440d5315a23SMark Brown 		}
2441d5315a23SMark Brown 		msleep(2);
2442d5315a23SMark Brown 	}
2443d5315a23SMark Brown 
2444d5315a23SMark Brown 	if (wm2200->pdata.reset) {
244598ad089fSMark Brown 		ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset,
244698ad089fSMark Brown 					    GPIOF_OUT_INIT_HIGH,
244798ad089fSMark Brown 					    "WM2200 /RESET");
2448d5315a23SMark Brown 		if (ret < 0) {
2449d5315a23SMark Brown 			dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
2450d5315a23SMark Brown 				wm2200->pdata.reset, ret);
2451d5315a23SMark Brown 			goto err_ldo;
2452d5315a23SMark Brown 		}
2453d5315a23SMark Brown 	}
2454d5315a23SMark Brown 
2455d5315a23SMark Brown 	ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, &reg);
2456d5315a23SMark Brown 	if (ret < 0) {
2457d5315a23SMark Brown 		dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
2458d5315a23SMark Brown 		goto err_reset;
2459d5315a23SMark Brown 	}
2460d5315a23SMark Brown 	switch (reg) {
2461d5315a23SMark Brown 	case 0x2200:
2462d5315a23SMark Brown 		break;
2463d5315a23SMark Brown 
2464d5315a23SMark Brown 	default:
2465d5315a23SMark Brown 		dev_err(&i2c->dev, "Device is not a WM2200, ID is %x\n", reg);
2466d5315a23SMark Brown 		ret = -EINVAL;
2467d5315a23SMark Brown 		goto err_reset;
2468d5315a23SMark Brown 	}
2469d5315a23SMark Brown 
2470d5315a23SMark Brown 	ret = regmap_read(wm2200->regmap, WM2200_DEVICE_REVISION, &reg);
2471d5315a23SMark Brown 	if (ret < 0) {
2472d5315a23SMark Brown 		dev_err(&i2c->dev, "Failed to read revision register\n");
2473d5315a23SMark Brown 		goto err_reset;
2474d5315a23SMark Brown 	}
2475d5315a23SMark Brown 
2476916be22cSAxel Lin 	wm2200->rev = reg & WM2200_DEVICE_REVISION_MASK;
2477d5315a23SMark Brown 
2478d5315a23SMark Brown 	dev_info(&i2c->dev, "revision %c\n", wm2200->rev + 'A');
2479d5315a23SMark Brown 
2480d5315a23SMark Brown 	switch (wm2200->rev) {
2481d5315a23SMark Brown 	case 0:
24825ae9eb4cSMark Brown 	case 1:
2483d5315a23SMark Brown 		ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch,
2484d5315a23SMark Brown 					    ARRAY_SIZE(wm2200_reva_patch));
2485d5315a23SMark Brown 		if (ret != 0) {
2486d5315a23SMark Brown 			dev_err(&i2c->dev, "Failed to register patch: %d\n",
2487d5315a23SMark Brown 				ret);
2488d5315a23SMark Brown 		}
2489d5315a23SMark Brown 		break;
2490d5315a23SMark Brown 	default:
2491d5315a23SMark Brown 		break;
2492d5315a23SMark Brown 	}
2493d5315a23SMark Brown 
2494d5315a23SMark Brown 	ret = wm2200_reset(wm2200);
2495d5315a23SMark Brown 	if (ret < 0) {
2496d5315a23SMark Brown 		dev_err(&i2c->dev, "Failed to issue reset\n");
2497d5315a23SMark Brown 		goto err_reset;
2498d5315a23SMark Brown 	}
2499d5315a23SMark Brown 
2500d5315a23SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.gpio_defaults); i++) {
2501d5315a23SMark Brown 		if (!wm2200->pdata.gpio_defaults[i])
2502d5315a23SMark Brown 			continue;
2503d5315a23SMark Brown 
2504d5315a23SMark Brown 		regmap_write(wm2200->regmap, WM2200_GPIO_CTRL_1 + i,
2505d5315a23SMark Brown 			     wm2200->pdata.gpio_defaults[i]);
2506d5315a23SMark Brown 	}
2507d5315a23SMark Brown 
2508d5315a23SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm2200_dig_vu); i++)
2509d5315a23SMark Brown 		regmap_update_bits(wm2200->regmap, wm2200_dig_vu[i],
2510d5315a23SMark Brown 				   WM2200_OUT_VU, WM2200_OUT_VU);
2511d5315a23SMark Brown 
2512d5315a23SMark Brown 	/* Assign slots 1-6 to channels 1-6 for both TX and RX */
2513d5315a23SMark Brown 	for (i = 0; i < 6; i++) {
2514d5315a23SMark Brown 		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_10 + i, i);
2515d5315a23SMark Brown 		regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i);
2516d5315a23SMark Brown 	}
2517d5315a23SMark Brown 
2518d5315a23SMark Brown 	for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) {
2519d5315a23SMark Brown 		regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i],
2520d5315a23SMark Brown 				   WM2200_IN1_MODE_MASK |
2521d5315a23SMark Brown 				   WM2200_IN1_DMIC_SUP_MASK,
2522d5315a23SMark Brown 				   (wm2200->pdata.in_mode[i] <<
2523d5315a23SMark Brown 				    WM2200_IN1_MODE_SHIFT) |
2524d5315a23SMark Brown 				   (wm2200->pdata.dmic_sup[i] <<
2525d5315a23SMark Brown 				    WM2200_IN1_DMIC_SUP_SHIFT));
2526d5315a23SMark Brown 	}
2527d5315a23SMark Brown 
2528d5315a23SMark Brown 	if (i2c->irq) {
2529d5315a23SMark Brown 		ret = request_threaded_irq(i2c->irq, NULL, wm2200_irq,
2530d5315a23SMark Brown 					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
2531d5315a23SMark Brown 					   "wm2200", wm2200);
2532d5315a23SMark Brown 		if (ret == 0)
2533d5315a23SMark Brown 			regmap_update_bits(wm2200->regmap,
2534d5315a23SMark Brown 					   WM2200_INTERRUPT_STATUS_2_MASK,
2535d5315a23SMark Brown 					   WM2200_FLL_LOCK_EINT, 0);
2536d5315a23SMark Brown 		else
2537d5315a23SMark Brown 			dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
2538d5315a23SMark Brown 				i2c->irq, ret);
2539d5315a23SMark Brown 	}
2540d5315a23SMark Brown 
2541d5315a23SMark Brown 	pm_runtime_set_active(&i2c->dev);
2542d5315a23SMark Brown 	pm_runtime_enable(&i2c->dev);
2543d5315a23SMark Brown 	pm_request_idle(&i2c->dev);
2544d5315a23SMark Brown 
2545d5315a23SMark Brown 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_wm2200,
2546d5315a23SMark Brown 				     &wm2200_dai, 1);
2547d5315a23SMark Brown 	if (ret != 0) {
2548d5315a23SMark Brown 		dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
2549d5315a23SMark Brown 		goto err_pm_runtime;
2550d5315a23SMark Brown 	}
2551d5315a23SMark Brown 
2552d5315a23SMark Brown 	return 0;
2553d5315a23SMark Brown 
2554d5315a23SMark Brown err_pm_runtime:
2555d5315a23SMark Brown 	pm_runtime_disable(&i2c->dev);
2556d5315a23SMark Brown err_reset:
255798ad089fSMark Brown 	if (wm2200->pdata.reset)
2558d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
2559d5315a23SMark Brown err_ldo:
256098ad089fSMark Brown 	if (wm2200->pdata.ldo_ena)
2561d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
2562d5315a23SMark Brown err_enable:
2563d5315a23SMark Brown 	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
2564d5315a23SMark Brown 			       wm2200->core_supplies);
2565d5315a23SMark Brown err_core:
2566d5315a23SMark Brown err_regmap:
2567d5315a23SMark Brown err:
2568d5315a23SMark Brown 	return ret;
2569d5315a23SMark Brown }
2570d5315a23SMark Brown 
2571d5315a23SMark Brown static __devexit int wm2200_i2c_remove(struct i2c_client *i2c)
2572d5315a23SMark Brown {
2573d5315a23SMark Brown 	struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c);
2574d5315a23SMark Brown 
2575d5315a23SMark Brown 	snd_soc_unregister_codec(&i2c->dev);
2576d5315a23SMark Brown 	if (i2c->irq)
2577d5315a23SMark Brown 		free_irq(i2c->irq, wm2200);
257898ad089fSMark Brown 	if (wm2200->pdata.reset)
2579d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.reset, 0);
258098ad089fSMark Brown 	if (wm2200->pdata.ldo_ena)
2581d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
2582d5315a23SMark Brown 
2583d5315a23SMark Brown 	return 0;
2584d5315a23SMark Brown }
2585d5315a23SMark Brown 
2586d5315a23SMark Brown #ifdef CONFIG_PM_RUNTIME
2587d5315a23SMark Brown static int wm2200_runtime_suspend(struct device *dev)
2588d5315a23SMark Brown {
2589d5315a23SMark Brown 	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
2590d5315a23SMark Brown 
2591d5315a23SMark Brown 	regcache_cache_only(wm2200->regmap, true);
2592d5315a23SMark Brown 	regcache_mark_dirty(wm2200->regmap);
2593d5315a23SMark Brown 	if (wm2200->pdata.ldo_ena)
2594d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
2595d5315a23SMark Brown 	regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
2596d5315a23SMark Brown 			       wm2200->core_supplies);
2597d5315a23SMark Brown 
2598d5315a23SMark Brown 	return 0;
2599d5315a23SMark Brown }
2600d5315a23SMark Brown 
2601d5315a23SMark Brown static int wm2200_runtime_resume(struct device *dev)
2602d5315a23SMark Brown {
2603d5315a23SMark Brown 	struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
2604d5315a23SMark Brown 	int ret;
2605d5315a23SMark Brown 
2606d5315a23SMark Brown 	ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
2607d5315a23SMark Brown 				    wm2200->core_supplies);
2608d5315a23SMark Brown 	if (ret != 0) {
2609d5315a23SMark Brown 		dev_err(dev, "Failed to enable supplies: %d\n",
2610d5315a23SMark Brown 			ret);
2611d5315a23SMark Brown 		return ret;
2612d5315a23SMark Brown 	}
2613d5315a23SMark Brown 
2614d5315a23SMark Brown 	if (wm2200->pdata.ldo_ena) {
2615d5315a23SMark Brown 		gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1);
2616d5315a23SMark Brown 		msleep(2);
2617d5315a23SMark Brown 	}
2618d5315a23SMark Brown 
2619d5315a23SMark Brown 	regcache_cache_only(wm2200->regmap, false);
2620d5315a23SMark Brown 	regcache_sync(wm2200->regmap);
2621d5315a23SMark Brown 
2622d5315a23SMark Brown 	return 0;
2623d5315a23SMark Brown }
2624d5315a23SMark Brown #endif
2625d5315a23SMark Brown 
2626d5315a23SMark Brown static struct dev_pm_ops wm2200_pm = {
2627d5315a23SMark Brown 	SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
2628d5315a23SMark Brown 			   NULL)
2629d5315a23SMark Brown };
2630d5315a23SMark Brown 
2631d5315a23SMark Brown static const struct i2c_device_id wm2200_i2c_id[] = {
2632d5315a23SMark Brown 	{ "wm2200", 0 },
2633d5315a23SMark Brown 	{ }
2634d5315a23SMark Brown };
2635d5315a23SMark Brown MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
2636d5315a23SMark Brown 
2637d5315a23SMark Brown static struct i2c_driver wm2200_i2c_driver = {
2638d5315a23SMark Brown 	.driver = {
2639d5315a23SMark Brown 		.name = "wm2200",
2640d5315a23SMark Brown 		.owner = THIS_MODULE,
2641d5315a23SMark Brown 		.pm = &wm2200_pm,
2642d5315a23SMark Brown 	},
2643d5315a23SMark Brown 	.probe =    wm2200_i2c_probe,
2644d5315a23SMark Brown 	.remove =   __devexit_p(wm2200_i2c_remove),
2645d5315a23SMark Brown 	.id_table = wm2200_i2c_id,
2646d5315a23SMark Brown };
2647d5315a23SMark Brown 
2648a9418ddcSSachin Kamat module_i2c_driver(wm2200_i2c_driver);
2649d5315a23SMark Brown 
2650d5315a23SMark Brown MODULE_DESCRIPTION("ASoC WM2200 driver");
2651d5315a23SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2652d5315a23SMark Brown MODULE_LICENSE("GPL");
2653