aboutsummaryrefslogtreecommitdiffstats
path: root/include/uapi/linux/elf.h
blob: ef6103bf1f9bb3ade18268a639cc784dcc695b95 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
#ifndef _UAPI_LINUX_ELF_H
#define _UAPI_LINUX_ELF_H

#include <linux/types.h>
#include <linux/elf-em.h>

/* 32-bit ELF base types. */
typedef __u32	Elf32_Addr;
typedef __u16	Elf32_Half;
typedef __u32	Elf32_Off;
typedef __s32	Elf32_Sword;
typedef __u32	Elf32_Word;

/* 64-bit ELF base types. */
typedef __u64	Elf64_Addr;
typedef __u16	Elf64_Half;
typedef __s16	Elf64_SHalf;
typedef __u64	Elf64_Off;
typedef __s32	Elf64_Sword;
typedef __u32	Elf64_Word;
typedef __u64	Elf64_Xword;
typedef __s64	Elf64_Sxword;

/* These constants are for the segment types stored in the image headers */
#define PT_NULL    0
#define PT_LOAD    1
#define PT_DYNAMIC 2
#define PT_INTERP  3
#define PT_NOTE    4
#define PT_SHLIB   5
#define PT_PHDR    6
#define PT_TLS     7               /* Thread local storage segment */
#define PT_LOOS    0x60000000      /* OS-specific */
#define PT_HIOS    0x6fffffff      /* OS-specific */
#define PT_LOPROC  0x70000000
#define PT_HIPROC  0x7fffffff
#define PT_GNU_EH_FRAME		0x6474e550

#define PT_GNU_STACK	(PT_LOOS + 0x474e551)

/*
 * Extended Numbering
 *
 * If the real number of program header table entries is larger than
 * or equal to PN_XNUM(0xffff), it is set to sh_info field of the
 * section header at index 0, and PN_XNUM is set to e_phnum
 * field. Otherwise, the section header at index 0 is zero
 * initialized, if it exists.
 *
 * Specifications are available in:
 *
 * - Oracle: Linker and Libraries.
 *   Part No: 817–1984–19, August 2011.
 *   http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf
 *
 * - System V ABI AMD64 Architecture Processor Supplement
 *   Draft Version 0.99.4,
 *   January 13, 2010.
 *   http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf
 */
#define PN_XNUM 0xffff

/* These constants define the different elf file types */
#define ET_NONE   0
#define ET_REL    1
#define ET_EXEC   2
#define ET_DYN    3
#define ET_CORE   4
#define ET_LOPROC 0xff00
#define ET_HIPROC 0xffff

/* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL		0
#define DT_NEEDED	1
#define DT_PLTRELSZ	2
#define DT_PLTGOT	3
#define DT_HASH		4
#define DT_STRTAB	5
#define DT_SYMTAB	6
#define DT_RELA		7
#define DT_RELASZ	8
#define DT_RELAENT	9
#define DT_STRSZ	10
#define DT_SYMENT	11
#define DT_INIT		12
#define DT_FINI		13
#define DT_SONAME	14
#define DT_RPATH 	15
#define DT_SYMBOLIC	16
#define DT_REL	        17
#define DT_RELSZ	18
#define DT_RELENT	19
#define DT_PLTREL	20
#define DT_DEBUG	21
#define DT_TEXTREL	22
#define DT_JMPREL	23
#define DT_ENCODING	32
#define OLD_DT_LOOS	0x60000000
#define DT_LOOS		0x6000000d
#define DT_HIOS		0x6ffff000
#define DT_VALRNGLO	0x6ffffd00
#define DT_VALRNGHI	0x6ffffdff
#define DT_ADDRRNGLO	0x6ffffe00
#define DT_ADDRRNGHI	0x6ffffeff
#define DT_VERSYM	0x6ffffff0
#define DT_RELACOUNT	0x6ffffff9
#define DT_RELCOUNT	0x6ffffffa
#define DT_FLAGS_1	0x6ffffffb
#define DT_VERDEF	0x6ffffffc
#define	DT_VERDEFNUM	0x6ffffffd
#define DT_VERNEED	0x6ffffffe
#define	DT_VERNEEDNUM	0x6fffffff
#define OLD_DT_HIOS     0x6fffffff
#define DT_LOPROC	0x70000000
#define DT_HIPROC	0x7fffffff

/* This info is needed when parsing the symbol table */
#define STB_LOCAL  0
#define STB_GLOBAL 1
#define STB_WEAK   2

#define STT_NOTYPE  0
#define STT_OBJECT  1
#define STT_FUNC    2
#define STT_SECTION 3
#define STT_FILE    4
#define STT_COMMON  5
#define STT_TLS     6

#define ELF_ST_BIND(x)		((x) >> 4)
#define ELF_ST_TYPE(x)		(((unsigned int) x) & 0xf)
#define ELF32_ST_BIND(x)	ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x)	ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x)	ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x)	ELF_ST_TYPE(x)

typedef struct dynamic{
  Elf32_Sword d_tag;
  union{
    Elf32_Sword	d_val;
    Elf32_Addr	d_ptr;
  } d_un;
} Elf32_Dyn;

typedef struct {
  Elf64_Sxword d_tag;		/* entry tag value */
  union {
    Elf64_Xword d_val;
    Elf64_Addr d_ptr;
  } d_un;
} Elf64_Dyn;

/* The following are used with relocations */
#define ELF32_R_SYM(x) ((x) >> 8)
#define ELF32_R_TYPE(x) ((x) & 0xff)

#define ELF64_R_SYM(i)			((i) >> 32)
#define ELF64_R_TYPE(i)			((i) & 0xffffffff)

typedef struct elf32_rel {
  Elf32_Addr	r_offset;
  Elf32_Word	r_info;
} Elf32_Rel;

typedef struct elf64_rel {
  Elf64_Addr r_offset;	/* Location at which to apply the action */
  Elf64_Xword r_info;	/* index and type of relocation */
} Elf64_Rel;

typedef struct elf32_rela{
  Elf32_Addr	r_offset;
  Elf32_Word	r_info;
  Elf32_Sword	r_addend;
} Elf32_Rela;

typedef struct elf64_rela {
  Elf64_Addr r_offset;	/* Location at which to apply the action */
  Elf64_Xword r_info;	/* index and type of relocation */
  Elf64_Sxword r_addend;	/* Constant addend used to compute value */
} Elf64_Rela;

typedef struct elf32_sym{
  Elf32_Word	st_name;
  Elf32_Addr	st_value;
  Elf32_Word	st_size;
  unsigned char	st_info;
  unsigned char	st_other;
  Elf32_Half	st_shndx;
} Elf32_Sym;

typedef struct elf64_sym {
  Elf64_Word st_name;		/* Symbol name, index in string tbl */
  unsigned char	st_info;	/* Type and binding attributes */
  unsigned char	st_other;	/* No defined meaning, 0 */
  Elf64_Half st_shndx;		/* Associated section index */
  Elf64_Addr st_value;		/* Value of the symbol */
  Elf64_Xword st_size;		/* Associated symbol size */
} Elf64_Sym;


#define EI_NIDENT	16

typedef struct elf32_hdr{
  unsigned char	e_ident[EI_NIDENT];
  Elf32_Half	e_type;
  Elf32_Half	e_machine;
  Elf32_Word	e_version;
  Elf32_Addr	e_entry;  /* Entry point */
  Elf32_Off	e_phoff;
  Elf32_Off	e_shoff;
  Elf32_Word	e_flags;
  Elf32_Half	e_ehsize;
  Elf32_Half	e_phentsize;
  Elf32_Half	e_phnum;
  Elf32_Half	e_shentsize;
  Elf32_Half	e_shnum;
  Elf32_Half	e_shstrndx;
} Elf32_Ehdr;

typedef struct elf64_hdr {
  unsigned char	e_ident[EI_NIDENT];	/* ELF "magic number" */
  Elf64_Half e_type;
  Elf64_Half e_machine;
  Elf64_Word e_version;
  Elf64_Addr e_entry;		/* Entry point virtual address */
  Elf64_Off e_phoff;		/* Program header table file offset */
  Elf64_Off e_shoff;		/* Section header table file offset */
  Elf64_Word e_flags;
  Elf64_Half e_ehsize;
  Elf64_Half e_phentsize;
  Elf64_Half e_phnum;
  Elf64_Half e_shentsize;
  Elf64_Half e_shnum;
  Elf64_Half e_shstrndx;
} Elf64_Ehdr;

