blob: 06d4e612a164e45505c664b1b6be455a85d9aaa3 [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
Mark Brown6e87bad2012-10-05 19:43:18 +01001153static int wm2200_setup_algs(struct snd_soc_codec *codec, int base)
1154{
1155 struct regmap *regmap = codec->control_data;
1156 struct wmfw_adsp1_id_hdr id;
1157 struct wmfw_adsp1_alg_hdr *alg;
1158 size_t algs;
1159 int zm, dm, pm, ret, i;
1160 __be32 val;
1161
1162 switch (base) {
1163 case WM2200_DSP1_CONTROL_1:
1164 dm = WM2200_DSP1_DM_BASE;
1165 pm = WM2200_DSP1_PM_BASE;
1166 zm = WM2200_DSP1_ZM_BASE;
1167 break;
1168 case WM2200_DSP2_CONTROL_1:
1169 dm = WM2200_DSP2_DM_BASE;
1170 pm = WM2200_DSP2_PM_BASE;
1171 zm = WM2200_DSP2_ZM_BASE;
1172 break;
1173 default:
1174 dev_err(codec->dev, "BASE %x\n", base);
1175 BUG_ON(1);
1176 return -EINVAL;
1177 }
1178
1179 ret = regmap_raw_read(regmap, dm, &id, sizeof(id));
1180 if (ret != 0) {
1181 dev_err(codec->dev, "Failed to read algorithm info: %d\n",
1182 ret);
1183 return ret;
1184 }
1185
1186 algs = be32_to_cpu(id.algs);
1187 dev_info(codec->dev, "Firmware: %x v%d.%d.%d, %d algorithms\n",
1188 be32_to_cpu(id.fw.id),
1189 (be32_to_cpu(id.fw.ver) & 0xff000) >> 16,
1190 (be32_to_cpu(id.fw.ver) & 0xff00) >> 8,
1191 be32_to_cpu(id.fw.ver) & 0xff,
1192 algs);
1193
1194 /* Read the terminator first to validate the length */
1195 ret = regmap_raw_read(regmap, dm +
1196 (sizeof(id) + (algs * sizeof(*alg))) / 2,
1197 &val, sizeof(val));
1198 if (ret != 0) {
1199 dev_err(codec->dev, "Failed to read algorithm list end: %d\n",
1200 ret);
1201 return ret;
1202 }
1203
1204 if (be32_to_cpu(val) != 0xbedead)
1205 dev_warn(codec->dev, "Algorithm list end %x 0x%x != 0xbeadead\n",
1206 (sizeof(id) + (algs * sizeof(*alg))) / 2,
1207 be32_to_cpu(val));
1208
1209 alg = kzalloc(sizeof(*alg) * algs, GFP_KERNEL);
1210 if (!alg)
1211 return -ENOMEM;
1212
1213 ret = regmap_raw_read(regmap, dm + (sizeof(id) / 2),
1214 alg, algs * sizeof(*alg));
1215 if (ret != 0) {
1216 dev_err(codec->dev, "Failed to read algorithm list: %d\n",
1217 ret);
1218 goto out;
1219 }
1220
1221 for (i = 0; i < algs; i++) {
1222 dev_info(codec->dev, "%d: ID %x v%d.%d.%d\n",
1223 i, be32_to_cpu(alg[i].alg.id),
1224 (be32_to_cpu(alg[i].alg.ver) & 0xff000) >> 16,
1225 (be32_to_cpu(alg[i].alg.ver) & 0xff00) >> 8,
1226 be32_to_cpu(alg[i].alg.ver) & 0xff);
1227 }
1228
1229out:
1230 kfree(alg);
1231 return ret;
1232}
1233
1234static int wm2200_load_coeff(struct snd_soc_codec *codec, int base)
1235{
1236 struct regmap *regmap = codec->control_data;
1237 struct wmfw_coeff_hdr *hdr;
1238 struct wmfw_coeff_item *blk;
1239 const struct firmware *firmware;
1240 const char *file, *region_name;
1241 int ret, dm, pm, zm, pos, blocks, type, offset, reg;
1242
1243 switch (base) {
1244 case WM2200_DSP1_CONTROL_1:
1245 file = "wm2200-dsp1.bin";
1246 dm = WM2200_DSP1_DM_BASE;
1247 pm = WM2200_DSP1_PM_BASE;
1248 zm = WM2200_DSP1_ZM_BASE;
1249 break;
1250 case WM2200_DSP2_CONTROL_1:
1251 file = "wm2200-dsp2.bin";
1252 dm = WM2200_DSP2_DM_BASE;
1253 pm = WM2200_DSP2_PM_BASE;
1254 zm = WM2200_DSP2_ZM_BASE;
1255 break;
1256 default:
1257 dev_err(codec->dev, "BASE %x\n", base);
1258 BUG_ON(1);
1259 return -EINVAL;
1260 }
1261
1262 ret = request_firmware(&firmware, file, codec->dev);
1263 if (ret != 0) {
1264 dev_err(codec->dev, "Failed to request '%s'\n", file);
1265 return ret;
1266 }
1267
1268 if (sizeof(*hdr) >= firmware->size) {
1269 dev_err(codec->dev, "%s: file too short, %d bytes\n",
1270 file, firmware->size);
1271 return -EINVAL;
1272 }
1273
1274 hdr = (void*)&firmware->data[0];
1275 if (memcmp(hdr->magic, "WMDR", 4) != 0) {
1276 dev_err(codec->dev, "%s: invalid magic\n", file);
1277 return -EINVAL;
1278 }
1279
1280 dev_dbg(codec->dev, "%s: v%d.%d.%d\n", file,
1281 (le32_to_cpu(hdr->ver) >> 16) & 0xff,
1282 (le32_to_cpu(hdr->ver) >> 8) & 0xff,
1283 le32_to_cpu(hdr->ver) & 0xff);
1284
1285 pos = le32_to_cpu(hdr->len);
1286
1287 blocks = 0;
1288 while (pos < firmware->size &&
1289 pos - firmware->size > sizeof(*blk)) {
1290 blk = (void*)(&firmware->data[pos]);
1291
1292 type = be32_to_cpu(blk->type) & 0xff;
1293 offset = le32_to_cpu(blk->offset) & 0xffffff;
1294
1295 dev_dbg(codec->dev, "%s.%d: %x v%d.%d.%d\n",
1296 file, blocks, le32_to_cpu(blk->id),
1297 (le32_to_cpu(blk->ver) >> 16) & 0xff,
1298 (le32_to_cpu(blk->ver) >> 8) & 0xff,
1299 le32_to_cpu(blk->ver) & 0xff);
1300 dev_dbg(codec->dev, "%s.%d: %d bytes at 0x%x in %x\n",
1301 file, blocks, le32_to_cpu(blk->len), offset, type);
1302
1303 reg = 0;
1304 region_name = "Unknown";
1305 switch (type) {
1306 case WMFW_NAME_TEXT:
1307 case WMFW_INFO_TEXT:
1308 break;
1309 case WMFW_ABSOLUTE:
1310 region_name = "register";
1311 reg = offset;
1312 break;
1313 default:
1314 dev_err(codec->dev, "Unknown region type %x\n", type);
1315 break;
1316 }
1317
1318 if (reg) {
1319 ret = regmap_raw_write(regmap, reg, blk->data,
1320 le32_to_cpu(blk->len));
1321 if (ret != 0) {
1322 dev_err(codec->dev,
1323 "%s.%d: Failed to write to %x in %s\n",
1324 file, blocks, reg, region_name);
1325 }
1326 }
1327
1328 pos += le32_to_cpu(blk->len) + sizeof(*blk);
1329 blocks++;
1330 }
1331
1332 if (pos > firmware->size)
1333 dev_warn(codec->dev, "%s.%d: %d bytes at end of file\n",
1334 file, blocks, pos - firmware->size);
1335
1336 return 0;
1337}
1338
Mark Browne10f8712012-10-04 16:31:52 +01001339static int wm2200_dsp_ev(struct snd_soc_dapm_widget *w,
1340 struct snd_kcontrol *kcontrol,
1341 int event)
1342{
1343 struct snd_soc_codec *codec = w->codec;
1344 int base = w->reg - WM2200_DSP_CONTROL_30;
1345 int ret;
1346
1347 switch (event) {
1348 case SND_SOC_DAPM_POST_PMU:
1349 ret = wm2200_dsp_load(codec, base);
1350 if (ret != 0)
1351 return ret;
1352
Mark Brown6e87bad2012-10-05 19:43:18 +01001353 ret = wm2200_setup_algs(codec, base);
1354 if (ret != 0)
1355 return ret;
1356
1357 ret = wm2200_load_coeff(codec, base);
1358 if (ret != 0)
1359 return ret;
1360
Mark Browne10f8712012-10-04 16:31:52 +01001361 /* Start the core running */
1362 snd_soc_update_bits(codec, w->reg,
1363 WM2200_DSP1_CORE_ENA | WM2200_DSP1_START,
1364 WM2200_DSP1_CORE_ENA | WM2200_DSP1_START);
1365 break;
1366
1367 case SND_SOC_DAPM_PRE_PMD:
1368 /* Halt the core */
1369 snd_soc_update_bits(codec, w->reg,
1370 WM2200_DSP1_CORE_ENA | WM2200_DSP1_START,
1371 0);
1372
1373 snd_soc_update_bits(codec, base + WM2200_DSP_CONTROL_19,
1374 WM2200_DSP1_WDMA_BUFFER_LENGTH_MASK, 0);
1375 break;
1376
1377 default:
1378 break;
1379 }
1380
1381 return 0;
1382}
1383
Mark Brownd5315a22012-01-25 19:29:41 +00001384static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0);
1385static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
1386static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0);
1387
1388static const char *wm2200_mixer_texts[] = {
1389 "None",
1390 "Tone Generator",
Mark Brown999e0682012-10-02 19:30:17 +01001391 "AEC Loopback",
Mark Brownd5315a22012-01-25 19:29:41 +00001392 "IN1L",
1393 "IN1R",
1394 "IN2L",
1395 "IN2R",
1396 "IN3L",
1397 "IN3R",
1398 "AIF1RX1",
1399 "AIF1RX2",
1400 "AIF1RX3",
1401 "AIF1RX4",
1402 "AIF1RX5",
1403 "AIF1RX6",
1404 "EQL",
1405 "EQR",
1406 "LHPF1",
1407 "LHPF2",
1408 "LHPF3",
1409 "LHPF4",
1410 "DSP1.1",
1411 "DSP1.2",
1412 "DSP1.3",
1413 "DSP1.4",
1414 "DSP1.5",
1415 "DSP1.6",
1416 "DSP2.1",
1417 "DSP2.2",
1418 "DSP2.3",
1419 "DSP2.4",
1420 "DSP2.5",
1421 "DSP2.6",
1422};
1423
1424static int wm2200_mixer_values[] = {
1425 0x00,
1426 0x04, /* Tone */
1427 0x08, /* AEC */
1428 0x10, /* Input */
1429 0x11,
1430 0x12,
1431 0x13,
1432 0x14,
1433 0x15,
1434 0x20, /* AIF */
1435 0x21,
1436 0x22,
1437 0x23,
1438 0x24,
1439 0x25,
1440 0x50, /* EQ */
1441 0x51,
1442 0x52,
1443 0x60, /* LHPF1 */
1444 0x61, /* LHPF2 */
1445 0x68, /* DSP1 */
1446 0x69,
1447 0x6a,
1448 0x6b,
1449 0x6c,
1450 0x6d,
1451 0x70, /* DSP2 */
1452 0x71,
1453 0x72,
1454 0x73,
1455 0x74,
1456 0x75,
1457};
1458
1459#define WM2200_MIXER_CONTROLS(name, base) \
1460 SOC_SINGLE_TLV(name " Input 1 Volume", base + 1 , \
1461 WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
1462 SOC_SINGLE_TLV(name " Input 2 Volume", base + 3 , \
1463 WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
1464 SOC_SINGLE_TLV(name " Input 3 Volume", base + 5 , \
1465 WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv), \
1466 SOC_SINGLE_TLV(name " Input 4 Volume", base + 7 , \
1467 WM2200_MIXER_VOL_SHIFT, 80, 0, mixer_tlv)
1468
1469#define WM2200_MUX_ENUM_DECL(name, reg) \
1470 SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \
1471 wm2200_mixer_texts, wm2200_mixer_values)
1472
1473#define WM2200_MUX_CTL_DECL(name) \
1474 const struct snd_kcontrol_new name##_mux = \
1475 SOC_DAPM_VALUE_ENUM("Route", name##_enum)
1476
1477#define WM2200_MIXER_ENUMS(name, base_reg) \
1478 static WM2200_MUX_ENUM_DECL(name##_in1_enum, base_reg); \
1479 static WM2200_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \
1480 static WM2200_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \
1481 static WM2200_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \
1482 static WM2200_MUX_CTL_DECL(name##_in1); \
1483 static WM2200_MUX_CTL_DECL(name##_in2); \
1484 static WM2200_MUX_CTL_DECL(name##_in3); \
Mark Brownffa8d9d2012-01-29 21:45:31 +00001485 static WM2200_MUX_CTL_DECL(name##_in4)
Mark Brownd5315a22012-01-25 19:29:41 +00001486
Mark Brown09d5d582012-10-03 15:57:03 +01001487#define WM2200_DSP_ENUMS(name, base_reg) \
1488 static WM2200_MUX_ENUM_DECL(name##_aux1_enum, base_reg); \
1489 static WM2200_MUX_ENUM_DECL(name##_aux2_enum, base_reg + 1); \
1490 static WM2200_MUX_ENUM_DECL(name##_aux3_enum, base_reg + 2); \
1491 static WM2200_MUX_ENUM_DECL(name##_aux4_enum, base_reg + 3); \
1492 static WM2200_MUX_ENUM_DECL(name##_aux5_enum, base_reg + 4); \
1493 static WM2200_MUX_ENUM_DECL(name##_aux6_enum, base_reg + 5); \
1494 static WM2200_MUX_CTL_DECL(name##_aux1); \
1495 static WM2200_MUX_CTL_DECL(name##_aux2); \
1496 static WM2200_MUX_CTL_DECL(name##_aux3); \
1497 static WM2200_MUX_CTL_DECL(name##_aux4); \
1498 static WM2200_MUX_CTL_DECL(name##_aux5); \
1499 static WM2200_MUX_CTL_DECL(name##_aux6);
1500
Mark Brownd5315a22012-01-25 19:29:41 +00001501static const struct snd_kcontrol_new wm2200_snd_controls[] = {
1502SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL,
1503 WM2200_IN1_OSR_SHIFT, 1, 0),
1504SOC_SINGLE("IN2 High Performance Switch", WM2200_IN2L_CONTROL,
1505 WM2200_IN2_OSR_SHIFT, 1, 0),
1506SOC_SINGLE("IN3 High Performance Switch", WM2200_IN3L_CONTROL,
1507 WM2200_IN3_OSR_SHIFT, 1, 0),
1508
1509SOC_DOUBLE_R_TLV("IN1 Volume", WM2200_IN1L_CONTROL, WM2200_IN1R_CONTROL,
1510 WM2200_IN1L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
1511SOC_DOUBLE_R_TLV("IN2 Volume", WM2200_IN2L_CONTROL, WM2200_IN2R_CONTROL,
1512 WM2200_IN2L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
1513SOC_DOUBLE_R_TLV("IN3 Volume", WM2200_IN3L_CONTROL, WM2200_IN3R_CONTROL,
1514 WM2200_IN3L_PGA_VOL_SHIFT, 0x5f, 0, in_tlv),
1515
1516SOC_DOUBLE_R("IN1 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
1517 WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_MUTE_SHIFT, 1, 1),
1518SOC_DOUBLE_R("IN2 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
1519 WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_MUTE_SHIFT, 1, 1),
1520SOC_DOUBLE_R("IN3 Digital Switch", WM2200_ADC_DIGITAL_VOLUME_1L,
1521 WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_MUTE_SHIFT, 1, 1),
1522
1523SOC_DOUBLE_R_TLV("IN1 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_1L,
1524 WM2200_ADC_DIGITAL_VOLUME_1R, WM2200_IN1L_DIG_VOL_SHIFT,
1525 0xbf, 0, digital_tlv),
1526SOC_DOUBLE_R_TLV("IN2 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_2L,
1527 WM2200_ADC_DIGITAL_VOLUME_2R, WM2200_IN2L_DIG_VOL_SHIFT,
1528 0xbf, 0, digital_tlv),
1529SOC_DOUBLE_R_TLV("IN3 Digital Volume", WM2200_ADC_DIGITAL_VOLUME_3L,
1530 WM2200_ADC_DIGITAL_VOLUME_3R, WM2200_IN3L_DIG_VOL_SHIFT,
1531 0xbf, 0, digital_tlv),
1532
1533SOC_SINGLE("OUT1 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
1534 WM2200_OUT1_OSR_SHIFT, 1, 0),
1535SOC_SINGLE("OUT2 High Performance Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
1536 WM2200_OUT2_OSR_SHIFT, 1, 0),
1537
1538SOC_DOUBLE_R("OUT1 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_1L,
1539 WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_MUTE_SHIFT, 1, 1),
1540SOC_DOUBLE_R_TLV("OUT1 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_1L,
1541 WM2200_DAC_DIGITAL_VOLUME_1R, WM2200_OUT1L_VOL_SHIFT, 0x9f, 0,
1542 digital_tlv),
1543SOC_DOUBLE_R_TLV("OUT1 Volume", WM2200_DAC_VOLUME_LIMIT_1L,
1544 WM2200_DAC_VOLUME_LIMIT_1R, WM2200_OUT1L_PGA_VOL_SHIFT,
1545 0x46, 0, out_tlv),
1546
1547SOC_DOUBLE_R("OUT2 Digital Switch", WM2200_DAC_DIGITAL_VOLUME_2L,
1548 WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_MUTE_SHIFT, 1, 1),
1549SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
1550 WM2200_DAC_DIGITAL_VOLUME_2R, WM2200_OUT2L_VOL_SHIFT, 0x9f, 0,
1551 digital_tlv),
1552SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
Mark Browna1b98e12012-10-02 19:10:43 +01001553 WM2200_SPK1R_MUTE_SHIFT, 1, 1),
Mark Brownd5315a22012-01-25 19:29:41 +00001554};
1555
1556WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
1557WM2200_MIXER_ENUMS(OUT1R, WM2200_OUT1RMIX_INPUT_1_SOURCE);
1558WM2200_MIXER_ENUMS(OUT2L, WM2200_OUT2LMIX_INPUT_1_SOURCE);
1559WM2200_MIXER_ENUMS(OUT2R, WM2200_OUT2RMIX_INPUT_1_SOURCE);
1560
1561WM2200_MIXER_ENUMS(AIF1TX1, WM2200_AIF1TX1MIX_INPUT_1_SOURCE);
1562WM2200_MIXER_ENUMS(AIF1TX2, WM2200_AIF1TX2MIX_INPUT_1_SOURCE);
1563WM2200_MIXER_ENUMS(AIF1TX3, WM2200_AIF1TX3MIX_INPUT_1_SOURCE);
1564WM2200_MIXER_ENUMS(AIF1TX4, WM2200_AIF1TX4MIX_INPUT_1_SOURCE);
1565WM2200_MIXER_ENUMS(AIF1TX5, WM2200_AIF1TX5MIX_INPUT_1_SOURCE);
1566WM2200_MIXER_ENUMS(AIF1TX6, WM2200_AIF1TX6MIX_INPUT_1_SOURCE);
1567
1568WM2200_MIXER_ENUMS(EQL, WM2200_EQLMIX_INPUT_1_SOURCE);
1569WM2200_MIXER_ENUMS(EQR, WM2200_EQRMIX_INPUT_1_SOURCE);
1570
1571WM2200_MIXER_ENUMS(DSP1L, WM2200_DSP1LMIX_INPUT_1_SOURCE);
1572WM2200_MIXER_ENUMS(DSP1R, WM2200_DSP1RMIX_INPUT_1_SOURCE);
1573WM2200_MIXER_ENUMS(DSP2L, WM2200_DSP2LMIX_INPUT_1_SOURCE);
1574WM2200_MIXER_ENUMS(DSP2R, WM2200_DSP2RMIX_INPUT_1_SOURCE);
1575
Mark Brown09d5d582012-10-03 15:57:03 +01001576WM2200_DSP_ENUMS(DSP1, WM2200_DSP1AUX1MIX_INPUT_1_SOURCE);
1577WM2200_DSP_ENUMS(DSP2, WM2200_DSP2AUX1MIX_INPUT_1_SOURCE);
1578
Mark Brownd5315a22012-01-25 19:29:41 +00001579WM2200_MIXER_ENUMS(LHPF1, WM2200_LHPF1MIX_INPUT_1_SOURCE);
1580WM2200_MIXER_ENUMS(LHPF2, WM2200_LHPF2MIX_INPUT_1_SOURCE);
1581
1582#define WM2200_MUX(name, ctrl) \
1583 SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl)
1584
1585#define WM2200_MIXER_WIDGETS(name, name_str) \
1586 WM2200_MUX(name_str " Input 1", &name##_in1_mux), \
1587 WM2200_MUX(name_str " Input 2", &name##_in2_mux), \
1588 WM2200_MUX(name_str " Input 3", &name##_in3_mux), \
1589 WM2200_MUX(name_str " Input 4", &name##_in4_mux), \
1590 SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0)
1591
Mark Brown09d5d582012-10-03 15:57:03 +01001592#define WM2200_DSP_WIDGETS(name, name_str) \
1593 WM2200_MIXER_WIDGETS(name##L, name_str "L"), \
1594 WM2200_MIXER_WIDGETS(name##R, name_str "R"), \
1595 WM2200_MUX(name_str " Aux 1", &name##_aux1_mux), \
1596 WM2200_MUX(name_str " Aux 2", &name##_aux2_mux), \
1597 WM2200_MUX(name_str " Aux 3", &name##_aux3_mux), \
1598 WM2200_MUX(name_str " Aux 4", &name##_aux4_mux), \
1599 WM2200_MUX(name_str " Aux 5", &name##_aux5_mux), \
1600 WM2200_MUX(name_str " Aux 6", &name##_aux6_mux)
1601
Mark Brownd5315a22012-01-25 19:29:41 +00001602#define WM2200_MIXER_INPUT_ROUTES(name) \
1603 { name, "Tone Generator", "Tone Generator" }, \
Mark Brown999e0682012-10-02 19:30:17 +01001604 { name, "AEC Loopback", "AEC Loopback" }, \
Mark Brownd5315a22012-01-25 19:29:41 +00001605 { name, "IN1L", "IN1L PGA" }, \
1606 { name, "IN1R", "IN1R PGA" }, \
1607 { name, "IN2L", "IN2L PGA" }, \
1608 { name, "IN2R", "IN2R PGA" }, \
1609 { name, "IN3L", "IN3L PGA" }, \
1610 { name, "IN3R", "IN3R PGA" }, \
1611 { name, "DSP1.1", "DSP1" }, \
1612 { name, "DSP1.2", "DSP1" }, \
1613 { name, "DSP1.3", "DSP1" }, \
1614 { name, "DSP1.4", "DSP1" }, \
1615 { name, "DSP1.5", "DSP1" }, \
1616 { name, "DSP1.6", "DSP1" }, \
1617 { name, "DSP2.1", "DSP2" }, \
1618 { name, "DSP2.2", "DSP2" }, \
1619 { name, "DSP2.3", "DSP2" }, \
1620 { name, "DSP2.4", "DSP2" }, \
1621 { name, "DSP2.5", "DSP2" }, \
1622 { name, "DSP2.6", "DSP2" }, \
1623 { name, "AIF1RX1", "AIF1RX1" }, \
1624 { name, "AIF1RX2", "AIF1RX2" }, \
1625 { name, "AIF1RX3", "AIF1RX3" }, \
1626 { name, "AIF1RX4", "AIF1RX4" }, \
1627 { name, "AIF1RX5", "AIF1RX5" }, \
1628 { name, "AIF1RX6", "AIF1RX6" }, \
1629 { name, "EQL", "EQL" }, \
1630 { name, "EQR", "EQR" }, \
1631 { name, "LHPF1", "LHPF1" }, \
1632 { name, "LHPF2", "LHPF2" }
1633
1634#define WM2200_MIXER_ROUTES(widget, name) \
1635 { widget, NULL, name " Mixer" }, \
1636 { name " Mixer", NULL, name " Input 1" }, \
1637 { name " Mixer", NULL, name " Input 2" }, \
1638 { name " Mixer", NULL, name " Input 3" }, \
1639 { name " Mixer", NULL, name " Input 4" }, \
1640 WM2200_MIXER_INPUT_ROUTES(name " Input 1"), \
1641 WM2200_MIXER_INPUT_ROUTES(name " Input 2"), \
1642 WM2200_MIXER_INPUT_ROUTES(name " Input 3"), \
1643 WM2200_MIXER_INPUT_ROUTES(name " Input 4")
1644
Mark Brown09d5d582012-10-03 15:57:03 +01001645#define WM2200_DSP_AUX_ROUTES(name) \
1646 { name, NULL, name " Aux 1" }, \
1647 { name, NULL, name " Aux 2" }, \
1648 { name, NULL, name " Aux 3" }, \
1649 { name, NULL, name " Aux 4" }, \
1650 { name, NULL, name " Aux 5" }, \
1651 { name, NULL, name " Aux 6" }, \
1652 WM2200_MIXER_INPUT_ROUTES(name " Aux 1"), \
1653 WM2200_MIXER_INPUT_ROUTES(name " Aux 2"), \
1654 WM2200_MIXER_INPUT_ROUTES(name " Aux 3"), \
1655 WM2200_MIXER_INPUT_ROUTES(name " Aux 4"), \
1656 WM2200_MIXER_INPUT_ROUTES(name " Aux 5"), \
1657 WM2200_MIXER_INPUT_ROUTES(name " Aux 6")
Mark Brown999e0682012-10-02 19:30:17 +01001658
1659static const char *wm2200_aec_loopback_texts[] = {
1660 "OUT1L", "OUT1R", "OUT2L", "OUT2R",
1661};
1662
1663static const struct soc_enum wm2200_aec_loopback =
1664 SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1,
1665 WM2200_AEC_LOOPBACK_SRC_SHIFT,
1666 ARRAY_SIZE(wm2200_aec_loopback_texts),
1667 wm2200_aec_loopback_texts);
1668
1669static const struct snd_kcontrol_new wm2200_aec_loopback_mux =
1670 SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback);
1671
Mark Brownd5315a22012-01-25 19:29:41 +00001672static const struct snd_soc_dapm_widget wm2200_dapm_widgets[] = {
1673SND_SOC_DAPM_SUPPLY("SYSCLK", WM2200_CLOCKING_3, WM2200_SYSCLK_ENA_SHIFT, 0,
1674 NULL, 0),
1675SND_SOC_DAPM_SUPPLY("CP1", WM2200_DM_CHARGE_PUMP_1, WM2200_CPDM_ENA_SHIFT, 0,
1676 NULL, 0),
1677SND_SOC_DAPM_SUPPLY("CP2", WM2200_MIC_CHARGE_PUMP_1, WM2200_CPMIC_ENA_SHIFT, 0,
1678 NULL, 0),
1679SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT,
1680 0, NULL, 0),
1681SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT,
1682 0, NULL, 0),
Mark Brown822b4b82012-09-07 10:54:32 +08001683SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
1684SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20, 0),
Mark Brownd5315a22012-01-25 19:29:41 +00001685
1686SND_SOC_DAPM_INPUT("IN1L"),
1687SND_SOC_DAPM_INPUT("IN1R"),
1688SND_SOC_DAPM_INPUT("IN2L"),
1689SND_SOC_DAPM_INPUT("IN2R"),
1690SND_SOC_DAPM_INPUT("IN3L"),
1691SND_SOC_DAPM_INPUT("IN3R"),
1692
1693SND_SOC_DAPM_SIGGEN("TONE"),
1694SND_SOC_DAPM_PGA("Tone Generator", WM2200_TONE_GENERATOR_1,
1695 WM2200_TONE_ENA_SHIFT, 0, NULL, 0),
1696
1697SND_SOC_DAPM_PGA("IN1L PGA", WM2200_INPUT_ENABLES, WM2200_IN1L_ENA_SHIFT, 0,
1698 NULL, 0),
1699SND_SOC_DAPM_PGA("IN1R PGA", WM2200_INPUT_ENABLES, WM2200_IN1R_ENA_SHIFT, 0,
1700 NULL, 0),
1701SND_SOC_DAPM_PGA("IN2L PGA", WM2200_INPUT_ENABLES, WM2200_IN2L_ENA_SHIFT, 0,
1702 NULL, 0),
1703SND_SOC_DAPM_PGA("IN2R PGA", WM2200_INPUT_ENABLES, WM2200_IN2R_ENA_SHIFT, 0,
1704 NULL, 0),
1705SND_SOC_DAPM_PGA("IN3L PGA", WM2200_INPUT_ENABLES, WM2200_IN3L_ENA_SHIFT, 0,
1706 NULL, 0),
1707SND_SOC_DAPM_PGA("IN3R PGA", WM2200_INPUT_ENABLES, WM2200_IN3R_ENA_SHIFT, 0,
1708 NULL, 0),
1709
1710SND_SOC_DAPM_AIF_IN("AIF1RX1", "Playback", 0,
1711 WM2200_AUDIO_IF_1_22, WM2200_AIF1RX1_ENA_SHIFT, 0),
1712SND_SOC_DAPM_AIF_IN("AIF1RX2", "Playback", 1,
1713 WM2200_AUDIO_IF_1_22, WM2200_AIF1RX2_ENA_SHIFT, 0),
1714SND_SOC_DAPM_AIF_IN("AIF1RX3", "Playback", 2,
1715 WM2200_AUDIO_IF_1_22, WM2200_AIF1RX3_ENA_SHIFT, 0),
1716SND_SOC_DAPM_AIF_IN("AIF1RX4", "Playback", 3,
1717 WM2200_AUDIO_IF_1_22, WM2200_AIF1RX4_ENA_SHIFT, 0),
1718SND_SOC_DAPM_AIF_IN("AIF1RX5", "Playback", 4,
1719 WM2200_AUDIO_IF_1_22, WM2200_AIF1RX5_ENA_SHIFT, 0),
1720SND_SOC_DAPM_AIF_IN("AIF1RX6", "Playback", 5,
1721 WM2200_AUDIO_IF_1_22, WM2200_AIF1RX6_ENA_SHIFT, 0),
1722
1723SND_SOC_DAPM_PGA("EQL", WM2200_EQL_1, WM2200_EQL_ENA_SHIFT, 0, NULL, 0),
1724SND_SOC_DAPM_PGA("EQR", WM2200_EQR_1, WM2200_EQR_ENA_SHIFT, 0, NULL, 0),
1725
1726SND_SOC_DAPM_PGA("LHPF1", WM2200_HPLPF1_1, WM2200_LHPF1_ENA_SHIFT, 0,
1727 NULL, 0),
1728SND_SOC_DAPM_PGA("LHPF2", WM2200_HPLPF2_1, WM2200_LHPF2_ENA_SHIFT, 0,
1729 NULL, 0),
1730
Mark Brown09d5d582012-10-03 15:57:03 +01001731SND_SOC_DAPM_PGA_E("DSP1", WM2200_DSP1_CONTROL_30, WM2200_DSP1_SYS_ENA_SHIFT,
Mark Browne10f8712012-10-04 16:31:52 +01001732 0, NULL, 0, wm2200_dsp_ev,
1733 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
Mark Brown09d5d582012-10-03 15:57:03 +01001734SND_SOC_DAPM_PGA_E("DSP2", WM2200_DSP2_CONTROL_30, WM2200_DSP2_SYS_ENA_SHIFT,
Mark Browne10f8712012-10-04 16:31:52 +01001735 0, NULL, 0, wm2200_dsp_ev,
1736 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
Mark Brownd5315a22012-01-25 19:29:41 +00001737
1738SND_SOC_DAPM_AIF_OUT("AIF1TX1", "Capture", 0,
1739 WM2200_AUDIO_IF_1_22, WM2200_AIF1TX1_ENA_SHIFT, 0),
1740SND_SOC_DAPM_AIF_OUT("AIF1TX2", "Capture", 1,
1741 WM2200_AUDIO_IF_1_22, WM2200_AIF1TX2_ENA_SHIFT, 0),
1742SND_SOC_DAPM_AIF_OUT("AIF1TX3", "Capture", 2,
1743 WM2200_AUDIO_IF_1_22, WM2200_AIF1TX3_ENA_SHIFT, 0),
1744SND_SOC_DAPM_AIF_OUT("AIF1TX4", "Capture", 3,
1745 WM2200_AUDIO_IF_1_22, WM2200_AIF1TX4_ENA_SHIFT, 0),
1746SND_SOC_DAPM_AIF_OUT("AIF1TX5", "Capture", 4,
1747 WM2200_AUDIO_IF_1_22, WM2200_AIF1TX5_ENA_SHIFT, 0),
1748SND_SOC_DAPM_AIF_OUT("AIF1TX6", "Capture", 5,
1749 WM2200_AUDIO_IF_1_22, WM2200_AIF1TX6_ENA_SHIFT, 0),
1750
Mark Brown999e0682012-10-02 19:30:17 +01001751SND_SOC_DAPM_MUX("AEC Loopback", WM2200_DAC_AEC_CONTROL_1,
1752 WM2200_AEC_LOOPBACK_ENA_SHIFT, 0, &wm2200_aec_loopback_mux),
1753
Mark Brownd5315a22012-01-25 19:29:41 +00001754SND_SOC_DAPM_PGA_S("OUT1L", 0, WM2200_OUTPUT_ENABLES,
1755 WM2200_OUT1L_ENA_SHIFT, 0, NULL, 0),
1756SND_SOC_DAPM_PGA_S("OUT1R", 0, WM2200_OUTPUT_ENABLES,
1757 WM2200_OUT1R_ENA_SHIFT, 0, NULL, 0),
1758
1759SND_SOC_DAPM_PGA_S("EPD_LP", 1, WM2200_EAR_PIECE_CTRL_1,
1760 WM2200_EPD_LP_ENA_SHIFT, 0, NULL, 0),
1761SND_SOC_DAPM_PGA_S("EPD_OUTP_LP", 1, WM2200_EAR_PIECE_CTRL_1,
1762 WM2200_EPD_OUTP_LP_ENA_SHIFT, 0, NULL, 0),
1763SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LP", 1, WM2200_EAR_PIECE_CTRL_1,
1764 WM2200_EPD_RMV_SHRT_LP_SHIFT, 0, NULL, 0),
1765
1766SND_SOC_DAPM_PGA_S("EPD_LN", 1, WM2200_EAR_PIECE_CTRL_1,
1767 WM2200_EPD_LN_ENA_SHIFT, 0, NULL, 0),
1768SND_SOC_DAPM_PGA_S("EPD_OUTP_LN", 1, WM2200_EAR_PIECE_CTRL_1,
1769 WM2200_EPD_OUTP_LN_ENA_SHIFT, 0, NULL, 0),
1770SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_LN", 1, WM2200_EAR_PIECE_CTRL_1,
1771 WM2200_EPD_RMV_SHRT_LN_SHIFT, 0, NULL, 0),
1772
1773SND_SOC_DAPM_PGA_S("EPD_RP", 1, WM2200_EAR_PIECE_CTRL_2,
1774 WM2200_EPD_RP_ENA_SHIFT, 0, NULL, 0),
1775SND_SOC_DAPM_PGA_S("EPD_OUTP_RP", 1, WM2200_EAR_PIECE_CTRL_2,
1776 WM2200_EPD_OUTP_RP_ENA_SHIFT, 0, NULL, 0),
1777SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RP", 1, WM2200_EAR_PIECE_CTRL_2,
1778 WM2200_EPD_RMV_SHRT_RP_SHIFT, 0, NULL, 0),
1779
1780SND_SOC_DAPM_PGA_S("EPD_RN", 1, WM2200_EAR_PIECE_CTRL_2,
1781 WM2200_EPD_RN_ENA_SHIFT, 0, NULL, 0),
1782SND_SOC_DAPM_PGA_S("EPD_OUTP_RN", 1, WM2200_EAR_PIECE_CTRL_2,
1783 WM2200_EPD_OUTP_RN_ENA_SHIFT, 0, NULL, 0),
1784SND_SOC_DAPM_PGA_S("EPD_RMV_SHRT_RN", 1, WM2200_EAR_PIECE_CTRL_2,
1785 WM2200_EPD_RMV_SHRT_RN_SHIFT, 0, NULL, 0),
1786
1787SND_SOC_DAPM_PGA("OUT2L", WM2200_OUTPUT_ENABLES, WM2200_OUT2L_ENA_SHIFT,
1788 0, NULL, 0),
1789SND_SOC_DAPM_PGA("OUT2R", WM2200_OUTPUT_ENABLES, WM2200_OUT2R_ENA_SHIFT,
1790 0, NULL, 0),
1791
1792SND_SOC_DAPM_OUTPUT("EPOUTLN"),
1793SND_SOC_DAPM_OUTPUT("EPOUTLP"),
1794SND_SOC_DAPM_OUTPUT("EPOUTRN"),
1795SND_SOC_DAPM_OUTPUT("EPOUTRP"),
1796SND_SOC_DAPM_OUTPUT("SPK"),
1797
1798WM2200_MIXER_WIDGETS(EQL, "EQL"),
1799WM2200_MIXER_WIDGETS(EQR, "EQR"),
1800
1801WM2200_MIXER_WIDGETS(LHPF1, "LHPF1"),
1802WM2200_MIXER_WIDGETS(LHPF2, "LHPF2"),
1803
Mark Brown09d5d582012-10-03 15:57:03 +01001804WM2200_DSP_WIDGETS(DSP1, "DSP1"),
1805WM2200_DSP_WIDGETS(DSP2, "DSP2"),
Mark Brownd5315a22012-01-25 19:29:41 +00001806
1807WM2200_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
1808WM2200_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
1809WM2200_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
1810WM2200_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
1811WM2200_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
1812WM2200_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
1813
1814WM2200_MIXER_WIDGETS(OUT1L, "OUT1L"),
1815WM2200_MIXER_WIDGETS(OUT1R, "OUT1R"),
1816WM2200_MIXER_WIDGETS(OUT2L, "OUT2L"),
1817WM2200_MIXER_WIDGETS(OUT2R, "OUT2R"),
1818};
1819
1820static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
1821 /* Everything needs SYSCLK but only hook up things on the edge
1822 * of the chip */
1823 { "IN1L", NULL, "SYSCLK" },
1824 { "IN1R", NULL, "SYSCLK" },
1825 { "IN2L", NULL, "SYSCLK" },
1826 { "IN2R", NULL, "SYSCLK" },
1827 { "IN3L", NULL, "SYSCLK" },
1828 { "IN3R", NULL, "SYSCLK" },
1829 { "OUT1L", NULL, "SYSCLK" },
1830 { "OUT1R", NULL, "SYSCLK" },
1831 { "OUT2L", NULL, "SYSCLK" },
1832 { "OUT2R", NULL, "SYSCLK" },
1833 { "AIF1RX1", NULL, "SYSCLK" },
1834 { "AIF1RX2", NULL, "SYSCLK" },
1835 { "AIF1RX3", NULL, "SYSCLK" },
1836 { "AIF1RX4", NULL, "SYSCLK" },
1837 { "AIF1RX5", NULL, "SYSCLK" },
1838 { "AIF1RX6", NULL, "SYSCLK" },
1839 { "AIF1TX1", NULL, "SYSCLK" },
1840 { "AIF1TX2", NULL, "SYSCLK" },
1841 { "AIF1TX3", NULL, "SYSCLK" },
1842 { "AIF1TX4", NULL, "SYSCLK" },
1843 { "AIF1TX5", NULL, "SYSCLK" },
1844 { "AIF1TX6", NULL, "SYSCLK" },
1845
1846 { "IN1L", NULL, "AVDD" },
1847 { "IN1R", NULL, "AVDD" },
1848 { "IN2L", NULL, "AVDD" },
1849 { "IN2R", NULL, "AVDD" },
1850 { "IN3L", NULL, "AVDD" },
1851 { "IN3R", NULL, "AVDD" },
1852 { "OUT1L", NULL, "AVDD" },
1853 { "OUT1R", NULL, "AVDD" },
1854
1855 { "IN1L PGA", NULL, "IN1L" },
1856 { "IN1R PGA", NULL, "IN1R" },
1857 { "IN2L PGA", NULL, "IN2L" },
1858 { "IN2R PGA", NULL, "IN2R" },
1859 { "IN3L PGA", NULL, "IN3L" },
1860 { "IN3R PGA", NULL, "IN3R" },
1861
1862 { "Tone Generator", NULL, "TONE" },
1863
1864 { "CP2", NULL, "CPVDD" },
1865 { "MICBIAS1", NULL, "CP2" },
1866 { "MICBIAS2", NULL, "CP2" },
1867
1868 { "CP1", NULL, "CPVDD" },
1869 { "EPD_LN", NULL, "CP1" },
1870 { "EPD_LP", NULL, "CP1" },
1871 { "EPD_RN", NULL, "CP1" },
1872 { "EPD_RP", NULL, "CP1" },
1873
1874 { "EPD_LP", NULL, "OUT1L" },
1875 { "EPD_OUTP_LP", NULL, "EPD_LP" },
1876 { "EPD_RMV_SHRT_LP", NULL, "EPD_OUTP_LP" },
1877 { "EPOUTLP", NULL, "EPD_RMV_SHRT_LP" },
1878
1879 { "EPD_LN", NULL, "OUT1L" },
1880 { "EPD_OUTP_LN", NULL, "EPD_LN" },
1881 { "EPD_RMV_SHRT_LN", NULL, "EPD_OUTP_LN" },
1882 { "EPOUTLN", NULL, "EPD_RMV_SHRT_LN" },
1883
1884 { "EPD_RP", NULL, "OUT1R" },
1885 { "EPD_OUTP_RP", NULL, "EPD_RP" },
1886 { "EPD_RMV_SHRT_RP", NULL, "EPD_OUTP_RP" },
1887 { "EPOUTRP", NULL, "EPD_RMV_SHRT_RP" },
1888
1889 { "EPD_RN", NULL, "OUT1R" },
1890 { "EPD_OUTP_RN", NULL, "EPD_RN" },
1891 { "EPD_RMV_SHRT_RN", NULL, "EPD_OUTP_RN" },
1892 { "EPOUTRN", NULL, "EPD_RMV_SHRT_RN" },
1893
1894 { "SPK", NULL, "OUT2L" },
1895 { "SPK", NULL, "OUT2R" },
1896
Mark Brown999e0682012-10-02 19:30:17 +01001897 { "AEC Loopback", "OUT1L", "OUT1L" },
1898 { "AEC Loopback", "OUT1R", "OUT1R" },
1899 { "AEC Loopback", "OUT2L", "OUT2L" },
1900 { "AEC Loopback", "OUT2R", "OUT2R" },
1901
Mark Brownd5315a22012-01-25 19:29:41 +00001902 WM2200_MIXER_ROUTES("DSP1", "DSP1L"),
1903 WM2200_MIXER_ROUTES("DSP1", "DSP1R"),
1904 WM2200_MIXER_ROUTES("DSP2", "DSP2L"),
1905 WM2200_MIXER_ROUTES("DSP2", "DSP2R"),
1906
Mark Brown09d5d582012-10-03 15:57:03 +01001907 WM2200_DSP_AUX_ROUTES("DSP1"),
1908 WM2200_DSP_AUX_ROUTES("DSP2"),
1909
Mark Brownd5315a22012-01-25 19:29:41 +00001910 WM2200_MIXER_ROUTES("OUT1L", "OUT1L"),
1911 WM2200_MIXER_ROUTES("OUT1R", "OUT1R"),
1912 WM2200_MIXER_ROUTES("OUT2L", "OUT2L"),
1913 WM2200_MIXER_ROUTES("OUT2R", "OUT2R"),
1914
1915 WM2200_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
1916 WM2200_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
1917 WM2200_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
1918 WM2200_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
1919 WM2200_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
1920 WM2200_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
1921
1922 WM2200_MIXER_ROUTES("EQL", "EQL"),
1923 WM2200_MIXER_ROUTES("EQR", "EQR"),
1924
1925 WM2200_MIXER_ROUTES("LHPF1", "LHPF1"),
1926 WM2200_MIXER_ROUTES("LHPF2", "LHPF2"),
1927};
1928
1929static int wm2200_probe(struct snd_soc_codec *codec)
1930{
1931 struct wm2200_priv *wm2200 = dev_get_drvdata(codec->dev);
1932 int ret;
1933
1934 wm2200->codec = codec;
1935 codec->control_data = wm2200->regmap;
1936 codec->dapm.bias_level = SND_SOC_BIAS_OFF;
1937
1938 ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
1939 if (ret != 0) {
1940 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
1941 return ret;
1942 }
1943
1944 return ret;
1945}
1946
1947static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1948{
1949 struct snd_soc_codec *codec = dai->codec;
1950 int lrclk, bclk, fmt_val;
1951
1952 lrclk = 0;
1953 bclk = 0;
1954
1955 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1956 case SND_SOC_DAIFMT_DSP_A:
1957 fmt_val = 0;
1958 break;
1959 case SND_SOC_DAIFMT_DSP_B:
1960 fmt_val = 1;
1961 break;
1962 case SND_SOC_DAIFMT_I2S:
1963 fmt_val = 2;
1964 break;
1965 case SND_SOC_DAIFMT_LEFT_J:
1966 fmt_val = 3;
1967 break;
1968 default:
1969 dev_err(codec->dev, "Unsupported DAI format %d\n",
1970 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1971 return -EINVAL;
1972 }
1973
1974 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1975 case SND_SOC_DAIFMT_CBS_CFS:
1976 break;
1977 case SND_SOC_DAIFMT_CBS_CFM:
1978 lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
1979 break;
1980 case SND_SOC_DAIFMT_CBM_CFS:
1981 bclk |= WM2200_AIF1_BCLK_MSTR;
1982 break;
1983 case SND_SOC_DAIFMT_CBM_CFM:
1984 lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
1985 bclk |= WM2200_AIF1_BCLK_MSTR;
1986 break;
1987 default:
1988 dev_err(codec->dev, "Unsupported master mode %d\n",
1989 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1990 return -EINVAL;
1991 }
1992
1993 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1994 case SND_SOC_DAIFMT_NB_NF:
1995 break;
1996 case SND_SOC_DAIFMT_IB_IF:
1997 bclk |= WM2200_AIF1_BCLK_INV;
1998 lrclk |= WM2200_AIF1TX_LRCLK_INV;
1999 break;
2000 case SND_SOC_DAIFMT_IB_NF:
2001 bclk |= WM2200_AIF1_BCLK_INV;
2002 break;
2003 case SND_SOC_DAIFMT_NB_IF:
2004 lrclk |= WM2200_AIF1TX_LRCLK_INV;
2005 break;
2006 default:
2007 return -EINVAL;
2008 }
2009
2010 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1, WM2200_AIF1_BCLK_MSTR |
2011 WM2200_AIF1_BCLK_INV, bclk);
2012 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
2013 WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
2014 lrclk);
2015 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_3,
2016 WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
2017 lrclk);
2018 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5,
2019 WM2200_AIF1_FMT_MASK << 1, fmt_val << 1);
2020
2021 return 0;
2022}
2023
2024static int wm2200_sr_code[] = {
2025 0,
2026 12000,
2027 24000,
2028 48000,
2029 96000,
2030 192000,
2031 384000,
2032 768000,
2033 0,
2034 11025,
2035 22050,
2036 44100,
2037 88200,
2038 176400,
2039 352800,
2040 705600,
2041 4000,
2042 8000,
2043 16000,
2044 32000,
2045 64000,
2046 128000,
2047 256000,
2048 512000,
2049};
2050
2051#define WM2200_NUM_BCLK_RATES 12
2052
2053static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = {
2054 6144000,
2055 3072000,
2056 2048000,
2057 1536000,
2058 768000,
2059 512000,
2060 384000,
2061 256000,
2062 192000,
2063 128000,
2064 96000,
2065 64000,
2066};
2067
2068static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
2069 5644800,
Mark Brownb0dfa452012-06-20 14:16:57 +01002070 3763200,
Mark Brownd5315a22012-01-25 19:29:41 +00002071 2882400,
2072 1881600,
2073 1411200,
2074 705600,
2075 470400,
2076 352800,
2077 176400,
2078 117600,
2079 88200,
2080 58800,
2081};
2082
2083static int wm2200_hw_params(struct snd_pcm_substream *substream,
2084 struct snd_pcm_hw_params *params,
2085 struct snd_soc_dai *dai)
2086{
2087 struct snd_soc_codec *codec = dai->codec;
2088 struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
2089 int i, bclk, lrclk, wl, fl, sr_code;
2090 int *bclk_rates;
2091
2092 /* Data sizes if not using TDM */
2093 wl = snd_pcm_format_width(params_format(params));
2094 if (wl < 0)
2095 return wl;
2096 fl = snd_soc_params_to_frame_size(params);
2097 if (fl < 0)
2098 return fl;
2099
2100 dev_dbg(codec->dev, "Word length %d bits, frame length %d bits\n",
2101 wl, fl);
2102
2103 /* Target BCLK rate */
2104 bclk = snd_soc_params_to_bclk(params);
2105 if (bclk < 0)
2106 return bclk;
2107
2108 if (!wm2200->sysclk) {
2109 dev_err(codec->dev, "SYSCLK has no rate set\n");
2110 return -EINVAL;
2111 }
2112
2113 for (i = 0; i < ARRAY_SIZE(wm2200_sr_code); i++)
2114 if (wm2200_sr_code[i] == params_rate(params))
2115 break;
2116 if (i == ARRAY_SIZE(wm2200_sr_code)) {
2117 dev_err(codec->dev, "Unsupported sample rate: %dHz\n",
2118 params_rate(params));
2119 return -EINVAL;
2120 }
2121 sr_code = i;
2122
2123 dev_dbg(codec->dev, "Target BCLK is %dHz, using %dHz SYSCLK\n",
2124 bclk, wm2200->sysclk);
2125
2126 if (wm2200->sysclk % 4000)
2127 bclk_rates = wm2200_bclk_rates_cd;
2128 else
2129 bclk_rates = wm2200_bclk_rates_dat;
2130
2131 for (i = 0; i < WM2200_NUM_BCLK_RATES; i++)
2132 if (bclk_rates[i] >= bclk && (bclk_rates[i] % bclk == 0))
2133 break;
2134 if (i == WM2200_NUM_BCLK_RATES) {
2135 dev_err(codec->dev,
2136 "No valid BCLK for %dHz found from %dHz SYSCLK\n",
2137 bclk, wm2200->sysclk);
2138 return -EINVAL;
2139 }
2140
2141 bclk = i;
2142 dev_dbg(codec->dev, "Setting %dHz BCLK\n", bclk_rates[bclk]);
2143 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_1,
2144 WM2200_AIF1_BCLK_DIV_MASK, bclk);
2145
2146 lrclk = bclk_rates[bclk] / params_rate(params);
2147 dev_dbg(codec->dev, "Setting %dHz LRCLK\n", bclk_rates[bclk] / lrclk);
2148 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
2149 dai->symmetric_rates)
2150 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_7,
2151 WM2200_AIF1RX_BCPF_MASK, lrclk);
2152 else
2153 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_6,
2154 WM2200_AIF1TX_BCPF_MASK, lrclk);
2155
2156 i = (wl << WM2200_AIF1TX_WL_SHIFT) | wl;
2157 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2158 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_9,
2159 WM2200_AIF1RX_WL_MASK |
2160 WM2200_AIF1RX_SLOT_LEN_MASK, i);
2161 else
2162 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_8,
2163 WM2200_AIF1TX_WL_MASK |
2164 WM2200_AIF1TX_SLOT_LEN_MASK, i);
2165
2166 snd_soc_update_bits(codec, WM2200_CLOCKING_4,
2167 WM2200_SAMPLE_RATE_1_MASK, sr_code);
2168
2169 return 0;
2170}
2171
2172static const struct snd_soc_dai_ops wm2200_dai_ops = {
2173 .set_fmt = wm2200_set_fmt,
2174 .hw_params = wm2200_hw_params,
2175};
2176
2177static int wm2200_set_sysclk(struct snd_soc_codec *codec, int clk_id,
2178 int source, unsigned int freq, int dir)
2179{
2180 struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
2181 int fval;
2182
2183 switch (clk_id) {
2184 case WM2200_CLK_SYSCLK:
2185 break;
2186
2187 default:
2188 dev_err(codec->dev, "Unknown clock %d\n", clk_id);
2189 return -EINVAL;
2190 }
2191
2192 switch (source) {
2193 case WM2200_CLKSRC_MCLK1:
2194 case WM2200_CLKSRC_MCLK2:
2195 case WM2200_CLKSRC_FLL:
2196 case WM2200_CLKSRC_BCLK1:
2197 break;
2198 default:
2199 dev_err(codec->dev, "Invalid source %d\n", source);
2200 return -EINVAL;
2201 }
2202
2203 switch (freq) {
2204 case 22579200:
2205 case 24576000:
2206 fval = 2;
2207 break;
2208 default:
2209 dev_err(codec->dev, "Invalid clock rate: %d\n", freq);
2210 return -EINVAL;
2211 }
2212
2213 /* TODO: Check if MCLKs are in use and enable/disable pulls to
2214 * match.
2215 */
2216
2217 snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_FREQ_MASK |
2218 WM2200_SYSCLK_SRC_MASK,
2219 fval << WM2200_SYSCLK_FREQ_SHIFT | source);
2220
2221 wm2200->sysclk = freq;
2222
2223 return 0;
2224}
2225
2226struct _fll_div {
2227 u16 fll_fratio;
2228 u16 fll_outdiv;
2229 u16 fll_refclk_div;
2230 u16 n;
2231 u16 theta;
2232 u16 lambda;
2233};
2234
2235static struct {
2236 unsigned int min;
2237 unsigned int max;
2238 u16 fll_fratio;
2239 int ratio;
2240} fll_fratios[] = {
2241 { 0, 64000, 4, 16 },
2242 { 64000, 128000, 3, 8 },
2243 { 128000, 256000, 2, 4 },
2244 { 256000, 1000000, 1, 2 },
2245 { 1000000, 13500000, 0, 1 },
2246};
2247
2248static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
2249 unsigned int Fout)
2250{
2251 unsigned int target;
2252 unsigned int div;
2253 unsigned int fratio, gcd_fll;
2254 int i;
2255
2256 /* Fref must be <=13.5MHz */
2257 div = 1;
2258 fll_div->fll_refclk_div = 0;
2259 while ((Fref / div) > 13500000) {
2260 div *= 2;
2261 fll_div->fll_refclk_div++;
2262
2263 if (div > 8) {
2264 pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
2265 Fref);
2266 return -EINVAL;
2267 }
2268 }
2269
2270 pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
2271
2272 /* Apply the division for our remaining calculations */
2273 Fref /= div;
2274
2275 /* Fvco should be 90-100MHz; don't check the upper bound */
2276 div = 2;
2277 while (Fout * div < 90000000) {
2278 div++;
2279 if (div > 64) {
2280 pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
2281 Fout);
2282 return -EINVAL;
2283 }
2284 }
2285 target = Fout * div;
2286 fll_div->fll_outdiv = div - 1;
2287
2288 pr_debug("FLL Fvco=%dHz\n", target);
2289
2290 /* Find an appropraite FLL_FRATIO and factor it out of the target */
2291 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
2292 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
2293 fll_div->fll_fratio = fll_fratios[i].fll_fratio;
2294 fratio = fll_fratios[i].ratio;
2295 break;
2296 }
2297 }
2298 if (i == ARRAY_SIZE(fll_fratios)) {
2299 pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
2300 return -EINVAL;
2301 }
2302
2303 fll_div->n = target / (fratio * Fref);
2304
2305 if (target % Fref == 0) {
2306 fll_div->theta = 0;
2307 fll_div->lambda = 0;
2308 } else {
2309 gcd_fll = gcd(target, fratio * Fref);
2310
2311 fll_div->theta = (target - (fll_div->n * fratio * Fref))
2312 / gcd_fll;
2313 fll_div->lambda = (fratio * Fref) / gcd_fll;
2314 }
2315
2316 pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
2317 fll_div->n, fll_div->theta, fll_div->lambda);
2318 pr_debug("FLL_FRATIO=%x(%d) FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
2319 fll_div->fll_fratio, fratio, fll_div->fll_outdiv,
2320 fll_div->fll_refclk_div);
2321
2322 return 0;
2323}
2324
2325static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
2326 unsigned int Fref, unsigned int Fout)
2327{
2328 struct i2c_client *i2c = to_i2c_client(codec->dev);
2329 struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
2330 struct _fll_div factors;
2331 int ret, i, timeout;
2332
2333 if (!Fout) {
2334 dev_dbg(codec->dev, "FLL disabled");
2335
2336 if (wm2200->fll_fout)
2337 pm_runtime_put(codec->dev);
2338
2339 wm2200->fll_fout = 0;
2340 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
2341 WM2200_FLL_ENA, 0);
2342 return 0;
2343 }
2344
2345 switch (source) {
2346 case WM2200_FLL_SRC_MCLK1:
2347 case WM2200_FLL_SRC_MCLK2:
2348 case WM2200_FLL_SRC_BCLK:
2349 break;
2350 default:
2351 dev_err(codec->dev, "Invalid FLL source %d\n", source);
2352 return -EINVAL;
2353 }
2354
2355 ret = fll_factors(&factors, Fref, Fout);
2356 if (ret < 0)
2357 return ret;
2358
2359 /* Disable the FLL while we reconfigure */
2360 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1, WM2200_FLL_ENA, 0);
2361
2362 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_2,
2363 WM2200_FLL_OUTDIV_MASK | WM2200_FLL_FRATIO_MASK,
2364 (factors.fll_outdiv << WM2200_FLL_OUTDIV_SHIFT) |
2365 factors.fll_fratio);
2366 if (factors.theta) {
2367 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
2368 WM2200_FLL_FRACN_ENA,
2369 WM2200_FLL_FRACN_ENA);
2370 snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
2371 WM2200_FLL_EFS_ENA,
2372 WM2200_FLL_EFS_ENA);
2373 } else {
2374 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_3,
2375 WM2200_FLL_FRACN_ENA, 0);
2376 snd_soc_update_bits(codec, WM2200_FLL_EFS_2,
2377 WM2200_FLL_EFS_ENA, 0);
2378 }
2379
2380 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_4, WM2200_FLL_THETA_MASK,
2381 factors.theta);
2382 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_6, WM2200_FLL_N_MASK,
2383 factors.n);
2384 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_7,
2385 WM2200_FLL_CLK_REF_DIV_MASK |
2386 WM2200_FLL_CLK_REF_SRC_MASK,
2387 (factors.fll_refclk_div
2388 << WM2200_FLL_CLK_REF_DIV_SHIFT) | source);
2389 snd_soc_update_bits(codec, WM2200_FLL_EFS_1,
2390 WM2200_FLL_LAMBDA_MASK, factors.lambda);
2391
2392 /* Clear any pending completions */
2393 try_wait_for_completion(&wm2200->fll_lock);
2394
2395 pm_runtime_get_sync(codec->dev);
2396
2397 snd_soc_update_bits(codec, WM2200_FLL_CONTROL_1,
2398 WM2200_FLL_ENA, WM2200_FLL_ENA);
2399
2400 if (i2c->irq)
2401 timeout = 2;
2402 else
2403 timeout = 50;
2404
2405 snd_soc_update_bits(codec, WM2200_CLOCKING_3, WM2200_SYSCLK_ENA,
2406 WM2200_SYSCLK_ENA);
2407
2408 /* Poll for the lock; will use the interrupt to exit quickly */
2409 for (i = 0; i < timeout; i++) {
2410 if (i2c->irq) {
2411 ret = wait_for_completion_timeout(&wm2200->fll_lock,
2412 msecs_to_jiffies(25));
2413 if (ret > 0)
2414 break;
2415 } else {
2416 msleep(1);
2417 }
2418
2419 ret = snd_soc_read(codec,
2420 WM2200_INTERRUPT_RAW_STATUS_2);
2421 if (ret < 0) {
2422 dev_err(codec->dev,
2423 "Failed to read FLL status: %d\n",
2424 ret);
2425 continue;
2426 }
2427 if (ret & WM2200_FLL_LOCK_STS)
2428 break;
2429 }
2430 if (i == timeout) {
2431 dev_err(codec->dev, "FLL lock timed out\n");
2432 pm_runtime_put(codec->dev);
2433 return -ETIMEDOUT;
2434 }
2435
2436 wm2200->fll_src = source;
2437 wm2200->fll_fref = Fref;
2438 wm2200->fll_fout = Fout;
2439
2440 dev_dbg(codec->dev, "FLL running %dHz->%dHz\n", Fref, Fout);
2441
2442 return 0;
2443}
2444
2445static int wm2200_dai_probe(struct snd_soc_dai *dai)
2446{
2447 struct snd_soc_codec *codec = dai->codec;
2448 unsigned int val = 0;
2449 int ret;
2450
2451 ret = snd_soc_read(codec, WM2200_GPIO_CTRL_1);
2452 if (ret >= 0) {
2453 if ((ret & WM2200_GP1_FN_MASK) != 0) {
2454 dai->symmetric_rates = true;
2455 val = WM2200_AIF1TX_LRCLK_SRC;
2456 }
2457 } else {
2458 dev_err(codec->dev, "Failed to read GPIO 1 config: %d\n", ret);
2459 }
2460
2461 snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_2,
2462 WM2200_AIF1TX_LRCLK_SRC, val);
2463
2464 return 0;
2465}
2466
2467#define WM2200_RATES SNDRV_PCM_RATE_8000_48000
2468
2469#define WM2200_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
2470 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
2471
2472static struct snd_soc_dai_driver wm2200_dai = {
2473 .name = "wm2200",
2474 .probe = wm2200_dai_probe,
2475 .playback = {
2476 .stream_name = "Playback",
2477 .channels_min = 2,
2478 .channels_max = 2,
2479 .rates = WM2200_RATES,
2480 .formats = WM2200_FORMATS,
2481 },
2482 .capture = {
2483 .stream_name = "Capture",
2484 .channels_min = 2,
2485 .channels_max = 2,
2486 .rates = WM2200_RATES,
2487 .formats = WM2200_FORMATS,
2488 },
2489 .ops = &wm2200_dai_ops,
2490};
2491
2492static struct snd_soc_codec_driver soc_codec_wm2200 = {
2493 .probe = wm2200_probe,
2494
2495 .idle_bias_off = true,
Mark Brown17c0cee2012-02-08 18:35:43 +00002496 .ignore_pmdown_time = true,
Mark Brownd5315a22012-01-25 19:29:41 +00002497 .set_sysclk = wm2200_set_sysclk,
2498 .set_pll = wm2200_set_fll,
2499
2500 .controls = wm2200_snd_controls,
2501 .num_controls = ARRAY_SIZE(wm2200_snd_controls),
2502 .dapm_widgets = wm2200_dapm_widgets,
2503 .num_dapm_widgets = ARRAY_SIZE(wm2200_dapm_widgets),
2504 .dapm_routes = wm2200_dapm_routes,
2505 .num_dapm_routes = ARRAY_SIZE(wm2200_dapm_routes),
2506};
2507
2508static irqreturn_t wm2200_irq(int irq, void *data)
2509{
2510 struct wm2200_priv *wm2200 = data;
2511 unsigned int val, mask;
2512 int ret;
2513
2514 ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, &val);
2515 if (ret != 0) {
2516 dev_err(wm2200->dev, "Failed to read IRQ status: %d\n", ret);
2517 return IRQ_NONE;
2518 }
2519
2520 ret = regmap_read(wm2200->regmap, WM2200_INTERRUPT_STATUS_2_MASK,
2521 &mask);
2522 if (ret != 0) {
2523 dev_warn(wm2200->dev, "Failed to read IRQ mask: %d\n", ret);
2524 mask = 0;
2525 }
2526
2527 val &= ~mask;
2528
2529 if (val & WM2200_FLL_LOCK_EINT) {
2530 dev_dbg(wm2200->dev, "FLL locked\n");
2531 complete(&wm2200->fll_lock);
2532 }
2533
2534 if (val) {
2535 regmap_write(wm2200->regmap, WM2200_INTERRUPT_STATUS_2, val);
2536
2537 return IRQ_HANDLED;
2538 } else {
2539 return IRQ_NONE;
2540 }
2541}
2542
2543static const struct regmap_config wm2200_regmap = {
2544 .reg_bits = 16,
2545 .val_bits = 16,
2546
Mark Browneae23282012-10-02 20:14:49 +01002547 .max_register = WM2200_MAX_REGISTER + (ARRAY_SIZE(wm2200_ranges) *
2548 WM2200_DSP_SPACING),
Mark Brownd5315a22012-01-25 19:29:41 +00002549 .reg_defaults = wm2200_reg_defaults,
2550 .num_reg_defaults = ARRAY_SIZE(wm2200_reg_defaults),
2551 .volatile_reg = wm2200_volatile_register,
2552 .readable_reg = wm2200_readable_register,
2553 .cache_type = REGCACHE_RBTREE,
Mark Browneae23282012-10-02 20:14:49 +01002554 .ranges = wm2200_ranges,
2555 .num_ranges = ARRAY_SIZE(wm2200_ranges),
Mark Brownd5315a22012-01-25 19:29:41 +00002556};
2557
2558static const unsigned int wm2200_dig_vu[] = {
2559 WM2200_DAC_DIGITAL_VOLUME_1L,
2560 WM2200_DAC_DIGITAL_VOLUME_1R,
2561 WM2200_DAC_DIGITAL_VOLUME_2L,
2562 WM2200_DAC_DIGITAL_VOLUME_2R,
2563 WM2200_ADC_DIGITAL_VOLUME_1L,
2564 WM2200_ADC_DIGITAL_VOLUME_1R,
2565 WM2200_ADC_DIGITAL_VOLUME_2L,
2566 WM2200_ADC_DIGITAL_VOLUME_2R,
2567 WM2200_ADC_DIGITAL_VOLUME_3L,
2568 WM2200_ADC_DIGITAL_VOLUME_3R,
2569};
2570
2571static const unsigned int wm2200_mic_ctrl_reg[] = {
2572 WM2200_IN1L_CONTROL,
2573 WM2200_IN2L_CONTROL,
2574 WM2200_IN3L_CONTROL,
2575};
2576
2577static __devinit int wm2200_i2c_probe(struct i2c_client *i2c,
2578 const struct i2c_device_id *id)
2579{
2580 struct wm2200_pdata *pdata = dev_get_platdata(&i2c->dev);
2581 struct wm2200_priv *wm2200;
2582 unsigned int reg;
2583 int ret, i;
2584
2585 wm2200 = devm_kzalloc(&i2c->dev, sizeof(struct wm2200_priv),
2586 GFP_KERNEL);
2587 if (wm2200 == NULL)
2588 return -ENOMEM;
2589
2590 wm2200->dev = &i2c->dev;
2591 init_completion(&wm2200->fll_lock);
2592
Mark Brown98ad0892012-10-01 19:27:45 +01002593 wm2200->regmap = devm_regmap_init_i2c(i2c, &wm2200_regmap);
Mark Brownd5315a22012-01-25 19:29:41 +00002594 if (IS_ERR(wm2200->regmap)) {
2595 ret = PTR_ERR(wm2200->regmap);
2596 dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
2597 ret);
2598 goto err;
2599 }
2600
2601 if (pdata)
2602 wm2200->pdata = *pdata;
2603
2604 i2c_set_clientdata(i2c, wm2200);
2605
2606 for (i = 0; i < ARRAY_SIZE(wm2200->core_supplies); i++)
2607 wm2200->core_supplies[i].supply = wm2200_core_supply_names[i];
2608
Mark Brown98ad0892012-10-01 19:27:45 +01002609 ret = devm_regulator_bulk_get(&i2c->dev,
2610 ARRAY_SIZE(wm2200->core_supplies),
2611 wm2200->core_supplies);
Mark Brownd5315a22012-01-25 19:29:41 +00002612 if (ret != 0) {
2613 dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
2614 ret);
2615 goto err_regmap;
2616 }
2617
2618 ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
2619 wm2200->core_supplies);
2620 if (ret != 0) {
2621 dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
2622 ret);
2623 goto err_core;
2624 }
2625
2626 if (wm2200->pdata.ldo_ena) {
Mark Brown98ad0892012-10-01 19:27:45 +01002627 ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.ldo_ena,
2628 GPIOF_OUT_INIT_HIGH,
2629 "WM2200 LDOENA");
Mark Brownd5315a22012-01-25 19:29:41 +00002630 if (ret < 0) {
2631 dev_err(&i2c->dev, "Failed to request LDOENA %d: %d\n",
2632 wm2200->pdata.ldo_ena, ret);
2633 goto err_enable;
2634 }
2635 msleep(2);
2636 }
2637
2638 if (wm2200->pdata.reset) {
Mark Brown98ad0892012-10-01 19:27:45 +01002639 ret = devm_gpio_request_one(&i2c->dev, wm2200->pdata.reset,
2640 GPIOF_OUT_INIT_HIGH,
2641 "WM2200 /RESET");
Mark Brownd5315a22012-01-25 19:29:41 +00002642 if (ret < 0) {
2643 dev_err(&i2c->dev, "Failed to request /RESET %d: %d\n",
2644 wm2200->pdata.reset, ret);
2645 goto err_ldo;
2646 }
2647 }
2648
2649 ret = regmap_read(wm2200->regmap, WM2200_SOFTWARE_RESET, &reg);
2650 if (ret < 0) {
2651 dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret);
2652 goto err_reset;
2653 }
2654 switch (reg) {
2655 case 0x2200:
2656 break;
2657
2658 default:
2659 dev_err(&i2c->dev, "Device is not a WM2200, ID is %x\n", reg);
2660 ret = -EINVAL;
2661 goto err_reset;
2662 }
2663
2664 ret = regmap_read(wm2200->regmap, WM2200_DEVICE_REVISION, &reg);
2665 if (ret < 0) {
2666 dev_err(&i2c->dev, "Failed to read revision register\n");
2667 goto err_reset;
2668 }
2669
Axel Lin916be222012-02-16 10:05:59 +08002670 wm2200->rev = reg & WM2200_DEVICE_REVISION_MASK;
Mark Brownd5315a22012-01-25 19:29:41 +00002671
2672 dev_info(&i2c->dev, "revision %c\n", wm2200->rev + 'A');
2673
2674 switch (wm2200->rev) {
2675 case 0:
Mark Brown5ae9eb42012-10-02 12:02:48 +01002676 case 1:
Mark Brownd5315a22012-01-25 19:29:41 +00002677 ret = regmap_register_patch(wm2200->regmap, wm2200_reva_patch,
2678 ARRAY_SIZE(wm2200_reva_patch));
2679 if (ret != 0) {
2680 dev_err(&i2c->dev, "Failed to register patch: %d\n",
2681 ret);
2682 }
2683 break;
2684 default:
2685 break;
2686 }
2687
2688 ret = wm2200_reset(wm2200);
2689 if (ret < 0) {
2690 dev_err(&i2c->dev, "Failed to issue reset\n");
2691 goto err_reset;
2692 }
2693
2694 for (i = 0; i < ARRAY_SIZE(wm2200->pdata.gpio_defaults); i++) {
2695 if (!wm2200->pdata.gpio_defaults[i])
2696 continue;
2697
2698 regmap_write(wm2200->regmap, WM2200_GPIO_CTRL_1 + i,
2699 wm2200->pdata.gpio_defaults[i]);
2700 }
2701
2702 for (i = 0; i < ARRAY_SIZE(wm2200_dig_vu); i++)
2703 regmap_update_bits(wm2200->regmap, wm2200_dig_vu[i],
2704 WM2200_OUT_VU, WM2200_OUT_VU);
2705
2706 /* Assign slots 1-6 to channels 1-6 for both TX and RX */
2707 for (i = 0; i < 6; i++) {
2708 regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_10 + i, i);
2709 regmap_write(wm2200->regmap, WM2200_AUDIO_IF_1_16 + i, i);
2710 }
2711
2712 for (i = 0; i < ARRAY_SIZE(wm2200->pdata.in_mode); i++) {
2713 regmap_update_bits(wm2200->regmap, wm2200_mic_ctrl_reg[i],
2714 WM2200_IN1_MODE_MASK |
2715 WM2200_IN1_DMIC_SUP_MASK,
2716 (wm2200->pdata.in_mode[i] <<
2717 WM2200_IN1_MODE_SHIFT) |
2718 (wm2200->pdata.dmic_sup[i] <<
2719 WM2200_IN1_DMIC_SUP_SHIFT));
2720 }
2721
2722 if (i2c->irq) {
2723 ret = request_threaded_irq(i2c->irq, NULL, wm2200_irq,
2724 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
2725 "wm2200", wm2200);
2726 if (ret == 0)
2727 regmap_update_bits(wm2200->regmap,
2728 WM2200_INTERRUPT_STATUS_2_MASK,
2729 WM2200_FLL_LOCK_EINT, 0);
2730 else
2731 dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
2732 i2c->irq, ret);
2733 }
2734
2735 pm_runtime_set_active(&i2c->dev);
2736 pm_runtime_enable(&i2c->dev);
2737 pm_request_idle(&i2c->dev);
2738
2739 ret = snd_soc_register_codec(&i2c->dev, &soc_codec_wm2200,
2740 &wm2200_dai, 1);
2741 if (ret != 0) {
2742 dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
2743 goto err_pm_runtime;
2744 }
2745
2746 return 0;
2747
2748err_pm_runtime:
2749 pm_runtime_disable(&i2c->dev);
2750err_reset:
Mark Brown98ad0892012-10-01 19:27:45 +01002751 if (wm2200->pdata.reset)
Mark Brownd5315a22012-01-25 19:29:41 +00002752 gpio_set_value_cansleep(wm2200->pdata.reset, 0);
Mark Brownd5315a22012-01-25 19:29:41 +00002753err_ldo:
Mark Brown98ad0892012-10-01 19:27:45 +01002754 if (wm2200->pdata.ldo_ena)
Mark Brownd5315a22012-01-25 19:29:41 +00002755 gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
Mark Brownd5315a22012-01-25 19:29:41 +00002756err_enable:
2757 regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
2758 wm2200->core_supplies);
2759err_core:
Mark Brownd5315a22012-01-25 19:29:41 +00002760err_regmap:
Mark Brownd5315a22012-01-25 19:29:41 +00002761err:
2762 return ret;
2763}
2764
2765static __devexit int wm2200_i2c_remove(struct i2c_client *i2c)
2766{
2767 struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c);
2768
2769 snd_soc_unregister_codec(&i2c->dev);
2770 if (i2c->irq)
2771 free_irq(i2c->irq, wm2200);
Mark Brown98ad0892012-10-01 19:27:45 +01002772 if (wm2200->pdata.reset)
Mark Brownd5315a22012-01-25 19:29:41 +00002773 gpio_set_value_cansleep(wm2200->pdata.reset, 0);
Mark Brown98ad0892012-10-01 19:27:45 +01002774 if (wm2200->pdata.ldo_ena)
Mark Brownd5315a22012-01-25 19:29:41 +00002775 gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
Mark Brownd5315a22012-01-25 19:29:41 +00002776
2777 return 0;
2778}
2779
2780#ifdef CONFIG_PM_RUNTIME
2781static int wm2200_runtime_suspend(struct device *dev)
2782{
2783 struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
2784
2785 regcache_cache_only(wm2200->regmap, true);
2786 regcache_mark_dirty(wm2200->regmap);
2787 if (wm2200->pdata.ldo_ena)
2788 gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0);
2789 regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
2790 wm2200->core_supplies);
2791
2792 return 0;
2793}
2794
2795static int wm2200_runtime_resume(struct device *dev)
2796{
2797 struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
2798 int ret;
2799
2800 ret = regulator_bulk_enable(ARRAY_SIZE(wm2200->core_supplies),
2801 wm2200->core_supplies);
2802 if (ret != 0) {
2803 dev_err(dev, "Failed to enable supplies: %d\n",
2804 ret);
2805 return ret;
2806 }
2807
2808 if (wm2200->pdata.ldo_ena) {
2809 gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 1);
2810 msleep(2);
2811 }
2812
2813 regcache_cache_only(wm2200->regmap, false);
2814 regcache_sync(wm2200->regmap);
2815
2816 return 0;
2817}
2818#endif
2819
2820static struct dev_pm_ops wm2200_pm = {
2821 SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
2822 NULL)
2823};
2824
2825static const struct i2c_device_id wm2200_i2c_id[] = {
2826 { "wm2200", 0 },
2827 { }
2828};
2829MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
2830
2831static struct i2c_driver wm2200_i2c_driver = {
2832 .driver = {
2833 .name = "wm2200",
2834 .owner = THIS_MODULE,
2835 .pm = &wm2200_pm,
2836 },
2837 .probe = wm2200_i2c_probe,
2838 .remove = __devexit_p(wm2200_i2c_remove),
2839 .id_table = wm2200_i2c_id,
2840};
2841
Sachin Kamata9418dd2012-08-06 17:25:53 +05302842module_i2c_driver(wm2200_i2c_driver);
Mark Brownd5315a22012-01-25 19:29:41 +00002843
2844MODULE_DESCRIPTION("ASoC WM2200 driver");
2845MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2846MODULE_LICENSE("GPL");