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