/* These constants define the permissions on sections in the program
   header, p_flags. */
#define PF_R		0x4
#define PF_W		0x2
#define PF_X		0x1

typedef struct elf32_phdr{
  Elf32_Word	p_type;
  Elf32_Off	p_offset;
  Elf32_Addr	p_vaddr;
  Elf32_Addr	p_paddr;
  Elf32_Word	p_filesz;
  Elf32_Word	p_memsz;
  Elf32_Word	p_flags;
  Elf32_Word	p_align;
} Elf32_Phdr;

typedef struct elf64_phdr {
  Elf64_Word p_type;
  Elf64_Word p_flags;
  Elf64_Off p_offset;		/* Segment file offset */
  Elf64_Addr p_vaddr;		/* Segment virtual address */
  Elf64_Addr p_paddr;		/* Segment physical address */
  Elf64_Xword p_filesz;		/* Segment size in file */
  Elf64_Xword p_memsz;		/* Segment size in memory */
  Elf64_Xword p_align;		/* Segment alignment, file & memory */
} Elf64_Phdr;

/* sh_type */
#define SHT_NULL	0
#define SHT_PROGBITS	1
#define SHT_SYMTAB	2
#define SHT_STRTAB	3
#define SHT_RELA	4
#define SHT_HASH	5
#define SHT_DYNAMIC	6
#define SHT_NOTE	7
#define SHT_NOBITS	8
#define SHT_REL		9
#define SHT_SHLIB	10
#define SHT_DYNSYM	11
#define SHT_NUM		12
#define SHT_LOPROC	0x70000000
#define SHT_HIPROC	0x7fffffff
#define SHT_LOUSER	0x80000000
#define SHT_HIUSER	0xffffffff

/* sh_flags */
#define SHF_WRITE	0x1
#define SHF_ALLOC	0x2
#define SHF_EXECINSTR	0x4
#define SHF_MASKPROC	0xf0000000

/* special section indexes */
#define SHN_UNDEF	0
#define SHN_LORESERVE	0xff00
#define SHN_LOPROC	0xff00
#define SHN_HIPROC	0xff1f
#define SHN_ABS		0xfff1
#define SHN_COMMON	0xfff2
#define SHN_HIRESERVE	0xffff
 
typedef struct elf32_shdr {
  Elf32_Word	sh_name;
  Elf32_Word	sh_type;
  Elf32_Word	sh_flags;
  Elf32_Addr	sh_addr;
  Elf32_Off	sh_offset;
  Elf32_Word	sh_size;
  Elf32_Word	sh_link;
  Elf32_Word	sh_info;
  Elf32_Word	sh_addralign;
  Elf32_Word	sh_entsize;
} Elf32_Shdr;

typedef struct elf64_shdr {
  Elf64_Word sh_name;		/* Section name, index in string tbl */
  Elf64_Word sh_type;		/* Type of section */
  Elf64_Xword sh_flags;		/* Miscellaneous section attributes */
  Elf64_Addr sh_addr;		/* Section virtual addr at execution */
  Elf64_Off sh_offset;		/* Section file offset */
  Elf64_Xword sh_size;		/* Size of section in bytes */
  Elf64_Word sh_link;		/* Index of another section */
  Elf64_Word sh_info;		/* Additional section information */
  Elf64_Xword sh_addralign;	/* Section alignment */
  Elf64_Xword sh_entsize;	/* Entry size if section holds table */
} Elf64_Shdr;

#define	EI_MAG0		0		/* e_ident[] indexes */
#define	EI_MAG1		1
#define	EI_MAG2		2
#define	EI_MAG3		3
#define	EI_CLASS	4
#define	EI_DATA		5
#define	EI_VERSION	6
#define	EI_OSABI	7
#define	EI_PAD		8

#define	ELFMAG0		0x7f		/* EI_MAG */
#define	ELFMAG1		'E'
#define	ELFMAG2		'L'
#define	ELFMAG3		'F'
#define	ELFMAG		"\177ELF"
#define	SELFMAG		4

#define	ELFCLASSNONE	0		/* EI_CLASS */
#define	ELFCLASS32	1
#define	ELFCLASS64	2
#define	ELFCLASSNUM	3

#define ELFDATANONE	0		/* e_ident[EI_DATA] */
#define ELFDATA2LSB	1
#define ELFDATA2MSB	2

#define EV_NONE		0		/* e_version, EI_VERSION */
#define EV_CURRENT	1
#define EV_NUM		2

#define ELFOSABI_NONE	0
#define ELFOSABI_LINUX	3

#ifndef ELF_OSABI
#define ELF_OSABI ELFOSABI_NONE
#endif

/*
 * Notes used in ET_CORE. Architectures export some of the arch register sets
 * using the corresponding note types via the PTRACE_GETREGSET and
 * PTRACE_SETREGSET requests.
 */
#define NT_PRSTATUS	1
#define NT_PRFPREG	2
#define NT_PRPSINFO	3
#define NT_TASKSTRUCT	4
#define NT_AUXV		6
/*
 * Note to userspace developers: size of NT_SIGINFO note may increase
 * in the future to accomodate more fields, don't assume it is fixed!
 */
#define NT_SIGINFO      0x53494749
#define NT_FILE         0x46494c45
#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
#define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
#define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
#define NT_S390_HIGH_GPRS	0x300	/* s390 upper register halves */
#define NT_S390_TIMER	0x301		/* s390 timer register */
#define NT_S390_TODCMP	0x302		/* s390 TOD clock comparator register */
#define NT_S390_TODPREG	0x303		/* s390 TOD programmable register */
#define NT_S390_CTRS	0x304		/* s390 control registers */
#define NT_S390_PREFIX	0x305		/* s390 prefix register */
#define NT_S390_LAST_BREAK	0x306	/* s390 breaking event address */
#define NT_S390_SYSTEM_CALL	0x307	/* s390 system call restart data */
#define NT_S390_TDB	0x308		/* s390 transaction diagnostic block */
#define NT_ARM_VFP	0x400		/* ARM VFP/NEON registers */
#define NT_ARM_TLS	0x401		/* ARM TLS register */
#define NT_ARM_HW_BREAK	0x402		/* ARM hardware breakpoint registers */
#define NT_ARM_HW_WATCH	0x403		/* ARM hardware watchpoint registers */
#define NT_METAG_CBUF	0x500		/* Metag catch buffer registers */
#define NT_METAG_RPIPE	0x501		/* Metag read pipeline state */
#define NT_METAG_TLS	0x502		/* Metag TLS pointer */


/* Note header in a PT_NOTE section */
typedef struct elf32_note {
  Elf32_Word	n_namesz;	/* Name size */
  Elf32_Word	n_descsz;	/* Content size */
  Elf32_Word	n_type;		/* Content type */
} Elf32_Nhdr;

/* Note header in a PT_NOTE section */
typedef struct elf64_note {
  Elf64_Word n_namesz;	/* Name size */
  Elf64_Word n_descsz;	/* Content size */
  Elf64_Word n_type;	/* Content type */
} Elf64_Nhdr;

