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