#endif /* _UAPI_LINUX_ELF_H */
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424




                                                    
                                          








                                                                            



























































































































































































































































































































































































                                                                                      
                                        









































































































































































































































































































































































































































































































































































































                                                                                               
                                                                             


























































































































































































































































































                                                                                
















                                                                             

                                                                
 

                                                      
 


                                                                     
 

                                                                
































































































































                                                                             
/*
 * wm8991.c  --  WM8991 ALSA Soc Audio driver
 *
 * Copyright 2007-2010 Wolfson Microelectronics PLC.
 * Author: Graeme Gregory
 *         Graeme.Gregory@wolfsonmicro.com
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <asm/div64.h>

#include "wm8991.h"

struct wm8991_priv {
	enum snd_soc_control_type control_type;
	unsigned int pcmclk;
};

static const u16 wm8991_reg_defs[] = {
	0x8991,     /* R0  - Reset */
	0x0000,     /* R1  - Power Management (1) */
	0x6000,     /* R2  - Power Management (2) */
	0x0000,     /* R3  - Power Management (3) */
	0x4050,     /* R4  - Audio Interface (1) */
	0x4000,     /* R5  - Audio Interface (2) */
	0x01C8,     /* R6  - Clocking (1) */
	0x0000,     /* R7  - Clocking (2) */
	0x0040,     /* R8  - Audio Interface (3) */
	0x0040,     /* R9  - Audio Interface (4) */
	0x0004,     /* R10 - DAC CTRL */
	0x00C0,     /* R11 - Left DAC Digital Volume */
	0x00C0,     /* R12 - Right DAC Digital Volume */
	0x0000,     /* R13 - Digital Side Tone */
	0x0100,     /* R14 - ADC CTRL */
	0x00C0,     /* R15 - Left ADC Digital Volume */
	0x00C0,     /* R16 - Right ADC Digital Volume */
	0x0000,     /* R17 */
	0x0000,     /* R18 - GPIO CTRL 1 */
	0x1000,     /* R19 - GPIO1 & GPIO2 */
	0x1010,     /* R20 - GPIO3 & GPIO4 */
	0x1010,     /* R21 - GPIO5 & GPIO6 */
	0x8000,     /* R22 - GPIOCTRL 2 */
	0x0800,     /* R23 - GPIO_POL */
	0x008B,     /* R24 - Left Line Input 1&2 Volume */
	0x008B,     /* R25 - Left Line Input 3&4 Volume */
	0x008B,     /* R26 - Right Line Input 1&2 Volume */
	0x008B,     /* R27 - Right Line Input 3&4 Volume */
	0x0000,     /* R28 - Left Output Volume */
	0x0000,     /* R29 - Right Output Volume */
	0x0066,     /* R30 - Line Outputs Volume */
	0x0022,     /* R31 - Out3/4 Volume */
	0x0079,     /* R32 - Left OPGA Volume */
	0x0079,     /* R33 - Right OPGA Volume */
	0x0003,     /* R34 - Speaker Volume */
	0x0003,     /* R35 - ClassD1 */
	0x0000,     /* R36 */
	0x0100,     /* R37 - ClassD3 */
	0x0000,     /* R38 */
	0x0000,     /* R39 - Input Mixer1 */
	0x0000,     /* R40 - Input Mixer2 */
	0x0000,     /* R41 - Input Mixer3 */
	0x0000,     /* R42 - Input Mixer4 */
	0x0000,     /* R43 - Input Mixer5 */
	0x0000,     /* R44 - Input Mixer6 */
	0x0000,     /* R45 - Output Mixer1 */
	0x0000,     /* R46 - Output Mixer2 */
	0x0000,     /* R47 - Output Mixer3 */
	0x0000,     /* R48 - Output Mixer4 */
	0x0000,     /* R49 - Output Mixer5 */
	0x0000,     /* R50 - Output Mixer6 */
	0x0180,     /* R51 - Out3/4 Mixer */
	0x0000,     /* R52 - Line Mixer1 */
	0x0000,     /* R53 - Line Mixer2 */
	0x0000,     /* R54 - Speaker Mixer */
	0x0000,     /* R55 - Additional Control */
	0x0000,     /* R56 - AntiPOP1 */
	0x0000,     /* R57 - AntiPOP2 */
	0x0000,     /* R58 - MICBIAS */
	0x0000,     /* R59 */
	0x0008,     /* R60 - PLL1 */
	0x0031,     /* R61 - PLL2 */
	0x0026,     /* R62 - PLL3 */
};

#define wm8991_reset(c) snd_soc_write(c, WM8991_RESET, 0)

static const unsigned int rec_mix_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 7, TLV_DB_LINEAR_ITEM(-1500, 600),
};

static const unsigned int in_pga_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 0x1F, TLV_DB_LINEAR_ITEM(-1650, 3000),
};

static const unsigned int out_mix_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 7, TLV_DB_LINEAR_ITEM(0, -2100),
};

static const unsigned int out_pga_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 127, TLV_DB_LINEAR_ITEM(-7300, 600),
};

static const unsigned int out_omix_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 7, TLV_DB_LINEAR_ITEM(-600, 0),
};

static const unsigned int out_dac_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 255, TLV_DB_LINEAR_ITEM(-7163, 0),
};

static const unsigned int in_adc_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 255, TLV_DB_LINEAR_ITEM(-7163, 1763),
};

static const unsigned int out_sidetone_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 31, TLV_DB_LINEAR_ITEM(-3600, 0),
};

static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
				      struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
	int reg = kcontrol->private_value & 0xff;
	int ret;
	u16 val;

	ret = snd_soc_put_volsw(kcontrol, ucontrol);
	if (ret < 0)
		return ret;

	/* now hit the volume update bits (always bit 8) */
	val = snd_soc_read(codec, reg);
	return snd_soc_write(codec, reg, val | 0x0100);
}

static const char *wm8991_digital_sidetone[] =
{"None", "Left ADC", "Right ADC", "Reserved"};

static const struct soc_enum wm8991_left_digital_sidetone_enum =
	SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
			WM8991_ADC_TO_DACL_SHIFT,
			WM8991_ADC_TO_DACL_MASK,
			wm8991_digital_sidetone);

static const struct soc_enum wm8991_right_digital_sidetone_enum =
	SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE,
			WM8991_ADC_TO_DACR_SHIFT,
			WM8991_ADC_TO_DACR_MASK,
			wm8991_digital_sidetone);

static const char *wm8991_adcmode[] =
{"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};

static const struct soc_enum wm8991_right_adcmode_enum =
	SOC_ENUM_SINGLE(WM8991_ADC_CTRL,
			WM8991_ADC_HPF_CUT_SHIFT,
			WM8991_ADC_HPF_CUT_MASK,
			wm8991_adcmode);

static const struct snd_kcontrol_new wm8991_snd_controls[] = {
	/* INMIXL */
	SOC_SINGLE("LIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L12MNBST_BIT, 1, 0),
	SOC_SINGLE("LIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L34MNBST_BIT, 1, 0),
	/* INMIXR */
	SOC_SINGLE("RIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R12MNBST_BIT, 1, 0),
	SOC_SINGLE("RIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R34MNBST_BIT, 1, 0),

	/* LOMIX */
	SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER3,
		WM8991_LLI3LOVOL_SHIFT, WM8991_LLI3LOVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3,
		WM8991_LR12LOVOL_SHIFT, WM8991_LR12LOVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3,
		WM8991_LL12LOVOL_SHIFT, WM8991_LL12LOVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER5,
		WM8991_LRI3LOVOL_SHIFT, WM8991_LRI3LOVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER5,
		WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER5,
		WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv),

	/* ROMIX */
	SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER4,
		WM8991_RRI3ROVOL_SHIFT, WM8991_RRI3ROVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4,
		WM8991_RL12ROVOL_SHIFT, WM8991_RL12ROVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4,
		WM8991_RR12ROVOL_SHIFT, WM8991_RR12ROVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER6,
		WM8991_RLI3ROVOL_SHIFT, WM8991_RLI3ROVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER6,
		WM8991_RLBROVOL_SHIFT, WM8991_RLBROVOL_MASK, 1, out_mix_tlv),
	SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER6,
		WM8991_RRBROVOL_SHIFT, WM8991_RRBROVOL_MASK, 1, out_mix_tlv),

	/* LOUT */
	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8991_LEFT_OUTPUT_VOLUME,
		WM8991_LOUTVOL_SHIFT, WM8991_LOUTVOL_MASK, 0, out_pga_tlv),
	SOC_SINGLE("LOUT ZC", WM8991_LEFT_OUTPUT_VOLUME, WM8991_LOZC_BIT, 1, 0),

	/* ROUT */
	SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8991_RIGHT_OUTPUT_VOLUME,
		WM8991_ROUTVOL_SHIFT, WM8991_ROUTVOL_MASK, 0, out_pga_tlv),
	SOC_SINGLE("ROUT ZC", WM8991_RIGHT_OUTPUT_VOLUME, WM8991_ROZC_BIT, 1, 0),

	/* LOPGA */
	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8991_LEFT_OPGA_VOLUME,
		WM8991_LOPGAVOL_SHIFT, WM8991_LOPGAVOL_MASK, 0, out_pga_tlv),
	SOC_SINGLE("LOPGA ZC Switch", WM8991_LEFT_OPGA_VOLUME,
		WM8991_LOPGAZC_BIT, 1, 0),

	/* ROPGA */
	SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8991_RIGHT_OPGA_VOLUME,
		WM8991_ROPGAVOL_SHIFT, WM8991_ROPGAVOL_MASK, 0, out_pga_tlv),
	SOC_SINGLE("ROPGA ZC Switch", WM8991_RIGHT_OPGA_VOLUME,
		WM8991_ROPGAZC_BIT, 1, 0),

	SOC_SINGLE("LON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
		WM8991_LONMUTE_BIT, 1, 0),
	SOC_SINGLE("LOP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
		WM8991_LOPMUTE_BIT, 1, 0),
	SOC_SINGLE("LOP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME,
		WM8991_LOATTN_BIT, 1, 0),
	SOC_SINGLE("RON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
		WM8991_RONMUTE_BIT, 1, 0),
	SOC_SINGLE("ROP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME,
		WM8991_ROPMUTE_BIT, 1, 0),
	SOC_SINGLE("ROP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME,
		WM8991_ROATTN_BIT, 1, 0),

	SOC_SINGLE("OUT3 Mute Switch", WM8991_OUT3_4_VOLUME,
		WM8991_OUT3MUTE_BIT, 1, 0),
	SOC_SINGLE("OUT3 Attenuation Switch", WM8991_OUT3_4_VOLUME,
		WM8991_OUT3ATTN_BIT, 1, 0),

	SOC_SINGLE("OUT4 Mute Switch", WM8991_OUT3_4_VOLUME,
		WM8991_OUT4MUTE_BIT, 1, 0),
	SOC_SINGLE("OUT4 Attenuation Switch", WM8991_OUT3_4_VOLUME,
		WM8991_OUT4ATTN_BIT, 1, 0),

	SOC_SINGLE("Speaker Mode Switch", WM8991_CLASSD1,
		WM8991_CDMODE_BIT, 1, 0),

	SOC_SINGLE("Speaker Output Attenuation Volume", WM8991_SPEAKER_VOLUME,
		WM8991_SPKVOL_SHIFT, WM8991_SPKVOL_MASK, 0),
	SOC_SINGLE("Speaker DC Boost Volume", WM8991_CLASSD3,
		WM8991_DCGAIN_SHIFT, WM8991_DCGAIN_MASK, 0),
	SOC_SINGLE("Speaker AC Boost Volume", WM8991_CLASSD3,
		WM8991_ACGAIN_SHIFT, WM8991_ACGAIN_MASK, 0),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
		WM8991_LEFT_DAC_DIGITAL_VOLUME,
		WM8991_DACL_VOL_SHIFT,
		WM8991_DACL_VOL_MASK,
		0,
		out_dac_tlv),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
		WM8991_RIGHT_DAC_DIGITAL_VOLUME,
		WM8991_DACR_VOL_SHIFT,
		WM8991_DACR_VOL_MASK,
		0,
		out_dac_tlv),

	SOC_ENUM("Left Digital Sidetone", wm8991_left_digital_sidetone_enum),
	SOC_ENUM("Right Digital Sidetone", wm8991_right_digital_sidetone_enum),

	SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE,
		WM8991_ADCL_DAC_SVOL_SHIFT, WM8991_ADCL_DAC_SVOL_MASK, 0,
		out_sidetone_tlv),
	SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE,
		WM8991_ADCR_DAC_SVOL_SHIFT, WM8991_ADCR_DAC_SVOL_MASK, 0,
		out_sidetone_tlv),

	SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8991_ADC_CTRL,
		WM8991_ADC_HPF_ENA_BIT, 1, 0),

	SOC_ENUM("ADC HPF Mode", wm8991_right_adcmode_enum),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
		WM8991_LEFT_ADC_DIGITAL_VOLUME,
		WM8991_ADCL_VOL_SHIFT,
		WM8991_ADCL_VOL_MASK,
		0,
		in_adc_tlv),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
		WM8991_RIGHT_ADC_DIGITAL_VOLUME,
		WM8991_ADCR_VOL_SHIFT,
		WM8991_ADCR_VOL_MASK,
		0,
		in_adc_tlv),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
		WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
		WM8991_LIN12VOL_SHIFT,
		WM8991_LIN12VOL_MASK,
		0,
		in_pga_tlv),

	SOC_SINGLE("LIN12 ZC Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
		WM8991_LI12ZC_BIT, 1, 0),

	SOC_SINGLE("LIN12 Mute Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME,
		WM8991_LI12MUTE_BIT, 1, 0),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
		WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
		WM8991_LIN34VOL_SHIFT,
		WM8991_LIN34VOL_MASK,
		0,
		in_pga_tlv),

	SOC_SINGLE("LIN34 ZC Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
		WM8991_LI34ZC_BIT, 1, 0),

	SOC_SINGLE("LIN34 Mute Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME,
		WM8991_LI34MUTE_BIT, 1, 0),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
		WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
		WM8991_RIN12VOL_SHIFT,
		WM8991_RIN12VOL_MASK,
		0,
		in_pga_tlv),

	SOC_SINGLE("RIN12 ZC Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
		WM8991_RI12ZC_BIT, 1, 0),

	SOC_SINGLE("RIN12 Mute Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME,
		WM8991_RI12MUTE_BIT, 1, 0),

	SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
		WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
		WM8991_RIN34VOL_SHIFT,
		WM8991_RIN34VOL_MASK,
		0,
		in_pga_tlv),

	SOC_SINGLE("RIN34 ZC Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
		WM8991_RI34ZC_BIT, 1, 0),

	SOC_SINGLE("RIN34 Mute Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME,
		WM8991_RI34MUTE_BIT, 1, 0),
};

/*
 * _DAPM_ Controls
 */
static int inmixer_event(struct snd_soc_dapm_widget *w,
			 struct snd_kcontrol *kcontrol, int event)
{
	u16 reg, fakepower;

	reg = snd_soc_read(w->codec, WM8991_POWER_MANAGEMENT_2);
	fakepower = snd_soc_read(w->codec, WM8991_INTDRIVBITS);

	if (fakepower & ((1 << WM8991_INMIXL_PWR_BIT) |
			 (1 << WM8991_AINLMUX_PWR_BIT)))
		reg |= WM8991_AINL_ENA;
	else
		reg &= ~WM8991_AINL_ENA;

	if (fakepower & ((1 << WM8991_INMIXR_PWR_BIT) |
			 (1 << WM8991_AINRMUX_PWR_BIT)))
		reg |= WM8991_AINR_ENA;
	else
		reg &= ~WM8991_AINR_ENA;

	snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg);
	return 0;
}

static int outmixer_event(struct snd_soc_dapm_widget *w,
			  struct snd_kcontrol *kcontrol, int event)
{
	u32 reg_shift = kcontrol->private_value & 0xfff;
	int ret = 0;
	u16 reg;

	switch (reg_shift) {
	case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8):
		reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER1);
		if (reg & WM8991_LDLO) {
			printk(KERN_WARNING
			       "Cannot set as Output Mixer 1 LDLO Set\n");
			ret = -1;
		}
		break;

	case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8):
		reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER2);
		if (reg & WM8991_RDRO) {
			printk(KERN_WARNING
			       "Cannot set as Output Mixer 2 RDRO Set\n");
			ret = -1;
		}
		break;

	case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8):
		reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
		if (reg & WM8991_LDSPK) {
			printk(KERN_WARNING
			       "Cannot set as Speaker Mixer LDSPK Set\n");
			ret = -1;
		}
		break;

	case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8):
		reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
		if (reg & WM8991_RDSPK) {
			printk(KERN_WARNING
			       "Cannot set as Speaker Mixer RDSPK Set\n");
			ret = -1;
		}
		break;
	}

	return ret;
}

/* INMIX dB values */
static const unsigned int in_mix_tlv[] = {
	TLV_DB_RANGE_HEAD(1),
	0, 7, TLV_DB_LINEAR_ITEM(-1200, 600),
};

/* Left In PGA Connections */
static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls[] = {
	SOC_DAPM_SINGLE("LIN1 Switch", WM8991_INPUT_MIXER2, WM8991_LMN1_BIT, 1, 0),
	SOC_DAPM_SINGLE("LIN2 Switch", WM8991_INPUT_MIXER2, WM8991_LMP2_BIT, 1, 0),
};

static const struct snd_kcontrol_new wm8991_dapm_lin34_pga_controls[] = {
	SOC_DAPM_SINGLE("LIN3 Switch", WM8991_INPUT_MIXER2, WM8991_LMN3_BIT, 1, 0),
	SOC_DAPM_SINGLE("LIN4 Switch", WM8991_INPUT_MIXER2, WM8991_LMP4_BIT, 1, 0),
};

/* Right In PGA Connections */
static const struct snd_kcontrol_new wm8991_dapm_rin12_pga_controls[] = {
	SOC_DAPM_SINGLE("RIN1 Switch", WM8991_INPUT_MIXER2, WM8991_RMN1_BIT, 1, 0),
	SOC_DAPM_SINGLE("RIN2 Switch", WM8991_INPUT_MIXER2, WM8991_RMP2_BIT, 1, 0),
};

static const struct snd_kcontrol_new wm8991_dapm_rin34_pga_controls[] = {
	SOC_DAPM_SINGLE("RIN3 Switch", WM8991_INPUT_MIXER2, WM8991_RMN3_BIT, 1, 0),
	SOC_DAPM_SINGLE("RIN4 Switch", WM8991_INPUT_MIXER2, WM8991_RMP4_BIT, 1, 0),
};

/* INMIXL */
static const struct snd_kcontrol_new wm8991_dapm_inmixl_controls[] = {
	SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8991_INPUT_MIXER3,
		WM8991_LDBVOL_SHIFT, WM8991_LDBVOL_MASK, 0, in_mix_tlv),
	SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8991_INPUT_MIXER5, WM8991_LI2BVOL_SHIFT,
		7, 0, in_mix_tlv),
	SOC_DAPM_SINGLE("LINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT,
		1, 0),
	SOC_DAPM_SINGLE("LINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT,
		1, 0),
};

/* INMIXR */
static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = {
	SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8991_INPUT_MIXER4,
		WM8991_RDBVOL_SHIFT, WM8991_RDBVOL_MASK, 0, in_mix_tlv),
	SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8991_INPUT_MIXER6, WM8991_RI2BVOL_SHIFT,
		7, 0, in_mix_tlv),
	SOC_DAPM_SINGLE("RINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT,
		1, 0),
	SOC_DAPM_SINGLE("RINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT,
		1, 0),
};

/* AINLMUX */
static const char *wm8991_ainlmux[] =
{"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};

static const struct soc_enum wm8991_ainlmux_enum =
	SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT,
			ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux);

static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls =
	SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum);

/* DIFFINL */

/* AINRMUX */
static const char *wm8991_ainrmux[] =
{"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};

static const struct soc_enum wm8991_ainrmux_enum =
	SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT,
			ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux);

static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls =
	SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum);

/* RXVOICE */
static const struct snd_kcontrol_new wm8991_dapm_rxvoice_controls[] = {
	SOC_DAPM_SINGLE_TLV("LIN4RXN", WM8991_INPUT_MIXER5, WM8991_LR4BVOL_SHIFT,
		WM8991_LR4BVOL_MASK, 0, in_mix_tlv),
	SOC_DAPM_SINGLE_TLV("RIN4RXP", WM8991_INPUT_MIXER6, WM8991_RL4BVOL_SHIFT,
		WM8991_RL4BVOL_MASK, 0, in_mix_tlv),
};

/* LOMIX */
static const struct snd_kcontrol_new wm8991_dapm_lomix_controls[] = {
	SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER1,
		WM8991_LRBLO_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER1,
		WM8991_LLBLO_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER1,
		WM8991_LRI3LO_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER1,
		WM8991_LLI3LO_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1,
		WM8991_LR12LO_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1,
		WM8991_LL12LO_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8991_OUTPUT_MIXER1,
		WM8991_LDLO_BIT, 1, 0),
};

/* ROMIX */
static const struct snd_kcontrol_new wm8991_dapm_romix_controls[] = {
	SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER2,
		WM8991_RLBRO_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER2,
		WM8991_RRBRO_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER2,
		WM8991_RLI3RO_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER2,
		WM8991_RRI3RO_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2,
		WM8991_RL12RO_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2,
		WM8991_RR12RO_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8991_OUTPUT_MIXER2,
		WM8991_RDRO_BIT, 1, 0),
};

/* LONMIX */
static const struct snd_kcontrol_new wm8991_dapm_lonmix_controls[] = {
	SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1,
		WM8991_LLOPGALON_BIT, 1, 0),
	SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER1,
		WM8991_LROPGALON_BIT, 1, 0),
	SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8991_LINE_MIXER1,
		WM8991_LOPLON_BIT, 1, 0),
};

/* LOPMIX */
static const struct snd_kcontrol_new wm8991_dapm_lopmix_controls[] = {
	SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER1,
		WM8991_LR12LOP_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER1,
		WM8991_LL12LOP_BIT, 1, 0),
	SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1,
		WM8991_LLOPGALOP_BIT, 1, 0),
};

/* RONMIX */
static const struct snd_kcontrol_new wm8991_dapm_ronmix_controls[] = {
	SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2,
		WM8991_RROPGARON_BIT, 1, 0),
	SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER2,
		WM8991_RLOPGARON_BIT, 1, 0),
	SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8991_LINE_MIXER2,
		WM8991_ROPRON_BIT, 1, 0),
};

/* ROPMIX */
static const struct snd_kcontrol_new wm8991_dapm_ropmix_controls[] = {
	SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER2,
		WM8991_RL12ROP_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER2,
		WM8991_RR12ROP_BIT, 1, 0),
	SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2,
		WM8991_RROPGAROP_BIT, 1, 0),
};

/* OUT3MIX */
static const struct snd_kcontrol_new wm8991_dapm_out3mix_controls[] = {
	SOC_DAPM_SINGLE("OUT3MIX LIN4RXN Bypass Switch", WM8991_OUT3_4_MIXER,
		WM8991_LI4O3_BIT, 1, 0),
	SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8991_OUT3_4_MIXER,
		WM8991_LPGAO3_BIT, 1, 0),
};

/* OUT4MIX */
static const struct snd_kcontrol_new wm8991_dapm_out4mix_controls[] = {
	SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8991_OUT3_4_MIXER,
		WM8991_RPGAO4_BIT, 1, 0),
	SOC_DAPM_SINGLE("OUT4MIX RIN4RXP Bypass Switch", WM8991_OUT3_4_MIXER,
		WM8991_RI4O4_BIT, 1, 0),
};

/* SPKMIX */
static const struct snd_kcontrol_new wm8991_dapm_spkmix_controls[] = {
	SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8991_SPEAKER_MIXER,
		WM8991_LI2SPK_BIT, 1, 0),
	SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8991_SPEAKER_MIXER,
		WM8991_LB2SPK_BIT, 1, 0),
	SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8991_SPEAKER_MIXER,
		WM8991_LOPGASPK_BIT, 1, 0),
	SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8991_SPEAKER_MIXER,
		WM8991_LDSPK_BIT, 1, 0),
	SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8991_SPEAKER_MIXER,
		WM8991_RDSPK_BIT, 1, 0),
	SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8991_SPEAKER_MIXER,
		WM8991_ROPGASPK_BIT, 1, 0),
	SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8991_SPEAKER_MIXER,
		WM8991_RL12ROP_BIT, 1, 0),
	SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8991_SPEAKER_MIXER,
		WM8991_RI2SPK_BIT, 1, 0),
};

static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
	/* Input Side */
	/* Input Lines */
	SND_SOC_DAPM_INPUT("LIN1"),
	SND_SOC_DAPM_INPUT("LIN2"),
	SND_SOC_DAPM_INPUT("LIN3"),
	SND_SOC_DAPM_INPUT("LIN4RXN"),
	SND_SOC_DAPM_INPUT("RIN3"),
	SND_SOC_DAPM_INPUT("RIN4RXP"),
	SND_SOC_DAPM_INPUT("RIN1"),
	SND_SOC_DAPM_INPUT("RIN2"),
	SND_SOC_DAPM_INPUT("Internal ADC Source"),

	/* DACs */
	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2,
		WM8991_ADCL_ENA_BIT, 0),
	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8991_POWER_MANAGEMENT_2,
		WM8991_ADCR_ENA_BIT, 0),

	/* Input PGAs */
	SND_SOC_DAPM_MIXER("LIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN12_ENA_BIT,
		0, &wm8991_dapm_lin12_pga_controls[0],
		ARRAY_SIZE(wm8991_dapm_lin12_pga_controls)),
	SND_SOC_DAPM_MIXER("LIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN34_ENA_BIT,
		0, &wm8991_dapm_lin34_pga_controls[0],
		ARRAY_SIZE(wm8991_dapm_lin34_pga_controls)),
	SND_SOC_DAPM_MIXER("RIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN12_ENA_BIT,
		0, &wm8991_dapm_rin12_pga_controls[0],
		ARRAY_SIZE(wm8991_dapm_rin12_pga_controls)),
	SND_SOC_DAPM_MIXER("RIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN34_ENA_BIT,
		0, &wm8991_dapm_rin34_pga_controls[0],
		ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)),

	/* INMIXL */
	SND_SOC_DAPM_MIXER_E("INMIXL", WM8991_INTDRIVBITS, WM8991_INMIXL_PWR_BIT, 0,
		&wm8991_dapm_inmixl_controls[0],
		ARRAY_SIZE(wm8991_dapm_inmixl_controls),
		inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

	/* AINLMUX */
	SND_SOC_DAPM_MUX_E("AINLMUX", WM8991_INTDRIVBITS, WM8991_AINLMUX_PWR_BIT, 0,
		&wm8991_dapm_ainlmux_controls, inmixer_event,
		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

	/* INMIXR */
	SND_SOC_DAPM_MIXER_E("INMIXR", WM8991_INTDRIVBITS, WM8991_INMIXR_PWR_BIT, 0,
		&wm8991_dapm_inmixr_controls[0],
		ARRAY_SIZE(wm8991_dapm_inmixr_controls),
		inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

	/* AINRMUX */
	SND_SOC_DAPM_MUX_E("AINRMUX", WM8991_INTDRIVBITS, WM8991_AINRMUX_PWR_BIT, 0,
		&wm8991_dapm_ainrmux_controls, inmixer_event,
		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

	/* Output Side */
	/* DACs */
	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8991_POWER_MANAGEMENT_3,
		WM8991_DACL_ENA_BIT, 0),
	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8991_POWER_MANAGEMENT_3,
		WM8991_DACR_ENA_BIT, 0),

	/* LOMIX */
	SND_SOC_DAPM_MIXER_E("LOMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOMIX_ENA_BIT,
		0, &wm8991_dapm_lomix_controls[0],
		ARRAY_SIZE(wm8991_dapm_lomix_controls),
		outmixer_event, SND_SOC_DAPM_PRE_REG),

	/* LONMIX */
	SND_SOC_DAPM_MIXER("LONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LON_ENA_BIT, 0,
		&wm8991_dapm_lonmix_controls[0],
		ARRAY_SIZE(wm8991_dapm_lonmix_controls)),

	/* LOPMIX */
	SND_SOC_DAPM_MIXER("LOPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOP_ENA_BIT, 0,
		&wm8991_dapm_lopmix_controls[0],
		ARRAY_SIZE(wm8991_dapm_lopmix_controls)),

	/* OUT3MIX */
	SND_SOC_DAPM_MIXER("OUT3MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT3_ENA_BIT, 0,
		&wm8991_dapm_out3mix_controls[0],
		ARRAY_SIZE(wm8991_dapm_out3mix_controls)),

	/* SPKMIX */
	SND_SOC_DAPM_MIXER_E("SPKMIX", WM8991_POWER_MANAGEMENT_1, WM8991_SPK_ENA_BIT, 0,
		&wm8991_dapm_spkmix_controls[0],
		ARRAY_SIZE(wm8991_dapm_spkmix_controls), outmixer_event,
		SND_SOC_DAPM_PRE_REG),

	/* OUT4MIX */
	SND_SOC_DAPM_MIXER("OUT4MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT4_ENA_BIT, 0,
		&wm8991_dapm_out4mix_controls[0],
		ARRAY_SIZE(wm8991_dapm_out4mix_controls)),

	/* ROPMIX */
	SND_SOC_DAPM_MIXER("ROPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROP_ENA_BIT, 0,
		&wm8991_dapm_ropmix_controls[0],
		ARRAY_SIZE(wm8991_dapm_ropmix_controls)),

	/* RONMIX */
	SND_SOC_DAPM_MIXER("RONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_RON_ENA_BIT, 0,
		&wm8991_dapm_ronmix_controls[0],
		ARRAY_SIZE(wm8991_dapm_ronmix_controls)),

	/* ROMIX */
	SND_SOC_DAPM_MIXER_E("ROMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROMIX_ENA_BIT,
		0, &wm8991_dapm_romix_controls[0],
		ARRAY_SIZE(wm8991_dapm_romix_controls),
		outmixer_event, SND_SOC_DAPM_PRE_REG),

	/* LOUT PGA */
	SND_SOC_DAPM_PGA("LOUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_LOUT_ENA_BIT, 0,
		NULL, 0),

	/* ROUT PGA */
	SND_SOC_DAPM_PGA("ROUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_ROUT_ENA_BIT, 0,
		NULL, 0),

	/* LOPGA */
	SND_SOC_DAPM_PGA("LOPGA", WM8991_POWER_MANAGEMENT_3, WM8991_LOPGA_ENA_BIT, 0,
		NULL, 0),

	/* ROPGA */
	SND_SOC_DAPM_PGA("ROPGA", WM8991_POWER_MANAGEMENT_3, WM8991_ROPGA_ENA_BIT, 0,
		NULL, 0),

	/* MICBIAS */
	SND_SOC_DAPM_MICBIAS("MICBIAS", WM8991_POWER_MANAGEMENT_1,
		WM8991_MICBIAS_ENA_BIT, 0),

	SND_SOC_DAPM_OUTPUT("LON"),
	SND_SOC_DAPM_OUTPUT("LOP"),
	SND_SOC_DAPM_OUTPUT("OUT3"),
	SND_SOC_DAPM_OUTPUT("LOUT"),
	SND_SOC_DAPM_OUTPUT("SPKN"),
	SND_SOC_DAPM_OUTPUT("SPKP"),
	SND_SOC_DAPM_OUTPUT("ROUT"),
	SND_SOC_DAPM_OUTPUT("OUT4"),
	SND_SOC_DAPM_OUTPUT("ROP"),
	SND_SOC_DAPM_OUTPUT("RON"),
	SND_SOC_DAPM_OUTPUT("OUT"),

	SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
};

static const struct snd_soc_dapm_route audio_map[] = {
	/* Make DACs turn on when playing even if not mixed into any outputs */
	{"Internal DAC Sink", NULL, "Left DAC"},
	{"Internal DAC Sink", NULL, "Right DAC"},

	/* Make ADCs turn on when recording even if not mixed from any inputs */
	{"Left ADC", NULL, "Internal ADC Source"},
	{"Right ADC", NULL, "Internal ADC Source"},

	/* Input Side */
	/* LIN12 PGA */
	{"LIN12 PGA", "LIN1 Switch", "LIN1"},
	{"LIN12 PGA", "LIN2 Switch", "LIN2"},
	/* LIN34 PGA */
	{"LIN34 PGA", "LIN3 Switch", "LIN3"},
	{"LIN34 PGA", "LIN4 Switch", "LIN4RXN"},
	/* INMIXL */
	{"INMIXL", "Record Left Volume", "LOMIX"},
	{"INMIXL", "LIN2 Volume", "LIN2"},
	{"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
	{"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
	/* AINLMUX */
	{"AINLMUX", "INMIXL Mix", "INMIXL"},
	{"AINLMUX", "DIFFINL Mix", "LIN12 PGA"},
	{"AINLMUX", "DIFFINL Mix", "LIN34 PGA"},
	{"AINLMUX", "RXVOICE Mix", "LIN4RXN"},
	{"AINLMUX", "RXVOICE Mix", "RIN4RXP"},
	/* ADC */
	{"Left ADC", NULL, "AINLMUX"},

	/* RIN12 PGA */
	{"RIN12 PGA", "RIN1 Switch", "RIN1"},
	{"RIN12 PGA", "RIN2 Switch", "RIN2"},
	/* RIN34 PGA */
	{"RIN34 PGA", "RIN3 Switch", "RIN3"},
	{"RIN34 PGA", "RIN4 Switch", "RIN4RXP"},
	/* INMIXL */
	{"INMIXR", "Record Right Volume", "ROMIX"},
	{"INMIXR", "RIN2 Volume", "RIN2"},
	{"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
	{"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
	/* AINRMUX */
	{"AINRMUX", "INMIXR Mix", "INMIXR"},
	{"AINRMUX", "DIFFINR Mix", "RIN12 PGA"},
	{"AINRMUX", "DIFFINR Mix", "RIN34 PGA"},
	{"AINRMUX", "RXVOICE Mix", "LIN4RXN"},
	{"AINRMUX", "RXVOICE Mix", "RIN4RXP"},
	/* ADC */
	{"Right ADC", NULL, "AINRMUX"},

	/* LOMIX */
	{"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
	{"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
	{"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
	{"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
	{"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"},
	{"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"},
	{"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},

	/* ROMIX */
	{"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
	{"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
	{"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
	{"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
	{"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"},
	{"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"},
	{"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},

	/* SPKMIX */
	{"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
	{"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
	{"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"},
	{"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"},
	{"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
	{"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
	{"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
	{"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},

	/* LONMIX */
	{"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
	{"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
	{"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},

	/* LOPMIX */
	{"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
	{"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
	{"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},

	/* OUT3MIX */
	{"OUT3MIX", "OUT3MIX LIN4RXN Bypass Switch", "LIN4RXN"},
	{"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},

	/* OUT4MIX */
	{"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
	{"OUT4MIX", "OUT4MIX RIN4RXP Bypass Switch", "RIN4RXP"},

	/* RONMIX */
	{"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
	{"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
	{"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},

	/* ROPMIX */
	{"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
	{"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
	{"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},

	/* Out Mixer PGAs */
	{"LOPGA", NULL, "LOMIX"},
	{"ROPGA", NULL, "ROMIX"},

	{"LOUT PGA", NULL, "LOMIX"},
	{"ROUT PGA", NULL, "ROMIX"},

	/* Output Pins */
	{"LON", NULL, "LONMIX"},
	{"LOP", NULL, "LOPMIX"},
	{"OUT", NULL, "OUT3MIX"},
	{"LOUT", NULL, "LOUT PGA"},
	{"SPKN", NULL, "SPKMIX"},
	{"ROUT", NULL, "ROUT PGA"},
	{"OUT4", NULL, "OUT4MIX"},
	{"ROP", NULL, "ROPMIX"},
	{"RON", NULL, "RONMIX"},
};

/* PLL divisors */
struct _pll_div {
	u32 div2;
	u32 n;
	u32 k;
};

/* The size in bits of the pll divide multiplied by 10
 * to allow rounding later */
#define FIXED_PLL_SIZE ((1 << 16) * 10)

static void pll_factors(struct _pll_div *pll_div, unsigned int target,
			unsigned int source)
{
	u64 Kpart;
	unsigned int K, Ndiv, Nmod;


	Ndiv = target / source;
	if (Ndiv < 6) {
		source >>= 1;
		pll_div->div2 = 1;
		Ndiv = target / source;
	} else
		pll_div->div2 = 0;

	if ((Ndiv < 6) || (Ndiv > 12))
		printk(KERN_WARNING
		       "WM8991 N value outwith recommended range! N = %d\n", Ndiv);

	pll_div->n = Ndiv;
	Nmod = target % source;
	Kpart = FIXED_PLL_SIZE * (long long)Nmod;

	do_div(Kpart, source);

	K = Kpart & 0xFFFFFFFF;

	/* Check if we need to round */
	if ((K % 10) >= 5)
		K += 5;

	/* Move down to proper range now rounding is done */
	K /= 10;

	pll_div->k = K;
}

static int wm8991_set_dai_pll(struct snd_soc_dai *codec_dai,
			      int pll_id, int src, unsigned int freq_in, unsigned int freq_out)
{
	u16 reg;
	struct snd_soc_codec *codec = codec_dai->codec;
	struct _pll_div pll_div;

	if (freq_in && freq_out) {
		pll_factors(&pll_div, freq_out * 4, freq_in);

		/* Turn on PLL */
		reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
		reg |= WM8991_PLL_ENA;
		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg);

		/* sysclk comes from PLL */
		reg = snd_soc_read(codec, WM8991_CLOCKING_2);
		snd_soc_write(codec, WM8991_CLOCKING_2, reg | WM8991_SYSCLK_SRC);

		/* set up N , fractional mode and pre-divisor if necessary */
		snd_soc_write(codec, WM8991_PLL1, pll_div.n | WM8991_SDM |
			      (pll_div.div2 ? WM8991_PRESCALE : 0));
		snd_soc_write(codec, WM8991_PLL2, (u8)(pll_div.k>>8));
		snd_soc_write(codec, WM8991_PLL3, (u8)(pll_div.k & 0xFF));
	} else {
		/* Turn on PLL */
		reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2);
		reg &= ~WM8991_PLL_ENA;
		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg);
	}
	return 0;
}

/*
 * Set's ADC and Voice DAC format.
 */
static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai,
			      unsigned int fmt)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	u16 audio1, audio3;

	audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1);
	audio3 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_3);

	/* set master/slave audio interface */
	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		audio3 &= ~WM8991_AIF_MSTR1;
		break;
	case SND_SOC_DAIFMT_CBM_CFM:
		audio3 |= WM8991_AIF_MSTR1;
		break;
	default:
		return -EINVAL;
	}

	audio1 &= ~WM8991_AIF_FMT_MASK;

	/* interface format */
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		audio1 |= WM8991_AIF_TMF_I2S;
		audio1 &= ~WM8991_AIF_LRCLK_INV;
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		audio1 |= WM8991_AIF_TMF_RIGHTJ;
		audio1 &= ~WM8991_AIF_LRCLK_INV;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		audio1 |= WM8991_AIF_TMF_LEFTJ;
		audio1 &= ~WM8991_AIF_LRCLK_INV;
		break;
	case SND_SOC_DAIFMT_DSP_A:
		audio1 |= WM8991_AIF_TMF_DSP;
		audio1 &= ~WM8991_AIF_LRCLK_INV;
		break;
	case SND_SOC_DAIFMT_DSP_B:
		audio1 |= WM8991_AIF_TMF_DSP | WM8991_AIF_LRCLK_INV;
		break;
	default:
		return -EINVAL;
	}

	snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1);
	snd_soc_write(codec, WM8991_AUDIO_INTERFACE_3, audio3);
	return 0;
}

static int wm8991_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
				 int div_id, int div)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	u16 reg;

	switch (div_id) {
	case WM8991_MCLK_DIV:
		reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
		      ~WM8991_MCLK_DIV_MASK;
		snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
		break;
	case WM8991_DACCLK_DIV:
		reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
		      ~WM8991_DAC_CLKDIV_MASK;
		snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
		break;
	case WM8991_ADCCLK_DIV:
		reg = snd_soc_read(codec, WM8991_CLOCKING_2) &
		      ~WM8991_ADC_CLKDIV_MASK;
		snd_soc_write(codec, WM8991_CLOCKING_2, reg | div);
		break;
	case WM8991_BCLK_DIV:
		reg = snd_soc_read(codec, WM8991_CLOCKING_1) &
		      ~WM8991_BCLK_DIV_MASK;
		snd_soc_write(codec, WM8991_CLOCKING_1, reg | div);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

/*
 * Set PCM DAI bit size and sample rate.
 */
static int wm8991_hw_params(struct snd_pcm_substream *substream,
			    struct snd_pcm_hw_params *params,
			    struct snd_soc_dai *dai)
{
	struct snd_soc_codec *codec = dai->codec;
	u16 audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1);

	audio1 &= ~WM8991_AIF_WL_MASK;
	/* bit size */
	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		break;
	case SNDRV_PCM_FORMAT_S20_3LE:
		audio1 |= WM8991_AIF_WL_20BITS;
		break;
	case SNDRV_PCM_FORMAT_S24_LE:
		audio1 |= WM8991_AIF_WL_24BITS;
		break;
	case SNDRV_PCM_FORMAT_S32_LE:
		audio1 |= WM8991_AIF_WL_32BITS;
		break;
	}

	snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1);
	return 0;
}

static int wm8991_mute(struct snd_soc_dai *dai, int mute)
{
	struct snd_soc_codec *codec = dai->codec;
	u16 val;

	val  = snd_soc_read(codec, WM8991_DAC_CTRL) & ~WM8991_DAC_MUTE;
	if (mute)
		snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);
	else
		snd_soc_write(codec, WM8991_DAC_CTRL, val);
	return 0;
}

static int wm8991_set_bias_level(struct snd_soc_codec *codec,
				 enum snd_soc_bias_level level)
{
	u16 val;

	switch (level) {
	case SND_SOC_BIAS_ON:
		break;

	case SND_SOC_BIAS_PREPARE:
		/* VMID=2*50k */
		val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) &
		      ~WM8991_VMID_MODE_MASK;
		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x2);
		break;

	case SND_SOC_BIAS_STANDBY:
		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
			snd_soc_cache_sync(codec);
			/* Enable all output discharge bits */
			snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
				      WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
				      WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
				      WM8991_DIS_ROUT);

			/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
				      WM8991_BUFDCOPEN | WM8991_POBCTRL |
				      WM8991_VMIDTOG);

			/* Delay to allow output caps to discharge */
			msleep(300);

			/* Disable VMIDTOG */
			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
				      WM8991_BUFDCOPEN | WM8991_POBCTRL);

			/* disable all output discharge bits */
			snd_soc_write(codec, WM8991_ANTIPOP1, 0);

			/* Enable outputs */
			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1b00);

			msleep(50);

			/* Enable VMID at 2x50k */
			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f02);

			msleep(100);

			/* Enable VREF */
			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03);

			msleep(600);

			/* Enable BUFIOEN */
			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
				      WM8991_BUFDCOPEN | WM8991_POBCTRL |
				      WM8991_BUFIOEN);

			/* Disable outputs */
			snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x3);

			/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
			snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_BUFIOEN);
		}

		/* VMID=2*250k */
		val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) &
		      ~WM8991_VMID_MODE_MASK;
		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x4);
		break;

	case SND_SOC_BIAS_OFF:
		/* Enable POBCTRL and SOFT_ST */
		snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
			      WM8991_POBCTRL | WM8991_BUFIOEN);

		/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
		snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST |
			      WM8991_BUFDCOPEN | WM8991_POBCTRL |
			      WM8991_BUFIOEN);

		/* mute DAC */
		val = snd_soc_read(codec, WM8991_DAC_CTRL);
		snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE);

		/* Enable any disabled outputs */
		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03);

		/* Disable VMID */
		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f01);

		msleep(300);

		/* Enable all output discharge bits */
		snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
			      WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
			      WM8991_DIS_OUT4 | WM8991_DIS_LOUT |
			      WM8991_DIS_ROUT);

		/* Disable VREF */
		snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x0);

		/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
		snd_soc_write(codec, WM8991_ANTIPOP2, 0x0);
		codec->cache_sync = 1;
		break;
	}

	codec->dapm.bias_level = level;
	return 0;
}

static int wm8991_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
	wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF);
	return 0;
}

static int wm8991_resume(struct snd_soc_codec *codec)
{
	wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	return 0;
}

/* power down chip */
static int wm8991_remove(struct snd_soc_codec *codec)
{
	wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF);
	return 0;
}

static int wm8991_probe(struct snd_soc_codec *codec)
{
	struct wm8991_priv *wm8991;
	int ret;

	wm8991 = snd_soc_codec_get_drvdata(codec);

	ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8991->control_type);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
		return ret;
	}

	ret = wm8991_reset(codec);
	if (ret < 0) {
		dev_err(codec->dev, "Failed to issue reset\n");
		return ret;
	}

	wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

	snd_soc_update_bits(codec, WM8991_AUDIO_INTERFACE_4,
			    WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);

	snd_soc_update_bits(codec, WM8991_GPIO1_GPIO2,
			    WM8991_GPIO1_SEL_MASK, 1);

	snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_1,
			    WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
			    WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);

	snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_2,
			    WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);

	snd_soc_write(codec, WM8991_DAC_CTRL, 0);
	snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
	snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));

	snd_soc_add_controls(codec, wm8991_snd_controls,
			     ARRAY_SIZE(wm8991_snd_controls));

	snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets,
				  ARRAY_SIZE(wm8991_dapm_widgets));
	snd_soc_dapm_add_routes(&codec->dapm, audio_map,
				ARRAY_SIZE(audio_map));
	return 0;
}

#define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
			SNDRV_PCM_FMTBIT_S24_LE)

static struct snd_soc_dai_ops wm8991_ops = {
	.hw_params = wm8991_hw_params,
	.digital_mute = wm8991_mute,
	.set_fmt = wm8991_set_dai_fmt,
	.set_clkdiv = wm8991_set_dai_clkdiv,
	.set_pll = wm8991_set_dai_pll
};

/*
 * The WM8991 supports 2 different and mutually exclusive DAI
 * configurations.
 *
 * 1. ADC/DAC on Primary Interface
 * 2. ADC on Primary Interface/DAC on secondary
 */
static struct snd_soc_dai_driver wm8991_dai = {
	/* ADC/DAC on primary */
	.name = "wm8991",
	.id = 1,
	.playback = {
		.stream_name = "Playback",
		.channels_min = 1,
		.channels_max = 2,
		.rates = SNDRV_PCM_RATE_8000_96000,
		.formats = WM8991_FORMATS
	},
	.capture = {
		.stream_name = "Capture",
		.channels_min = 1,
		.channels_max = 2,
		.rates = SNDRV_PCM_RATE_8000_96000,
		.formats = WM8991_FORMATS
	},
	.ops = &wm8991_ops
};

static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
	.probe = wm8991_probe,
	.remove = wm8991_remove,
	.suspend = wm8991_suspend,
	.resume = wm8991_resume,
	.set_bias_level = wm8991_set_bias_level,
	.reg_cache_size = WM8991_MAX_REGISTER + 1,
	.reg_word_size = sizeof(u16),
	.reg_cache_default = wm8991_reg_defs
};

static __devinit int wm8991_i2c_probe(struct i2c_client *i2c,
				      const struct i2c_device_id *id)
{
	struct wm8991_priv *wm8991;
	int ret;

	wm8991 = kzalloc(sizeof *wm8991, GFP_KERNEL);
	if (!wm8991)
		return -ENOMEM;

	wm8991->control_type = SND_SOC_I2C;
	i2c_set_clientdata(i2c, wm8991);

	ret = snd_soc_register_codec(&i2c->dev,
				     &soc_codec_dev_wm8991, &wm8991_dai, 1);
	if (ret < 0)
		kfree(wm8991);
	return ret;
}

static __devexit int wm8991_i2c_remove(struct i2c_client *client)
{
	snd_soc_unregister_codec(&client->dev);
	kfree(i2c_get_clientdata(client));
	return 0;
}

static const struct i2c_device_id wm8991_i2c_id[] = {
	{ "wm8991", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id);

static struct i2c_driver wm8991_i2c_driver = {
	.driver = {
		.name = "wm8991",
		.owner = THIS_MODULE,
	},
	.probe = wm8991_i2c_probe,
	.remove = __devexit_p(wm8991_i2c_remove),
	.id_table = wm8991_i2c_id,
};

static int __init wm8991_modinit(void)
{
	int ret;
	ret = i2c_add_driver(&wm8991_i2c_driver);
	if (ret != 0) {
		printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n",
		       ret);
	}
	return 0;
}
module_init(wm8991_modinit);

static void __exit wm8991_exit(void)
{
	i2c_del_driver(&wm8991_i2c_driver);
}
module_exit(wm8991_exit);

MODULE_DESCRIPTION("ASoC WM8991 driver");
MODULE_AUTHOR("Graeme Gregory");
MODULE_LICENSE("GPL");