1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2942c435bSMark Brown /*
3942c435bSMark Brown * wm8993.c -- WM8993 ALSA SoC audio driver
4942c435bSMark Brown *
5656baaebSMark Brown * Copyright 2009-12 Wolfson Microelectronics plc
6942c435bSMark Brown *
7942c435bSMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8942c435bSMark Brown */
9942c435bSMark Brown
10942c435bSMark Brown #include <linux/module.h>
11942c435bSMark Brown #include <linux/moduleparam.h>
12942c435bSMark Brown #include <linux/init.h>
13942c435bSMark Brown #include <linux/delay.h>
14942c435bSMark Brown #include <linux/pm.h>
15942c435bSMark Brown #include <linux/i2c.h>
16d0ad0af0SMark Brown #include <linux/regmap.h>
17b37e399bSMark Brown #include <linux/regulator/consumer.h>
18942c435bSMark Brown #include <linux/spi/spi.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
20942c435bSMark Brown #include <sound/core.h>
21942c435bSMark Brown #include <sound/pcm.h>
22942c435bSMark Brown #include <sound/pcm_params.h>
23942c435bSMark Brown #include <sound/tlv.h>
24942c435bSMark Brown #include <sound/soc.h>
25942c435bSMark Brown #include <sound/initval.h>
26942c435bSMark Brown #include <sound/wm8993.h>
27942c435bSMark Brown
28942c435bSMark Brown #include "wm8993.h"
29a2342ae3SMark Brown #include "wm_hubs.h"
30942c435bSMark Brown
31b37e399bSMark Brown #define WM8993_NUM_SUPPLIES 6
32b37e399bSMark Brown static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = {
33b37e399bSMark Brown "DCVDD",
34b37e399bSMark Brown "DBVDD",
35b37e399bSMark Brown "AVDD1",
36b37e399bSMark Brown "AVDD2",
37b37e399bSMark Brown "CPVDD",
38b37e399bSMark Brown "SPKVDD",
39b37e399bSMark Brown };
40b37e399bSMark Brown
41c418a84aSAxel Lin static const struct reg_default wm8993_reg_defaults[] = {
42d0ad0af0SMark Brown { 1, 0x0000 }, /* R1 - Power Management (1) */
43d0ad0af0SMark Brown { 2, 0x6000 }, /* R2 - Power Management (2) */
44d0ad0af0SMark Brown { 3, 0x0000 }, /* R3 - Power Management (3) */
45d0ad0af0SMark Brown { 4, 0x4050 }, /* R4 - Audio Interface (1) */
46d0ad0af0SMark Brown { 5, 0x4000 }, /* R5 - Audio Interface (2) */
47d0ad0af0SMark Brown { 6, 0x01C8 }, /* R6 - Clocking 1 */
48d0ad0af0SMark Brown { 7, 0x0000 }, /* R7 - Clocking 2 */
49d0ad0af0SMark Brown { 8, 0x0000 }, /* R8 - Audio Interface (3) */
50d0ad0af0SMark Brown { 9, 0x0040 }, /* R9 - Audio Interface (4) */
51d0ad0af0SMark Brown { 10, 0x0004 }, /* R10 - DAC CTRL */
52d0ad0af0SMark Brown { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */
53d0ad0af0SMark Brown { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */
54d0ad0af0SMark Brown { 13, 0x0000 }, /* R13 - Digital Side Tone */
55d0ad0af0SMark Brown { 14, 0x0300 }, /* R14 - ADC CTRL */
56d0ad0af0SMark Brown { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */
57d0ad0af0SMark Brown { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */
58d0ad0af0SMark Brown { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */
59d0ad0af0SMark Brown { 19, 0x0010 }, /* R19 - GPIO1 */
60d0ad0af0SMark Brown { 20, 0x0000 }, /* R20 - IRQ_DEBOUNCE */
61b8034229SMark Brown { 21, 0x0000 }, /* R21 - Inputs Clamp */
62e2da2677SMark Brown { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */
63e2da2677SMark Brown { 23, 0x0800 }, /* R23 - GPIO_POL */
64d0ad0af0SMark Brown { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
65d0ad0af0SMark Brown { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
66d0ad0af0SMark Brown { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
67d0ad0af0SMark Brown { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
68d0ad0af0SMark Brown { 28, 0x006D }, /* R28 - Left Output Volume */
69d0ad0af0SMark Brown { 29, 0x006D }, /* R29 - Right Output Volume */
70d0ad0af0SMark Brown { 30, 0x0066 }, /* R30 - Line Outputs Volume */
71d0ad0af0SMark Brown { 31, 0x0020 }, /* R31 - HPOUT2 Volume */
72d0ad0af0SMark Brown { 32, 0x0079 }, /* R32 - Left OPGA Volume */
73d0ad0af0SMark Brown { 33, 0x0079 }, /* R33 - Right OPGA Volume */
74d0ad0af0SMark Brown { 34, 0x0003 }, /* R34 - SPKMIXL Attenuation */
75d0ad0af0SMark Brown { 35, 0x0003 }, /* R35 - SPKMIXR Attenuation */
76d0ad0af0SMark Brown { 36, 0x0011 }, /* R36 - SPKOUT Mixers */
77d0ad0af0SMark Brown { 37, 0x0100 }, /* R37 - SPKOUT Boost */
78d0ad0af0SMark Brown { 38, 0x0079 }, /* R38 - Speaker Volume Left */
79d0ad0af0SMark Brown { 39, 0x0079 }, /* R39 - Speaker Volume Right */
80d0ad0af0SMark Brown { 40, 0x0000 }, /* R40 - Input Mixer2 */
81d0ad0af0SMark Brown { 41, 0x0000 }, /* R41 - Input Mixer3 */
82d0ad0af0SMark Brown { 42, 0x0000 }, /* R42 - Input Mixer4 */
83d0ad0af0SMark Brown { 43, 0x0000 }, /* R43 - Input Mixer5 */
84d0ad0af0SMark Brown { 44, 0x0000 }, /* R44 - Input Mixer6 */
85d0ad0af0SMark Brown { 45, 0x0000 }, /* R45 - Output Mixer1 */
86d0ad0af0SMark Brown { 46, 0x0000 }, /* R46 - Output Mixer2 */
87d0ad0af0SMark Brown { 47, 0x0000 }, /* R47 - Output Mixer3 */
88d0ad0af0SMark Brown { 48, 0x0000 }, /* R48 - Output Mixer4 */
89d0ad0af0SMark Brown { 49, 0x0000 }, /* R49 - Output Mixer5 */
90d0ad0af0SMark Brown { 50, 0x0000 }, /* R50 - Output Mixer6 */
91d0ad0af0SMark Brown { 51, 0x0000 }, /* R51 - HPOUT2 Mixer */
92d0ad0af0SMark Brown { 52, 0x0000 }, /* R52 - Line Mixer1 */
93d0ad0af0SMark Brown { 53, 0x0000 }, /* R53 - Line Mixer2 */
94d0ad0af0SMark Brown { 54, 0x0000 }, /* R54 - Speaker Mixer */
95d0ad0af0SMark Brown { 55, 0x0000 }, /* R55 - Additional Control */
96d0ad0af0SMark Brown { 56, 0x0000 }, /* R56 - AntiPOP1 */
97d0ad0af0SMark Brown { 57, 0x0000 }, /* R57 - AntiPOP2 */
98d0ad0af0SMark Brown { 58, 0x0000 }, /* R58 - MICBIAS */
99d0ad0af0SMark Brown { 60, 0x0000 }, /* R60 - FLL Control 1 */
100d0ad0af0SMark Brown { 61, 0x0000 }, /* R61 - FLL Control 2 */
101d0ad0af0SMark Brown { 62, 0x0000 }, /* R62 - FLL Control 3 */
102d0ad0af0SMark Brown { 63, 0x2EE0 }, /* R63 - FLL Control 4 */
103d0ad0af0SMark Brown { 64, 0x0002 }, /* R64 - FLL Control 5 */
104d0ad0af0SMark Brown { 65, 0x2287 }, /* R65 - Clocking 3 */
105d0ad0af0SMark Brown { 66, 0x025F }, /* R66 - Clocking 4 */
106d0ad0af0SMark Brown { 67, 0x0000 }, /* R67 - MW Slave Control */
107d0ad0af0SMark Brown { 69, 0x0002 }, /* R69 - Bus Control 1 */
108d0ad0af0SMark Brown { 70, 0x0000 }, /* R70 - Write Sequencer 0 */
109d0ad0af0SMark Brown { 71, 0x0000 }, /* R71 - Write Sequencer 1 */
110d0ad0af0SMark Brown { 72, 0x0000 }, /* R72 - Write Sequencer 2 */
111d0ad0af0SMark Brown { 73, 0x0000 }, /* R73 - Write Sequencer 3 */
112d0ad0af0SMark Brown { 74, 0x0000 }, /* R74 - Write Sequencer 4 */
113d0ad0af0SMark Brown { 75, 0x0000 }, /* R75 - Write Sequencer 5 */
114d0ad0af0SMark Brown { 76, 0x1F25 }, /* R76 - Charge Pump 1 */
115d0ad0af0SMark Brown { 81, 0x0000 }, /* R81 - Class W 0 */
116d0ad0af0SMark Brown { 85, 0x054A }, /* R85 - DC Servo 1 */
117d0ad0af0SMark Brown { 87, 0x0000 }, /* R87 - DC Servo 3 */
118d0ad0af0SMark Brown { 96, 0x0100 }, /* R96 - Analogue HP 0 */
119d0ad0af0SMark Brown { 98, 0x0000 }, /* R98 - EQ1 */
120d0ad0af0SMark Brown { 99, 0x000C }, /* R99 - EQ2 */
121d0ad0af0SMark Brown { 100, 0x000C }, /* R100 - EQ3 */
122d0ad0af0SMark Brown { 101, 0x000C }, /* R101 - EQ4 */
123d0ad0af0SMark Brown { 102, 0x000C }, /* R102 - EQ5 */
124d0ad0af0SMark Brown { 103, 0x000C }, /* R103 - EQ6 */
125d0ad0af0SMark Brown { 104, 0x0FCA }, /* R104 - EQ7 */
126d0ad0af0SMark Brown { 105, 0x0400 }, /* R105 - EQ8 */
127d0ad0af0SMark Brown { 106, 0x00D8 }, /* R106 - EQ9 */
128d0ad0af0SMark Brown { 107, 0x1EB5 }, /* R107 - EQ10 */
129d0ad0af0SMark Brown { 108, 0xF145 }, /* R108 - EQ11 */
130d0ad0af0SMark Brown { 109, 0x0B75 }, /* R109 - EQ12 */
131d0ad0af0SMark Brown { 110, 0x01C5 }, /* R110 - EQ13 */
132d0ad0af0SMark Brown { 111, 0x1C58 }, /* R111 - EQ14 */
133d0ad0af0SMark Brown { 112, 0xF373 }, /* R112 - EQ15 */
134d0ad0af0SMark Brown { 113, 0x0A54 }, /* R113 - EQ16 */
135d0ad0af0SMark Brown { 114, 0x0558 }, /* R114 - EQ17 */
136d0ad0af0SMark Brown { 115, 0x168E }, /* R115 - EQ18 */
137d0ad0af0SMark Brown { 116, 0xF829 }, /* R116 - EQ19 */
138d0ad0af0SMark Brown { 117, 0x07AD }, /* R117 - EQ20 */
139d0ad0af0SMark Brown { 118, 0x1103 }, /* R118 - EQ21 */
140d0ad0af0SMark Brown { 119, 0x0564 }, /* R119 - EQ22 */
141d0ad0af0SMark Brown { 120, 0x0559 }, /* R120 - EQ23 */
142d0ad0af0SMark Brown { 121, 0x4000 }, /* R121 - EQ24 */
143d0ad0af0SMark Brown { 122, 0x0000 }, /* R122 - Digital Pulls */
144d0ad0af0SMark Brown { 123, 0x0F08 }, /* R123 - DRC Control 1 */
145d0ad0af0SMark Brown { 124, 0x0000 }, /* R124 - DRC Control 2 */
146d0ad0af0SMark Brown { 125, 0x0080 }, /* R125 - DRC Control 3 */
147d0ad0af0SMark Brown { 126, 0x0000 }, /* R126 - DRC Control 4 */
148942c435bSMark Brown };
149942c435bSMark Brown
150942c435bSMark Brown static struct {
151942c435bSMark Brown int ratio;
152942c435bSMark Brown int clk_sys_rate;
153942c435bSMark Brown } clk_sys_rates[] = {
154942c435bSMark Brown { 64, 0 },
155942c435bSMark Brown { 128, 1 },
156942c435bSMark Brown { 192, 2 },
157942c435bSMark Brown { 256, 3 },
158942c435bSMark Brown { 384, 4 },
159942c435bSMark Brown { 512, 5 },
160942c435bSMark Brown { 768, 6 },
161942c435bSMark Brown { 1024, 7 },
162942c435bSMark Brown { 1408, 8 },
163942c435bSMark Brown { 1536, 9 },
164942c435bSMark Brown };
165942c435bSMark Brown
166942c435bSMark Brown static struct {
167942c435bSMark Brown int rate;
168942c435bSMark Brown int sample_rate;
169942c435bSMark Brown } sample_rates[] = {
170942c435bSMark Brown { 8000, 0 },
171942c435bSMark Brown { 11025, 1 },
172942c435bSMark Brown { 12000, 1 },
173942c435bSMark Brown { 16000, 2 },
174942c435bSMark Brown { 22050, 3 },
175942c435bSMark Brown { 24000, 3 },
176942c435bSMark Brown { 32000, 4 },
177942c435bSMark Brown { 44100, 5 },
178942c435bSMark Brown { 48000, 5 },
179942c435bSMark Brown };
180942c435bSMark Brown
181942c435bSMark Brown static struct {
182942c435bSMark Brown int div; /* *10 due to .5s */
183942c435bSMark Brown int bclk_div;
184942c435bSMark Brown } bclk_divs[] = {
185942c435bSMark Brown { 10, 0 },
186942c435bSMark Brown { 15, 1 },
187942c435bSMark Brown { 20, 2 },
188942c435bSMark Brown { 30, 3 },
189942c435bSMark Brown { 40, 4 },
190942c435bSMark Brown { 55, 5 },
191942c435bSMark Brown { 60, 6 },
192942c435bSMark Brown { 80, 7 },
193942c435bSMark Brown { 110, 8 },
194942c435bSMark Brown { 120, 9 },
195942c435bSMark Brown { 160, 10 },
196942c435bSMark Brown { 220, 11 },
197942c435bSMark Brown { 240, 12 },
198942c435bSMark Brown { 320, 13 },
199942c435bSMark Brown { 440, 14 },
200942c435bSMark Brown { 480, 15 },
201942c435bSMark Brown };
202942c435bSMark Brown
203942c435bSMark Brown struct wm8993_priv {
2043ed7074cSMark Brown struct wm_hubs_data hubs_data;
205164548d3SMark Brown struct device *dev;
206d0ad0af0SMark Brown struct regmap *regmap;
207b37e399bSMark Brown struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
208942c435bSMark Brown struct wm8993_platform_data pdata;
209164548d3SMark Brown struct completion fll_lock;
210942c435bSMark Brown int master;
211942c435bSMark Brown int sysclk_source;
212d3c9e9a1SMark Brown int tdm_slots;
213d3c9e9a1SMark Brown int tdm_width;
214942c435bSMark Brown unsigned int mclk_rate;
215942c435bSMark Brown unsigned int sysclk_rate;
216942c435bSMark Brown unsigned int fs;
217942c435bSMark Brown unsigned int bclk;
218942c435bSMark Brown unsigned int fll_fref;
219942c435bSMark Brown unsigned int fll_fout;
22053242c68SMark Brown int fll_src;
221942c435bSMark Brown };
222942c435bSMark Brown
wm8993_volatile(struct device * dev,unsigned int reg)223d0ad0af0SMark Brown static bool wm8993_volatile(struct device *dev, unsigned int reg)
224942c435bSMark Brown {
225942c435bSMark Brown switch (reg) {
226942c435bSMark Brown case WM8993_SOFTWARE_RESET:
227164548d3SMark Brown case WM8993_GPIO_CTRL_1:
228942c435bSMark Brown case WM8993_DC_SERVO_0:
229942c435bSMark Brown case WM8993_DC_SERVO_READBACK_0:
230942c435bSMark Brown case WM8993_DC_SERVO_READBACK_1:
231942c435bSMark Brown case WM8993_DC_SERVO_READBACK_2:
232d0ad0af0SMark Brown return true;
233942c435bSMark Brown default:
234d0ad0af0SMark Brown return false;
235d0ad0af0SMark Brown }
236d0ad0af0SMark Brown }
237d0ad0af0SMark Brown
wm8993_readable(struct device * dev,unsigned int reg)238d0ad0af0SMark Brown static bool wm8993_readable(struct device *dev, unsigned int reg)
239d0ad0af0SMark Brown {
240d0ad0af0SMark Brown switch (reg) {
241d0ad0af0SMark Brown case WM8993_SOFTWARE_RESET:
242d0ad0af0SMark Brown case WM8993_POWER_MANAGEMENT_1:
243d0ad0af0SMark Brown case WM8993_POWER_MANAGEMENT_2:
244d0ad0af0SMark Brown case WM8993_POWER_MANAGEMENT_3:
245d0ad0af0SMark Brown case WM8993_AUDIO_INTERFACE_1:
246d0ad0af0SMark Brown case WM8993_AUDIO_INTERFACE_2:
247d0ad0af0SMark Brown case WM8993_CLOCKING_1:
248d0ad0af0SMark Brown case WM8993_CLOCKING_2:
249d0ad0af0SMark Brown case WM8993_AUDIO_INTERFACE_3:
250d0ad0af0SMark Brown case WM8993_AUDIO_INTERFACE_4:
251d0ad0af0SMark Brown case WM8993_DAC_CTRL:
252d0ad0af0SMark Brown case WM8993_LEFT_DAC_DIGITAL_VOLUME:
253d0ad0af0SMark Brown case WM8993_RIGHT_DAC_DIGITAL_VOLUME:
254d0ad0af0SMark Brown case WM8993_DIGITAL_SIDE_TONE:
255d0ad0af0SMark Brown case WM8993_ADC_CTRL:
256d0ad0af0SMark Brown case WM8993_LEFT_ADC_DIGITAL_VOLUME:
257d0ad0af0SMark Brown case WM8993_RIGHT_ADC_DIGITAL_VOLUME:
258d0ad0af0SMark Brown case WM8993_GPIO_CTRL_1:
259d0ad0af0SMark Brown case WM8993_GPIO1:
260d0ad0af0SMark Brown case WM8993_IRQ_DEBOUNCE:
261d0ad0af0SMark Brown case WM8993_GPIOCTRL_2:
262d0ad0af0SMark Brown case WM8993_GPIO_POL:
263d0ad0af0SMark Brown case WM8993_LEFT_LINE_INPUT_1_2_VOLUME:
264d0ad0af0SMark Brown case WM8993_LEFT_LINE_INPUT_3_4_VOLUME:
265d0ad0af0SMark Brown case WM8993_RIGHT_LINE_INPUT_1_2_VOLUME:
266d0ad0af0SMark Brown case WM8993_RIGHT_LINE_INPUT_3_4_VOLUME:
267d0ad0af0SMark Brown case WM8993_LEFT_OUTPUT_VOLUME:
268d0ad0af0SMark Brown case WM8993_RIGHT_OUTPUT_VOLUME:
269d0ad0af0SMark Brown case WM8993_LINE_OUTPUTS_VOLUME:
270d0ad0af0SMark Brown case WM8993_HPOUT2_VOLUME:
271d0ad0af0SMark Brown case WM8993_LEFT_OPGA_VOLUME:
272d0ad0af0SMark Brown case WM8993_RIGHT_OPGA_VOLUME:
273d0ad0af0SMark Brown case WM8993_SPKMIXL_ATTENUATION:
274d0ad0af0SMark Brown case WM8993_SPKMIXR_ATTENUATION:
275d0ad0af0SMark Brown case WM8993_SPKOUT_MIXERS:
276d0ad0af0SMark Brown case WM8993_SPKOUT_BOOST:
277d0ad0af0SMark Brown case WM8993_SPEAKER_VOLUME_LEFT:
278d0ad0af0SMark Brown case WM8993_SPEAKER_VOLUME_RIGHT:
279d0ad0af0SMark Brown case WM8993_INPUT_MIXER2:
280d0ad0af0SMark Brown case WM8993_INPUT_MIXER3:
281d0ad0af0SMark Brown case WM8993_INPUT_MIXER4:
282d0ad0af0SMark Brown case WM8993_INPUT_MIXER5:
283d0ad0af0SMark Brown case WM8993_INPUT_MIXER6:
284d0ad0af0SMark Brown case WM8993_OUTPUT_MIXER1:
285d0ad0af0SMark Brown case WM8993_OUTPUT_MIXER2:
286d0ad0af0SMark Brown case WM8993_OUTPUT_MIXER3:
287d0ad0af0SMark Brown case WM8993_OUTPUT_MIXER4:
288d0ad0af0SMark Brown case WM8993_OUTPUT_MIXER5:
289d0ad0af0SMark Brown case WM8993_OUTPUT_MIXER6:
290d0ad0af0SMark Brown case WM8993_HPOUT2_MIXER:
291d0ad0af0SMark Brown case WM8993_LINE_MIXER1:
292d0ad0af0SMark Brown case WM8993_LINE_MIXER2:
293d0ad0af0SMark Brown case WM8993_SPEAKER_MIXER:
294d0ad0af0SMark Brown case WM8993_ADDITIONAL_CONTROL:
295d0ad0af0SMark Brown case WM8993_ANTIPOP1:
296d0ad0af0SMark Brown case WM8993_ANTIPOP2:
297d0ad0af0SMark Brown case WM8993_MICBIAS:
298d0ad0af0SMark Brown case WM8993_FLL_CONTROL_1:
299d0ad0af0SMark Brown case WM8993_FLL_CONTROL_2:
300d0ad0af0SMark Brown case WM8993_FLL_CONTROL_3:
301d0ad0af0SMark Brown case WM8993_FLL_CONTROL_4:
302d0ad0af0SMark Brown case WM8993_FLL_CONTROL_5:
303d0ad0af0SMark Brown case WM8993_CLOCKING_3:
304d0ad0af0SMark Brown case WM8993_CLOCKING_4:
305d0ad0af0SMark Brown case WM8993_MW_SLAVE_CONTROL:
306d0ad0af0SMark Brown case WM8993_BUS_CONTROL_1:
307d0ad0af0SMark Brown case WM8993_WRITE_SEQUENCER_0:
308d0ad0af0SMark Brown case WM8993_WRITE_SEQUENCER_1:
309d0ad0af0SMark Brown case WM8993_WRITE_SEQUENCER_2:
310d0ad0af0SMark Brown case WM8993_WRITE_SEQUENCER_3:
311d0ad0af0SMark Brown case WM8993_WRITE_SEQUENCER_4:
312d0ad0af0SMark Brown case WM8993_WRITE_SEQUENCER_5:
313d0ad0af0SMark Brown case WM8993_CHARGE_PUMP_1:
314d0ad0af0SMark Brown case WM8993_CLASS_W_0:
315d0ad0af0SMark Brown case WM8993_DC_SERVO_0:
316d0ad0af0SMark Brown case WM8993_DC_SERVO_1:
317d0ad0af0SMark Brown case WM8993_DC_SERVO_3:
318d0ad0af0SMark Brown case WM8993_DC_SERVO_READBACK_0:
319d0ad0af0SMark Brown case WM8993_DC_SERVO_READBACK_1:
320d0ad0af0SMark Brown case WM8993_DC_SERVO_READBACK_2:
321d0ad0af0SMark Brown case WM8993_ANALOGUE_HP_0:
322d0ad0af0SMark Brown case WM8993_EQ1:
323d0ad0af0SMark Brown case WM8993_EQ2:
324d0ad0af0SMark Brown case WM8993_EQ3:
325d0ad0af0SMark Brown case WM8993_EQ4:
326d0ad0af0SMark Brown case WM8993_EQ5:
327d0ad0af0SMark Brown case WM8993_EQ6:
328d0ad0af0SMark Brown case WM8993_EQ7:
329d0ad0af0SMark Brown case WM8993_EQ8:
330d0ad0af0SMark Brown case WM8993_EQ9:
331d0ad0af0SMark Brown case WM8993_EQ10:
332d0ad0af0SMark Brown case WM8993_EQ11:
333d0ad0af0SMark Brown case WM8993_EQ12:
334d0ad0af0SMark Brown case WM8993_EQ13:
335d0ad0af0SMark Brown case WM8993_EQ14:
336d0ad0af0SMark Brown case WM8993_EQ15:
337d0ad0af0SMark Brown case WM8993_EQ16:
338d0ad0af0SMark Brown case WM8993_EQ17:
339d0ad0af0SMark Brown case WM8993_EQ18:
340d0ad0af0SMark Brown case WM8993_EQ19:
341d0ad0af0SMark Brown case WM8993_EQ20:
342d0ad0af0SMark Brown case WM8993_EQ21:
343d0ad0af0SMark Brown case WM8993_EQ22:
344d0ad0af0SMark Brown case WM8993_EQ23:
345d0ad0af0SMark Brown case WM8993_EQ24:
346d0ad0af0SMark Brown case WM8993_DIGITAL_PULLS:
347d0ad0af0SMark Brown case WM8993_DRC_CONTROL_1:
348d0ad0af0SMark Brown case WM8993_DRC_CONTROL_2:
349d0ad0af0SMark Brown case WM8993_DRC_CONTROL_3:
350d0ad0af0SMark Brown case WM8993_DRC_CONTROL_4:
351d0ad0af0SMark Brown return true;
352d0ad0af0SMark Brown default:
353d0ad0af0SMark Brown return false;
354942c435bSMark Brown }
355942c435bSMark Brown }
356942c435bSMark Brown
357942c435bSMark Brown struct _fll_div {
358942c435bSMark Brown u16 fll_fratio;
359942c435bSMark Brown u16 fll_outdiv;
360942c435bSMark Brown u16 fll_clk_ref_div;
361942c435bSMark Brown u16 n;
362942c435bSMark Brown u16 k;
363942c435bSMark Brown };
364942c435bSMark Brown
365942c435bSMark Brown /* The size in bits of the FLL divide multiplied by 10
366942c435bSMark Brown * to allow rounding later */
367942c435bSMark Brown #define FIXED_FLL_SIZE ((1 << 16) * 10)
368942c435bSMark Brown
369942c435bSMark Brown static struct {
370942c435bSMark Brown unsigned int min;
371942c435bSMark Brown unsigned int max;
372942c435bSMark Brown u16 fll_fratio;
373942c435bSMark Brown int ratio;
374942c435bSMark Brown } fll_fratios[] = {
375942c435bSMark Brown { 0, 64000, 4, 16 },
376942c435bSMark Brown { 64000, 128000, 3, 8 },
377942c435bSMark Brown { 128000, 256000, 2, 4 },
378942c435bSMark Brown { 256000, 1000000, 1, 2 },
379942c435bSMark Brown { 1000000, 13500000, 0, 1 },
380942c435bSMark Brown };
381942c435bSMark Brown
fll_factors(struct _fll_div * fll_div,unsigned int Fref,unsigned int Fout)382942c435bSMark Brown static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
383942c435bSMark Brown unsigned int Fout)
384942c435bSMark Brown {
385942c435bSMark Brown u64 Kpart;
386942c435bSMark Brown unsigned int K, Ndiv, Nmod, target;
387942c435bSMark Brown unsigned int div;
388942c435bSMark Brown int i;
389942c435bSMark Brown
390942c435bSMark Brown /* Fref must be <=13.5MHz */
391942c435bSMark Brown div = 1;
3920c11f655SMark Brown fll_div->fll_clk_ref_div = 0;
393942c435bSMark Brown while ((Fref / div) > 13500000) {
394942c435bSMark Brown div *= 2;
3950c11f655SMark Brown fll_div->fll_clk_ref_div++;
396942c435bSMark Brown
397942c435bSMark Brown if (div > 8) {
398942c435bSMark Brown pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
399942c435bSMark Brown Fref);
400942c435bSMark Brown return -EINVAL;
401942c435bSMark Brown }
402942c435bSMark Brown }
403942c435bSMark Brown
404942c435bSMark Brown pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
405942c435bSMark Brown
406942c435bSMark Brown /* Apply the division for our remaining calculations */
407942c435bSMark Brown Fref /= div;
408942c435bSMark Brown
409942c435bSMark Brown /* Fvco should be 90-100MHz; don't check the upper bound */
410942c435bSMark Brown div = 0;
411942c435bSMark Brown target = Fout * 2;
412942c435bSMark Brown while (target < 90000000) {
413942c435bSMark Brown div++;
414942c435bSMark Brown target *= 2;
415942c435bSMark Brown if (div > 7) {
416942c435bSMark Brown pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
417942c435bSMark Brown Fout);
418942c435bSMark Brown return -EINVAL;
419942c435bSMark Brown }
420942c435bSMark Brown }
421942c435bSMark Brown fll_div->fll_outdiv = div;
422942c435bSMark Brown
423942c435bSMark Brown pr_debug("Fvco=%dHz\n", target);
424942c435bSMark Brown
42525985edcSLucas De Marchi /* Find an appropriate FLL_FRATIO and factor it out of the target */
426942c435bSMark Brown for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
427942c435bSMark Brown if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
428942c435bSMark Brown fll_div->fll_fratio = fll_fratios[i].fll_fratio;
429942c435bSMark Brown target /= fll_fratios[i].ratio;
430942c435bSMark Brown break;
431942c435bSMark Brown }
432942c435bSMark Brown }
433942c435bSMark Brown if (i == ARRAY_SIZE(fll_fratios)) {
434942c435bSMark Brown pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
435942c435bSMark Brown return -EINVAL;
436942c435bSMark Brown }
437942c435bSMark Brown
438942c435bSMark Brown /* Now, calculate N.K */
439942c435bSMark Brown Ndiv = target / Fref;
440942c435bSMark Brown
441942c435bSMark Brown fll_div->n = Ndiv;
442942c435bSMark Brown Nmod = target % Fref;
443942c435bSMark Brown pr_debug("Nmod=%d\n", Nmod);
444942c435bSMark Brown
445942c435bSMark Brown /* Calculate fractional part - scale up so we can round. */
446942c435bSMark Brown Kpart = FIXED_FLL_SIZE * (long long)Nmod;
447942c435bSMark Brown
448942c435bSMark Brown do_div(Kpart, Fref);
449942c435bSMark Brown
450942c435bSMark Brown K = Kpart & 0xFFFFFFFF;
451942c435bSMark Brown
452942c435bSMark Brown if ((K % 10) >= 5)
453942c435bSMark Brown K += 5;
454942c435bSMark Brown
455942c435bSMark Brown /* Move down to proper range now rounding is done */
456942c435bSMark Brown fll_div->k = K / 10;
457942c435bSMark Brown
458942c435bSMark Brown pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
459942c435bSMark Brown fll_div->n, fll_div->k,
460942c435bSMark Brown fll_div->fll_fratio, fll_div->fll_outdiv,
461942c435bSMark Brown fll_div->fll_clk_ref_div);
462942c435bSMark Brown
463942c435bSMark Brown return 0;
464942c435bSMark Brown }
465942c435bSMark Brown
_wm8993_set_fll(struct snd_soc_component * component,int fll_id,int source,unsigned int Fref,unsigned int Fout)46600a6941cSKuninori Morimoto static int _wm8993_set_fll(struct snd_soc_component *component, int fll_id, int source,
467942c435bSMark Brown unsigned int Fref, unsigned int Fout)
468942c435bSMark Brown {
46900a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
47000a6941cSKuninori Morimoto struct i2c_client *i2c = to_i2c_client(component->dev);
471942c435bSMark Brown u16 reg1, reg4, reg5;
472942c435bSMark Brown struct _fll_div fll_div;
473164548d3SMark Brown unsigned int timeout;
474942c435bSMark Brown int ret;
475942c435bSMark Brown
476942c435bSMark Brown /* Any change? */
477942c435bSMark Brown if (Fref == wm8993->fll_fref && Fout == wm8993->fll_fout)
478942c435bSMark Brown return 0;
479942c435bSMark Brown
480942c435bSMark Brown /* Disable the FLL */
481942c435bSMark Brown if (Fout == 0) {
48200a6941cSKuninori Morimoto dev_dbg(component->dev, "FLL disabled\n");
483942c435bSMark Brown wm8993->fll_fref = 0;
484942c435bSMark Brown wm8993->fll_fout = 0;
485942c435bSMark Brown
4866d75dfc3SKuninori Morimoto reg1 = snd_soc_component_read(component, WM8993_FLL_CONTROL_1);
487942c435bSMark Brown reg1 &= ~WM8993_FLL_ENA;
48800a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
489942c435bSMark Brown
490942c435bSMark Brown return 0;
491942c435bSMark Brown }
492942c435bSMark Brown
493942c435bSMark Brown ret = fll_factors(&fll_div, Fref, Fout);
494942c435bSMark Brown if (ret != 0)
495942c435bSMark Brown return ret;
496942c435bSMark Brown
4976d75dfc3SKuninori Morimoto reg5 = snd_soc_component_read(component, WM8993_FLL_CONTROL_5);
498942c435bSMark Brown reg5 &= ~WM8993_FLL_CLK_SRC_MASK;
499942c435bSMark Brown
500942c435bSMark Brown switch (fll_id) {
501942c435bSMark Brown case WM8993_FLL_MCLK:
502942c435bSMark Brown break;
503942c435bSMark Brown
504942c435bSMark Brown case WM8993_FLL_LRCLK:
505942c435bSMark Brown reg5 |= 1;
506942c435bSMark Brown break;
507942c435bSMark Brown
508942c435bSMark Brown case WM8993_FLL_BCLK:
509942c435bSMark Brown reg5 |= 2;
510942c435bSMark Brown break;
511942c435bSMark Brown
512942c435bSMark Brown default:
51300a6941cSKuninori Morimoto dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
514942c435bSMark Brown return -EINVAL;
515942c435bSMark Brown }
516942c435bSMark Brown
517942c435bSMark Brown /* Any FLL configuration change requires that the FLL be
518942c435bSMark Brown * disabled first. */
5196d75dfc3SKuninori Morimoto reg1 = snd_soc_component_read(component, WM8993_FLL_CONTROL_1);
520942c435bSMark Brown reg1 &= ~WM8993_FLL_ENA;
52100a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
522942c435bSMark Brown
523942c435bSMark Brown /* Apply the configuration */
524942c435bSMark Brown if (fll_div.k)
525942c435bSMark Brown reg1 |= WM8993_FLL_FRAC_MASK;
526942c435bSMark Brown else
527942c435bSMark Brown reg1 &= ~WM8993_FLL_FRAC_MASK;
52800a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1);
529942c435bSMark Brown
53000a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_2,
531942c435bSMark Brown (fll_div.fll_outdiv << WM8993_FLL_OUTDIV_SHIFT) |
532942c435bSMark Brown (fll_div.fll_fratio << WM8993_FLL_FRATIO_SHIFT));
53300a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_3, fll_div.k);
534942c435bSMark Brown
5356d75dfc3SKuninori Morimoto reg4 = snd_soc_component_read(component, WM8993_FLL_CONTROL_4);
536942c435bSMark Brown reg4 &= ~WM8993_FLL_N_MASK;
537942c435bSMark Brown reg4 |= fll_div.n << WM8993_FLL_N_SHIFT;
53800a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_4, reg4);
539942c435bSMark Brown
540942c435bSMark Brown reg5 &= ~WM8993_FLL_CLK_REF_DIV_MASK;
541942c435bSMark Brown reg5 |= fll_div.fll_clk_ref_div << WM8993_FLL_CLK_REF_DIV_SHIFT;
54200a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_5, reg5);
543942c435bSMark Brown
544164548d3SMark Brown /* If we've got an interrupt wired up make sure we get it */
545164548d3SMark Brown if (i2c->irq)
546164548d3SMark Brown timeout = msecs_to_jiffies(20);
547164548d3SMark Brown else if (Fref < 1000000)
548164548d3SMark Brown timeout = msecs_to_jiffies(3);
549164548d3SMark Brown else
550164548d3SMark Brown timeout = msecs_to_jiffies(1);
551164548d3SMark Brown
552164548d3SMark Brown try_wait_for_completion(&wm8993->fll_lock);
553164548d3SMark Brown
554942c435bSMark Brown /* Enable the FLL */
55500a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_FLL_CONTROL_1, reg1 | WM8993_FLL_ENA);
556942c435bSMark Brown
557164548d3SMark Brown timeout = wait_for_completion_timeout(&wm8993->fll_lock, timeout);
558164548d3SMark Brown if (i2c->irq && !timeout)
55900a6941cSKuninori Morimoto dev_warn(component->dev, "Timed out waiting for FLL\n");
560986b2f2cSMark Brown
56100a6941cSKuninori Morimoto dev_dbg(component->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
562942c435bSMark Brown
563942c435bSMark Brown wm8993->fll_fref = Fref;
564942c435bSMark Brown wm8993->fll_fout = Fout;
56553242c68SMark Brown wm8993->fll_src = source;
566942c435bSMark Brown
567942c435bSMark Brown return 0;
568942c435bSMark Brown }
569942c435bSMark Brown
wm8993_set_fll(struct snd_soc_dai * dai,int fll_id,int source,unsigned int Fref,unsigned int Fout)570f0fba2adSLiam Girdwood static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
571f0fba2adSLiam Girdwood unsigned int Fref, unsigned int Fout)
572f0fba2adSLiam Girdwood {
57300a6941cSKuninori Morimoto return _wm8993_set_fll(dai->component, fll_id, source, Fref, Fout);
574f0fba2adSLiam Girdwood }
575f0fba2adSLiam Girdwood
configure_clock(struct snd_soc_component * component)57600a6941cSKuninori Morimoto static int configure_clock(struct snd_soc_component *component)
577942c435bSMark Brown {
57800a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
579942c435bSMark Brown unsigned int reg;
580942c435bSMark Brown
581942c435bSMark Brown /* This should be done on init() for bypass paths */
582942c435bSMark Brown switch (wm8993->sysclk_source) {
583942c435bSMark Brown case WM8993_SYSCLK_MCLK:
58400a6941cSKuninori Morimoto dev_dbg(component->dev, "Using %dHz MCLK\n", wm8993->mclk_rate);
585942c435bSMark Brown
5866d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8993_CLOCKING_2);
5870182dcc5SMark Brown reg &= ~(WM8993_MCLK_DIV | WM8993_SYSCLK_SRC);
588942c435bSMark Brown if (wm8993->mclk_rate > 13500000) {
589942c435bSMark Brown reg |= WM8993_MCLK_DIV;
590942c435bSMark Brown wm8993->sysclk_rate = wm8993->mclk_rate / 2;
591942c435bSMark Brown } else {
592942c435bSMark Brown reg &= ~WM8993_MCLK_DIV;
593942c435bSMark Brown wm8993->sysclk_rate = wm8993->mclk_rate;
594942c435bSMark Brown }
59500a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_CLOCKING_2, reg);
596942c435bSMark Brown break;
597942c435bSMark Brown
598942c435bSMark Brown case WM8993_SYSCLK_FLL:
59900a6941cSKuninori Morimoto dev_dbg(component->dev, "Using %dHz FLL clock\n",
600942c435bSMark Brown wm8993->fll_fout);
601942c435bSMark Brown
6026d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8993_CLOCKING_2);
603942c435bSMark Brown reg |= WM8993_SYSCLK_SRC;
604942c435bSMark Brown if (wm8993->fll_fout > 13500000) {
605942c435bSMark Brown reg |= WM8993_MCLK_DIV;
606942c435bSMark Brown wm8993->sysclk_rate = wm8993->fll_fout / 2;
607942c435bSMark Brown } else {
608942c435bSMark Brown reg &= ~WM8993_MCLK_DIV;
609942c435bSMark Brown wm8993->sysclk_rate = wm8993->fll_fout;
610942c435bSMark Brown }
61100a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_CLOCKING_2, reg);
612942c435bSMark Brown break;
613942c435bSMark Brown
614942c435bSMark Brown default:
61500a6941cSKuninori Morimoto dev_err(component->dev, "System clock not configured\n");
616942c435bSMark Brown return -EINVAL;
617942c435bSMark Brown }
618942c435bSMark Brown
61900a6941cSKuninori Morimoto dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm8993->sysclk_rate);
620942c435bSMark Brown
621942c435bSMark Brown return 0;
622942c435bSMark Brown }
623942c435bSMark Brown
624942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
625942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(drc_comp_threash, -4500, 75, 0);
626942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(drc_comp_amp, -2250, 75, 0);
627942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
628f1022087SLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(drc_max_tlv,
629942c435bSMark Brown 0, 2, TLV_DB_SCALE_ITEM(1200, 600, 0),
630f1022087SLars-Peter Clausen 3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0)
631f1022087SLars-Peter Clausen );
632942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
633942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -1800, 300, 0);
634942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
635942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
636942c435bSMark Brown static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
637942c435bSMark Brown
638942c435bSMark Brown static const char *dac_deemph_text[] = {
639942c435bSMark Brown "None",
640942c435bSMark Brown "32kHz",
641942c435bSMark Brown "44.1kHz",
642942c435bSMark Brown "48kHz",
643942c435bSMark Brown };
644942c435bSMark Brown
6452d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(dac_deemph,
6462d075611STakashi Iwai WM8993_DAC_CTRL, 4, dac_deemph_text);
647942c435bSMark Brown
648942c435bSMark Brown static const char *adc_hpf_text[] = {
649942c435bSMark Brown "Hi-Fi",
650942c435bSMark Brown "Voice 1",
651942c435bSMark Brown "Voice 2",
652942c435bSMark Brown "Voice 3",
653942c435bSMark Brown };
654942c435bSMark Brown
6552d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(adc_hpf,
6562d075611STakashi Iwai WM8993_ADC_CTRL, 5, adc_hpf_text);
657942c435bSMark Brown
658942c435bSMark Brown static const char *drc_path_text[] = {
659942c435bSMark Brown "ADC",
660942c435bSMark Brown "DAC"
661942c435bSMark Brown };
662942c435bSMark Brown
6632d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_path,
6642d075611STakashi Iwai WM8993_DRC_CONTROL_1, 14, drc_path_text);
665942c435bSMark Brown
666942c435bSMark Brown static const char *drc_r0_text[] = {
667942c435bSMark Brown "1",
668942c435bSMark Brown "1/2",
669942c435bSMark Brown "1/4",
670942c435bSMark Brown "1/8",
671942c435bSMark Brown "1/16",
672942c435bSMark Brown "0",
673942c435bSMark Brown };
674942c435bSMark Brown
6752d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_r0,
6762d075611STakashi Iwai WM8993_DRC_CONTROL_3, 8, drc_r0_text);
677942c435bSMark Brown
678942c435bSMark Brown static const char *drc_r1_text[] = {
679942c435bSMark Brown "1",
680942c435bSMark Brown "1/2",
681942c435bSMark Brown "1/4",
682942c435bSMark Brown "1/8",
683942c435bSMark Brown "0",
684942c435bSMark Brown };
685942c435bSMark Brown
6862d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_r1,
6872d075611STakashi Iwai WM8993_DRC_CONTROL_4, 13, drc_r1_text);
688942c435bSMark Brown
689942c435bSMark Brown static const char *drc_attack_text[] = {
690942c435bSMark Brown "Reserved",
691942c435bSMark Brown "181us",
692942c435bSMark Brown "363us",
693942c435bSMark Brown "726us",
694942c435bSMark Brown "1.45ms",
695942c435bSMark Brown "2.9ms",
696942c435bSMark Brown "5.8ms",
697942c435bSMark Brown "11.6ms",
698942c435bSMark Brown "23.2ms",
699942c435bSMark Brown "46.4ms",
700942c435bSMark Brown "92.8ms",
701942c435bSMark Brown "185.6ms",
702942c435bSMark Brown };
703942c435bSMark Brown
7042d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_attack,
7052d075611STakashi Iwai WM8993_DRC_CONTROL_2, 12, drc_attack_text);
706942c435bSMark Brown
707942c435bSMark Brown static const char *drc_decay_text[] = {
708942c435bSMark Brown "186ms",
709942c435bSMark Brown "372ms",
710942c435bSMark Brown "743ms",
711942c435bSMark Brown "1.49s",
712942c435bSMark Brown "2.97ms",
713942c435bSMark Brown "5.94ms",
714942c435bSMark Brown "11.89ms",
715942c435bSMark Brown "23.78ms",
716942c435bSMark Brown "47.56ms",
717942c435bSMark Brown };
718942c435bSMark Brown
7192d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_decay,
7202d075611STakashi Iwai WM8993_DRC_CONTROL_2, 8, drc_decay_text);
721942c435bSMark Brown
722942c435bSMark Brown static const char *drc_ff_text[] = {
723942c435bSMark Brown "5 samples",
724942c435bSMark Brown "9 samples",
725942c435bSMark Brown };
726942c435bSMark Brown
7272d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_ff,
7282d075611STakashi Iwai WM8993_DRC_CONTROL_3, 7, drc_ff_text);
729942c435bSMark Brown
730942c435bSMark Brown static const char *drc_qr_rate_text[] = {
731942c435bSMark Brown "0.725ms",
732942c435bSMark Brown "1.45ms",
733942c435bSMark Brown "5.8ms",
734942c435bSMark Brown };
735942c435bSMark Brown
7362d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_qr_rate,
7372d075611STakashi Iwai WM8993_DRC_CONTROL_3, 0, drc_qr_rate_text);
738942c435bSMark Brown
739942c435bSMark Brown static const char *drc_smooth_text[] = {
740942c435bSMark Brown "Low",
741942c435bSMark Brown "Medium",
742942c435bSMark Brown "High",
743942c435bSMark Brown };
744942c435bSMark Brown
7452d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_smooth,
7462d075611STakashi Iwai WM8993_DRC_CONTROL_1, 4, drc_smooth_text);
747942c435bSMark Brown
748942c435bSMark Brown static const struct snd_kcontrol_new wm8993_snd_controls[] = {
749942c435bSMark Brown SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE,
750942c435bSMark Brown 5, 9, 12, 0, sidetone_tlv),
751942c435bSMark Brown
752942c435bSMark Brown SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0),
753942c435bSMark Brown SOC_ENUM("DRC Path", drc_path),
754af901ca1SAndré Goddard Rosa SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8993_DRC_CONTROL_2,
755942c435bSMark Brown 2, 60, 1, drc_comp_threash),
756942c435bSMark Brown SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3,
757942c435bSMark Brown 11, 30, 1, drc_comp_amp),
758942c435bSMark Brown SOC_ENUM("DRC R0", drc_r0),
759942c435bSMark Brown SOC_ENUM("DRC R1", drc_r1),
760942c435bSMark Brown SOC_SINGLE_TLV("DRC Minimum Volume", WM8993_DRC_CONTROL_1, 2, 3, 1,
761942c435bSMark Brown drc_min_tlv),
762942c435bSMark Brown SOC_SINGLE_TLV("DRC Maximum Volume", WM8993_DRC_CONTROL_1, 0, 3, 0,
763942c435bSMark Brown drc_max_tlv),
764942c435bSMark Brown SOC_ENUM("DRC Attack Rate", drc_attack),
765942c435bSMark Brown SOC_ENUM("DRC Decay Rate", drc_decay),
766942c435bSMark Brown SOC_ENUM("DRC FF Delay", drc_ff),
767942c435bSMark Brown SOC_SINGLE("DRC Anti-clip Switch", WM8993_DRC_CONTROL_1, 9, 1, 0),
768942c435bSMark Brown SOC_SINGLE("DRC Quick Release Switch", WM8993_DRC_CONTROL_1, 10, 1, 0),
769942c435bSMark Brown SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0,
770942c435bSMark Brown drc_qr_tlv),
771942c435bSMark Brown SOC_ENUM("DRC Quick Release Rate", drc_qr_rate),
772942c435bSMark Brown SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0),
773942c435bSMark Brown SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0),
774af901ca1SAndré Goddard Rosa SOC_ENUM("DRC Smoothing Hysteresis Threshold", drc_smooth),
775942c435bSMark Brown SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0,
776942c435bSMark Brown drc_startup_tlv),
777942c435bSMark Brown
778942c435bSMark Brown SOC_SINGLE("EQ Switch", WM8993_EQ1, 0, 1, 0),
779942c435bSMark Brown
780942c435bSMark Brown SOC_DOUBLE_R_TLV("Capture Volume", WM8993_LEFT_ADC_DIGITAL_VOLUME,
781942c435bSMark Brown WM8993_RIGHT_ADC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
782942c435bSMark Brown SOC_SINGLE("ADC High Pass Filter Switch", WM8993_ADC_CTRL, 8, 1, 0),
783942c435bSMark Brown SOC_ENUM("ADC High Pass Filter Mode", adc_hpf),
784942c435bSMark Brown
785942c435bSMark Brown SOC_DOUBLE_R_TLV("Playback Volume", WM8993_LEFT_DAC_DIGITAL_VOLUME,
786942c435bSMark Brown WM8993_RIGHT_DAC_DIGITAL_VOLUME, 1, 96, 0, digital_tlv),
787942c435bSMark Brown SOC_SINGLE_TLV("Playback Boost Volume", WM8993_AUDIO_INTERFACE_2, 10, 3, 0,
788942c435bSMark Brown dac_boost_tlv),
789942c435bSMark Brown SOC_ENUM("DAC Deemphasis", dac_deemph),
790942c435bSMark Brown
791942c435bSMark Brown SOC_SINGLE_TLV("SPKL DAC Volume", WM8993_SPKMIXL_ATTENUATION,
792a2342ae3SMark Brown 2, 1, 1, wm_hubs_spkmix_tlv),
793942c435bSMark Brown
794942c435bSMark Brown SOC_SINGLE_TLV("SPKR DAC Volume", WM8993_SPKMIXR_ATTENUATION,
795a2342ae3SMark Brown 2, 1, 1, wm_hubs_spkmix_tlv),
796942c435bSMark Brown };
797942c435bSMark Brown
798942c435bSMark Brown static const struct snd_kcontrol_new wm8993_eq_controls[] = {
799942c435bSMark Brown SOC_SINGLE_TLV("EQ1 Volume", WM8993_EQ2, 0, 24, 0, eq_tlv),
800942c435bSMark Brown SOC_SINGLE_TLV("EQ2 Volume", WM8993_EQ3, 0, 24, 0, eq_tlv),
801942c435bSMark Brown SOC_SINGLE_TLV("EQ3 Volume", WM8993_EQ4, 0, 24, 0, eq_tlv),
802942c435bSMark Brown SOC_SINGLE_TLV("EQ4 Volume", WM8993_EQ5, 0, 24, 0, eq_tlv),
803942c435bSMark Brown SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
804942c435bSMark Brown };
805942c435bSMark Brown
clk_sys_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)806942c435bSMark Brown static int clk_sys_event(struct snd_soc_dapm_widget *w,
807942c435bSMark Brown struct snd_kcontrol *kcontrol, int event)
808942c435bSMark Brown {
80900a6941cSKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
810942c435bSMark Brown
811942c435bSMark Brown switch (event) {
812942c435bSMark Brown case SND_SOC_DAPM_PRE_PMU:
81300a6941cSKuninori Morimoto return configure_clock(component);
814942c435bSMark Brown
815942c435bSMark Brown case SND_SOC_DAPM_POST_PMD:
816942c435bSMark Brown break;
817942c435bSMark Brown }
818942c435bSMark Brown
819942c435bSMark Brown return 0;
820942c435bSMark Brown }
821942c435bSMark Brown
822a2342ae3SMark Brown static const struct snd_kcontrol_new left_speaker_mixer[] = {
823a2342ae3SMark Brown SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0),
824a2342ae3SMark Brown SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0),
825a2342ae3SMark Brown SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 3, 1, 0),
826a2342ae3SMark Brown SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
827942c435bSMark Brown };
828942c435bSMark Brown
829a2342ae3SMark Brown static const struct snd_kcontrol_new right_speaker_mixer[] = {
830a2342ae3SMark Brown SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 6, 1, 0),
831a2342ae3SMark Brown SOC_DAPM_SINGLE("IN1RP Switch", WM8993_SPEAKER_MIXER, 4, 1, 0),
832a2342ae3SMark Brown SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0),
833a2342ae3SMark Brown SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0),
834942c435bSMark Brown };
835942c435bSMark Brown
83659ae07a5SMark Brown static const char *aif_text[] = {
83759ae07a5SMark Brown "Left", "Right"
83859ae07a5SMark Brown };
83959ae07a5SMark Brown
8402d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(aifoutl_enum,
8412d075611STakashi Iwai WM8993_AUDIO_INTERFACE_1, 15, aif_text);
84259ae07a5SMark Brown
84359ae07a5SMark Brown static const struct snd_kcontrol_new aifoutl_mux =
84459ae07a5SMark Brown SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
84559ae07a5SMark Brown
8462d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(aifoutr_enum,
8472d075611STakashi Iwai WM8993_AUDIO_INTERFACE_1, 14, aif_text);
84859ae07a5SMark Brown
84959ae07a5SMark Brown static const struct snd_kcontrol_new aifoutr_mux =
85059ae07a5SMark Brown SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
85159ae07a5SMark Brown
8522d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(aifinl_enum,
8532d075611STakashi Iwai WM8993_AUDIO_INTERFACE_2, 15, aif_text);
85459ae07a5SMark Brown
85559ae07a5SMark Brown static const struct snd_kcontrol_new aifinl_mux =
85659ae07a5SMark Brown SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
85759ae07a5SMark Brown
8582d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(aifinr_enum,
8592d075611STakashi Iwai WM8993_AUDIO_INTERFACE_2, 14, aif_text);
86059ae07a5SMark Brown
86159ae07a5SMark Brown static const struct snd_kcontrol_new aifinr_mux =
86259ae07a5SMark Brown SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
86359ae07a5SMark Brown
86459ae07a5SMark Brown static const char *sidetone_text[] = {
86559ae07a5SMark Brown "None", "Left", "Right"
86659ae07a5SMark Brown };
86759ae07a5SMark Brown
8682d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(sidetonel_enum,
8692d075611STakashi Iwai WM8993_DIGITAL_SIDE_TONE, 2, sidetone_text);
87059ae07a5SMark Brown
87159ae07a5SMark Brown static const struct snd_kcontrol_new sidetonel_mux =
87259ae07a5SMark Brown SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum);
87359ae07a5SMark Brown
8742d075611STakashi Iwai static SOC_ENUM_SINGLE_DECL(sidetoner_enum,
8752d075611STakashi Iwai WM8993_DIGITAL_SIDE_TONE, 0, sidetone_text);
87659ae07a5SMark Brown
87759ae07a5SMark Brown static const struct snd_kcontrol_new sidetoner_mux =
87859ae07a5SMark Brown SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum);
87959ae07a5SMark Brown
880942c435bSMark Brown static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = {
881942c435bSMark Brown SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event,
882942c435bSMark Brown SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
883942c435bSMark Brown SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0),
884942c435bSMark Brown SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0),
8854e04adafSMark Brown SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, NULL, 0),
886942c435bSMark Brown
88759ae07a5SMark Brown SND_SOC_DAPM_ADC("ADCL", NULL, WM8993_POWER_MANAGEMENT_2, 1, 0),
88859ae07a5SMark Brown SND_SOC_DAPM_ADC("ADCR", NULL, WM8993_POWER_MANAGEMENT_2, 0, 0),
889942c435bSMark Brown
89059ae07a5SMark Brown SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux),
89159ae07a5SMark Brown SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux),
892942c435bSMark Brown
89359ae07a5SMark Brown SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
89459ae07a5SMark Brown SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
89559ae07a5SMark Brown
89659ae07a5SMark Brown SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
89759ae07a5SMark Brown SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
89859ae07a5SMark Brown
89959ae07a5SMark Brown SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux),
90059ae07a5SMark Brown SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux),
90159ae07a5SMark Brown
90259ae07a5SMark Brown SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &sidetonel_mux),
90359ae07a5SMark Brown SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &sidetoner_mux),
90459ae07a5SMark Brown
90559ae07a5SMark Brown SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0),
90659ae07a5SMark Brown SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0),
907942c435bSMark Brown
908c340304dSMark Brown SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
909c340304dSMark Brown SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
910942c435bSMark Brown
911942c435bSMark Brown SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
912942c435bSMark Brown left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
913942c435bSMark Brown SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0,
914942c435bSMark Brown right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
915b70a51baSMark Brown SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
916942c435bSMark Brown };
917942c435bSMark Brown
918942c435bSMark Brown static const struct snd_soc_dapm_route routes[] = {
9194e04adafSMark Brown { "MICBIAS1", NULL, "VMID" },
9204e04adafSMark Brown { "MICBIAS2", NULL, "VMID" },
9214e04adafSMark Brown
922942c435bSMark Brown { "ADCL", NULL, "CLK_SYS" },
923942c435bSMark Brown { "ADCL", NULL, "CLK_DSP" },
924942c435bSMark Brown { "ADCR", NULL, "CLK_SYS" },
925942c435bSMark Brown { "ADCR", NULL, "CLK_DSP" },
926942c435bSMark Brown
92759ae07a5SMark Brown { "AIFOUTL Mux", "Left", "ADCL" },
92859ae07a5SMark Brown { "AIFOUTL Mux", "Right", "ADCR" },
92959ae07a5SMark Brown { "AIFOUTR Mux", "Left", "ADCL" },
93059ae07a5SMark Brown { "AIFOUTR Mux", "Right", "ADCR" },
93159ae07a5SMark Brown
93259ae07a5SMark Brown { "AIFOUTL", NULL, "AIFOUTL Mux" },
93359ae07a5SMark Brown { "AIFOUTR", NULL, "AIFOUTR Mux" },
93459ae07a5SMark Brown
93559ae07a5SMark Brown { "DACL Mux", "Left", "AIFINL" },
93659ae07a5SMark Brown { "DACL Mux", "Right", "AIFINR" },
93759ae07a5SMark Brown { "DACR Mux", "Left", "AIFINL" },
93859ae07a5SMark Brown { "DACR Mux", "Right", "AIFINR" },
93959ae07a5SMark Brown
94059ae07a5SMark Brown { "DACL Sidetone", "Left", "ADCL" },
94159ae07a5SMark Brown { "DACL Sidetone", "Right", "ADCR" },
94259ae07a5SMark Brown { "DACR Sidetone", "Left", "ADCL" },
94359ae07a5SMark Brown { "DACR Sidetone", "Right", "ADCR" },
94459ae07a5SMark Brown
945942c435bSMark Brown { "DACL", NULL, "CLK_SYS" },
946942c435bSMark Brown { "DACL", NULL, "CLK_DSP" },
94759ae07a5SMark Brown { "DACL", NULL, "DACL Mux" },
94859ae07a5SMark Brown { "DACL", NULL, "DACL Sidetone" },
949942c435bSMark Brown { "DACR", NULL, "CLK_SYS" },
950942c435bSMark Brown { "DACR", NULL, "CLK_DSP" },
95159ae07a5SMark Brown { "DACR", NULL, "DACR Mux" },
95259ae07a5SMark Brown { "DACR", NULL, "DACR Sidetone" },
953942c435bSMark Brown
954942c435bSMark Brown { "Left Output Mixer", "DAC Switch", "DACL" },
955942c435bSMark Brown
956942c435bSMark Brown { "Right Output Mixer", "DAC Switch", "DACR" },
957942c435bSMark Brown
958942c435bSMark Brown { "Left Output PGA", NULL, "CLK_SYS" },
959942c435bSMark Brown
960942c435bSMark Brown { "Right Output PGA", NULL, "CLK_SYS" },
961942c435bSMark Brown
962942c435bSMark Brown { "SPKL", "DAC Switch", "DACL" },
963942c435bSMark Brown { "SPKL", NULL, "CLK_SYS" },
964942c435bSMark Brown
965942c435bSMark Brown { "SPKR", "DAC Switch", "DACR" },
966942c435bSMark Brown { "SPKR", NULL, "CLK_SYS" },
967942c435bSMark Brown
968942c435bSMark Brown { "Left Headphone Mux", "DAC", "DACL" },
969942c435bSMark Brown { "Right Headphone Mux", "DAC", "DACR" },
970942c435bSMark Brown };
971942c435bSMark Brown
wm8993_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)97200a6941cSKuninori Morimoto static int wm8993_set_bias_level(struct snd_soc_component *component,
973942c435bSMark Brown enum snd_soc_bias_level level)
974942c435bSMark Brown {
97500a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
976cf56f627SMark Brown int ret;
977942c435bSMark Brown
97800a6941cSKuninori Morimoto wm_hubs_set_bias_level(component, level);
9795f2f3890SMark Brown
980942c435bSMark Brown switch (level) {
981942c435bSMark Brown case SND_SOC_BIAS_ON:
982942c435bSMark Brown case SND_SOC_BIAS_PREPARE:
983942c435bSMark Brown /* VMID=2*40k */
98400a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
985942c435bSMark Brown WM8993_VMID_SEL_MASK, 0x2);
98600a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_2,
987942c435bSMark Brown WM8993_TSHUT_ENA, WM8993_TSHUT_ENA);
988942c435bSMark Brown break;
989942c435bSMark Brown
990942c435bSMark Brown case SND_SOC_BIAS_STANDBY:
99100a6941cSKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
992cf56f627SMark Brown ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
993cf56f627SMark Brown wm8993->supplies);
994cf56f627SMark Brown if (ret != 0)
995cf56f627SMark Brown return ret;
996cf56f627SMark Brown
997d0ad0af0SMark Brown regcache_cache_only(wm8993->regmap, false);
998d0ad0af0SMark Brown regcache_sync(wm8993->regmap);
999cf56f627SMark Brown
100000a6941cSKuninori Morimoto wm_hubs_vmid_ena(component);
10015f2f3890SMark Brown
1002942c435bSMark Brown /* Bring up VMID with fast soft start */
100300a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
1004942c435bSMark Brown WM8993_STARTUP_BIAS_ENA |
1005942c435bSMark Brown WM8993_VMID_BUF_ENA |
1006942c435bSMark Brown WM8993_VMID_RAMP_MASK |
1007942c435bSMark Brown WM8993_BIAS_SRC,
1008942c435bSMark Brown WM8993_STARTUP_BIAS_ENA |
1009942c435bSMark Brown WM8993_VMID_BUF_ENA |
1010942c435bSMark Brown WM8993_VMID_RAMP_MASK |
1011942c435bSMark Brown WM8993_BIAS_SRC);
1012942c435bSMark Brown
1013942c435bSMark Brown /* If either line output is single ended we
1014942c435bSMark Brown * need the VMID buffer */
1015942c435bSMark Brown if (!wm8993->pdata.lineout1_diff ||
1016942c435bSMark Brown !wm8993->pdata.lineout2_diff)
101700a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
1018942c435bSMark Brown WM8993_LINEOUT_VMID_BUF_ENA,
1019942c435bSMark Brown WM8993_LINEOUT_VMID_BUF_ENA);
1020942c435bSMark Brown
1021942c435bSMark Brown /* VMID=2*40k */
102200a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
1023942c435bSMark Brown WM8993_VMID_SEL_MASK |
1024942c435bSMark Brown WM8993_BIAS_ENA,
1025942c435bSMark Brown WM8993_BIAS_ENA | 0x2);
1026942c435bSMark Brown msleep(32);
1027942c435bSMark Brown
1028942c435bSMark Brown /* Switch to normal bias */
102900a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
1030942c435bSMark Brown WM8993_BIAS_SRC |
1031942c435bSMark Brown WM8993_STARTUP_BIAS_ENA, 0);
1032942c435bSMark Brown }
1033942c435bSMark Brown
1034942c435bSMark Brown /* VMID=2*240k */
103500a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
1036942c435bSMark Brown WM8993_VMID_SEL_MASK, 0x4);
1037942c435bSMark Brown
103800a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_2,
1039942c435bSMark Brown WM8993_TSHUT_ENA, 0);
1040942c435bSMark Brown break;
1041942c435bSMark Brown
1042942c435bSMark Brown case SND_SOC_BIAS_OFF:
104300a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_ANTIPOP1,
1044942c435bSMark Brown WM8993_LINEOUT_VMID_BUF_ENA, 0);
1045942c435bSMark Brown
104600a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_POWER_MANAGEMENT_1,
1047942c435bSMark Brown WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA,
1048942c435bSMark Brown 0);
1049cf56f627SMark Brown
105000a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_ANTIPOP2,
105183b65425SMark Brown WM8993_STARTUP_BIAS_ENA |
105283b65425SMark Brown WM8993_VMID_BUF_ENA |
105383b65425SMark Brown WM8993_VMID_RAMP_MASK |
105483b65425SMark Brown WM8993_BIAS_SRC, 0);
105583b65425SMark Brown
1056d0ad0af0SMark Brown regcache_cache_only(wm8993->regmap, true);
1057d0ad0af0SMark Brown regcache_mark_dirty(wm8993->regmap);
1058cf56f627SMark Brown
1059cf56f627SMark Brown regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies),
1060cf56f627SMark Brown wm8993->supplies);
1061942c435bSMark Brown break;
1062942c435bSMark Brown }
1063942c435bSMark Brown
1064942c435bSMark Brown return 0;
1065942c435bSMark Brown }
1066942c435bSMark Brown
wm8993_set_sysclk(struct snd_soc_dai * codec_dai,int clk_id,unsigned int freq,int dir)1067942c435bSMark Brown static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai,
1068942c435bSMark Brown int clk_id, unsigned int freq, int dir)
1069942c435bSMark Brown {
107000a6941cSKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
107100a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
1072942c435bSMark Brown
1073942c435bSMark Brown switch (clk_id) {
1074942c435bSMark Brown case WM8993_SYSCLK_MCLK:
1075942c435bSMark Brown wm8993->mclk_rate = freq;
10763e146b55SGustavo A. R. Silva fallthrough;
1077942c435bSMark Brown case WM8993_SYSCLK_FLL:
1078942c435bSMark Brown wm8993->sysclk_source = clk_id;
1079942c435bSMark Brown break;
1080942c435bSMark Brown
1081942c435bSMark Brown default:
1082942c435bSMark Brown return -EINVAL;
1083942c435bSMark Brown }
1084942c435bSMark Brown
1085942c435bSMark Brown return 0;
1086942c435bSMark Brown }
1087942c435bSMark Brown
wm8993_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)1088942c435bSMark Brown static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
1089942c435bSMark Brown unsigned int fmt)
1090942c435bSMark Brown {
109100a6941cSKuninori Morimoto struct snd_soc_component *component = dai->component;
109200a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
10936d75dfc3SKuninori Morimoto unsigned int aif1 = snd_soc_component_read(component, WM8993_AUDIO_INTERFACE_1);
10946d75dfc3SKuninori Morimoto unsigned int aif4 = snd_soc_component_read(component, WM8993_AUDIO_INTERFACE_4);
1095942c435bSMark Brown
1096942c435bSMark Brown aif1 &= ~(WM8993_BCLK_DIR | WM8993_AIF_BCLK_INV |
1097942c435bSMark Brown WM8993_AIF_LRCLK_INV | WM8993_AIF_FMT_MASK);
1098942c435bSMark Brown aif4 &= ~WM8993_LRCLK_DIR;
1099942c435bSMark Brown
1100942c435bSMark Brown switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1101942c435bSMark Brown case SND_SOC_DAIFMT_CBS_CFS:
1102942c435bSMark Brown wm8993->master = 0;
1103942c435bSMark Brown break;
1104942c435bSMark Brown case SND_SOC_DAIFMT_CBS_CFM:
1105942c435bSMark Brown aif4 |= WM8993_LRCLK_DIR;
1106942c435bSMark Brown wm8993->master = 1;
1107942c435bSMark Brown break;
1108942c435bSMark Brown case SND_SOC_DAIFMT_CBM_CFS:
1109942c435bSMark Brown aif1 |= WM8993_BCLK_DIR;
1110942c435bSMark Brown wm8993->master = 1;
1111942c435bSMark Brown break;
1112942c435bSMark Brown case SND_SOC_DAIFMT_CBM_CFM:
1113942c435bSMark Brown aif1 |= WM8993_BCLK_DIR;
1114942c435bSMark Brown aif4 |= WM8993_LRCLK_DIR;
1115942c435bSMark Brown wm8993->master = 1;
1116942c435bSMark Brown break;
1117942c435bSMark Brown default:
1118942c435bSMark Brown return -EINVAL;
1119942c435bSMark Brown }
1120942c435bSMark Brown
1121942c435bSMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1122942c435bSMark Brown case SND_SOC_DAIFMT_DSP_B:
1123942c435bSMark Brown aif1 |= WM8993_AIF_LRCLK_INV;
11243e146b55SGustavo A. R. Silva fallthrough;
1125942c435bSMark Brown case SND_SOC_DAIFMT_DSP_A:
1126942c435bSMark Brown aif1 |= 0x18;
1127942c435bSMark Brown break;
1128942c435bSMark Brown case SND_SOC_DAIFMT_I2S:
1129942c435bSMark Brown aif1 |= 0x10;
1130942c435bSMark Brown break;
1131942c435bSMark Brown case SND_SOC_DAIFMT_RIGHT_J:
1132942c435bSMark Brown break;
1133942c435bSMark Brown case SND_SOC_DAIFMT_LEFT_J:
1134942c435bSMark Brown aif1 |= 0x8;
1135942c435bSMark Brown break;
1136942c435bSMark Brown default:
1137942c435bSMark Brown return -EINVAL;
1138942c435bSMark Brown }
1139942c435bSMark Brown
1140942c435bSMark Brown switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1141942c435bSMark Brown case SND_SOC_DAIFMT_DSP_A:
1142942c435bSMark Brown case SND_SOC_DAIFMT_DSP_B:
1143942c435bSMark Brown /* frame inversion not valid for DSP modes */
1144942c435bSMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1145942c435bSMark Brown case SND_SOC_DAIFMT_NB_NF:
1146942c435bSMark Brown break;
1147942c435bSMark Brown case SND_SOC_DAIFMT_IB_NF:
1148942c435bSMark Brown aif1 |= WM8993_AIF_BCLK_INV;
1149942c435bSMark Brown break;
1150942c435bSMark Brown default:
1151942c435bSMark Brown return -EINVAL;
1152942c435bSMark Brown }
1153942c435bSMark Brown break;
1154942c435bSMark Brown
1155942c435bSMark Brown case SND_SOC_DAIFMT_I2S:
1156942c435bSMark Brown case SND_SOC_DAIFMT_RIGHT_J:
1157942c435bSMark Brown case SND_SOC_DAIFMT_LEFT_J:
1158942c435bSMark Brown switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1159942c435bSMark Brown case SND_SOC_DAIFMT_NB_NF:
1160942c435bSMark Brown break;
1161942c435bSMark Brown case SND_SOC_DAIFMT_IB_IF:
1162942c435bSMark Brown aif1 |= WM8993_AIF_BCLK_INV | WM8993_AIF_LRCLK_INV;
1163942c435bSMark Brown break;
1164942c435bSMark Brown case SND_SOC_DAIFMT_IB_NF:
1165942c435bSMark Brown aif1 |= WM8993_AIF_BCLK_INV;
1166942c435bSMark Brown break;
1167942c435bSMark Brown case SND_SOC_DAIFMT_NB_IF:
1168942c435bSMark Brown aif1 |= WM8993_AIF_LRCLK_INV;
1169942c435bSMark Brown break;
1170942c435bSMark Brown default:
1171942c435bSMark Brown return -EINVAL;
1172942c435bSMark Brown }
1173942c435bSMark Brown break;
1174942c435bSMark Brown default:
1175942c435bSMark Brown return -EINVAL;
1176942c435bSMark Brown }
1177942c435bSMark Brown
117800a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_1, aif1);
117900a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_4, aif4);
1180942c435bSMark Brown
1181942c435bSMark Brown return 0;
1182942c435bSMark Brown }
1183942c435bSMark Brown
wm8993_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1184942c435bSMark Brown static int wm8993_hw_params(struct snd_pcm_substream *substream,
1185942c435bSMark Brown struct snd_pcm_hw_params *params,
1186942c435bSMark Brown struct snd_soc_dai *dai)
1187942c435bSMark Brown {
118800a6941cSKuninori Morimoto struct snd_soc_component *component = dai->component;
118900a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
1190942c435bSMark Brown int ret, i, best, best_val, cur_val;
1191942c435bSMark Brown unsigned int clocking1, clocking3, aif1, aif4;
1192942c435bSMark Brown
11936d75dfc3SKuninori Morimoto clocking1 = snd_soc_component_read(component, WM8993_CLOCKING_1);
1194942c435bSMark Brown clocking1 &= ~WM8993_BCLK_DIV_MASK;
1195942c435bSMark Brown
11966d75dfc3SKuninori Morimoto clocking3 = snd_soc_component_read(component, WM8993_CLOCKING_3);
1197942c435bSMark Brown clocking3 &= ~(WM8993_CLK_SYS_RATE_MASK | WM8993_SAMPLE_RATE_MASK);
1198942c435bSMark Brown
11996d75dfc3SKuninori Morimoto aif1 = snd_soc_component_read(component, WM8993_AUDIO_INTERFACE_1);
1200942c435bSMark Brown aif1 &= ~WM8993_AIF_WL_MASK;
1201942c435bSMark Brown
12026d75dfc3SKuninori Morimoto aif4 = snd_soc_component_read(component, WM8993_AUDIO_INTERFACE_4);
1203942c435bSMark Brown aif4 &= ~WM8993_LRCLK_RATE_MASK;
1204942c435bSMark Brown
1205942c435bSMark Brown /* What BCLK do we need? */
1206942c435bSMark Brown wm8993->fs = params_rate(params);
1207942c435bSMark Brown wm8993->bclk = 2 * wm8993->fs;
1208d3c9e9a1SMark Brown if (wm8993->tdm_slots) {
120900a6941cSKuninori Morimoto dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
1210d3c9e9a1SMark Brown wm8993->tdm_slots, wm8993->tdm_width);
1211d3c9e9a1SMark Brown wm8993->bclk *= wm8993->tdm_width * wm8993->tdm_slots;
1212d3c9e9a1SMark Brown } else {
1213ae62ba67SMark Brown switch (params_width(params)) {
1214ae62ba67SMark Brown case 16:
1215942c435bSMark Brown wm8993->bclk *= 16;
1216942c435bSMark Brown break;
1217ae62ba67SMark Brown case 20:
1218942c435bSMark Brown wm8993->bclk *= 20;
1219942c435bSMark Brown aif1 |= 0x8;
1220942c435bSMark Brown break;
1221ae62ba67SMark Brown case 24:
1222942c435bSMark Brown wm8993->bclk *= 24;
1223942c435bSMark Brown aif1 |= 0x10;
1224942c435bSMark Brown break;
1225ae62ba67SMark Brown case 32:
1226942c435bSMark Brown wm8993->bclk *= 32;
1227942c435bSMark Brown aif1 |= 0x18;
1228942c435bSMark Brown break;
1229942c435bSMark Brown default:
1230942c435bSMark Brown return -EINVAL;
1231942c435bSMark Brown }
1232d3c9e9a1SMark Brown }
1233942c435bSMark Brown
123400a6941cSKuninori Morimoto dev_dbg(component->dev, "Target BCLK is %dHz\n", wm8993->bclk);
1235942c435bSMark Brown
123600a6941cSKuninori Morimoto ret = configure_clock(component);
1237942c435bSMark Brown if (ret != 0)
1238942c435bSMark Brown return ret;
1239942c435bSMark Brown
1240942c435bSMark Brown /* Select nearest CLK_SYS_RATE */
1241942c435bSMark Brown best = 0;
1242942c435bSMark Brown best_val = abs((wm8993->sysclk_rate / clk_sys_rates[0].ratio)
1243942c435bSMark Brown - wm8993->fs);
1244942c435bSMark Brown for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
1245942c435bSMark Brown cur_val = abs((wm8993->sysclk_rate /
1246ef995e3aSJoe Perches clk_sys_rates[i].ratio) - wm8993->fs);
1247942c435bSMark Brown if (cur_val < best_val) {
1248942c435bSMark Brown best = i;
1249942c435bSMark Brown best_val = cur_val;
1250942c435bSMark Brown }
1251942c435bSMark Brown }
125200a6941cSKuninori Morimoto dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
1253942c435bSMark Brown clk_sys_rates[best].ratio);
1254942c435bSMark Brown clocking3 |= (clk_sys_rates[best].clk_sys_rate
1255942c435bSMark Brown << WM8993_CLK_SYS_RATE_SHIFT);
1256942c435bSMark Brown
1257942c435bSMark Brown /* SAMPLE_RATE */
1258942c435bSMark Brown best = 0;
1259942c435bSMark Brown best_val = abs(wm8993->fs - sample_rates[0].rate);
1260942c435bSMark Brown for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
1261942c435bSMark Brown /* Closest match */
1262942c435bSMark Brown cur_val = abs(wm8993->fs - sample_rates[i].rate);
1263942c435bSMark Brown if (cur_val < best_val) {
1264942c435bSMark Brown best = i;
1265942c435bSMark Brown best_val = cur_val;
1266942c435bSMark Brown }
1267942c435bSMark Brown }
126800a6941cSKuninori Morimoto dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
1269942c435bSMark Brown sample_rates[best].rate);
1270e465d544SMark Brown clocking3 |= (sample_rates[best].sample_rate
1271e465d544SMark Brown << WM8993_SAMPLE_RATE_SHIFT);
1272942c435bSMark Brown
1273942c435bSMark Brown /* BCLK_DIV */
1274942c435bSMark Brown best = 0;
1275942c435bSMark Brown best_val = INT_MAX;
1276942c435bSMark Brown for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
1277942c435bSMark Brown cur_val = ((wm8993->sysclk_rate * 10) / bclk_divs[i].div)
1278942c435bSMark Brown - wm8993->bclk;
1279942c435bSMark Brown if (cur_val < 0) /* Table is sorted */
1280942c435bSMark Brown break;
1281942c435bSMark Brown if (cur_val < best_val) {
1282942c435bSMark Brown best = i;
1283942c435bSMark Brown best_val = cur_val;
1284942c435bSMark Brown }
1285942c435bSMark Brown }
1286942c435bSMark Brown wm8993->bclk = (wm8993->sysclk_rate * 10) / bclk_divs[best].div;
128700a6941cSKuninori Morimoto dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
1288942c435bSMark Brown bclk_divs[best].div, wm8993->bclk);
1289942c435bSMark Brown clocking1 |= bclk_divs[best].bclk_div << WM8993_BCLK_DIV_SHIFT;
1290942c435bSMark Brown
1291942c435bSMark Brown /* LRCLK is a simple fraction of BCLK */
129200a6941cSKuninori Morimoto dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm8993->bclk / wm8993->fs);
1293942c435bSMark Brown aif4 |= wm8993->bclk / wm8993->fs;
1294942c435bSMark Brown
129500a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_CLOCKING_1, clocking1);
129600a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_CLOCKING_3, clocking3);
129700a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_1, aif1);
129800a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_AUDIO_INTERFACE_4, aif4);
1299942c435bSMark Brown
1300942c435bSMark Brown /* ReTune Mobile? */
1301942c435bSMark Brown if (wm8993->pdata.num_retune_configs) {
13026d75dfc3SKuninori Morimoto u16 eq1 = snd_soc_component_read(component, WM8993_EQ1);
1303942c435bSMark Brown struct wm8993_retune_mobile_setting *s;
1304942c435bSMark Brown
1305942c435bSMark Brown best = 0;
1306942c435bSMark Brown best_val = abs(wm8993->pdata.retune_configs[0].rate
1307942c435bSMark Brown - wm8993->fs);
1308942c435bSMark Brown for (i = 0; i < wm8993->pdata.num_retune_configs; i++) {
1309942c435bSMark Brown cur_val = abs(wm8993->pdata.retune_configs[i].rate
1310942c435bSMark Brown - wm8993->fs);
1311942c435bSMark Brown if (cur_val < best_val) {
1312942c435bSMark Brown best_val = cur_val;
1313942c435bSMark Brown best = i;
1314942c435bSMark Brown }
1315942c435bSMark Brown }
1316942c435bSMark Brown s = &wm8993->pdata.retune_configs[best];
1317942c435bSMark Brown
131800a6941cSKuninori Morimoto dev_dbg(component->dev, "ReTune Mobile %s tuned for %dHz\n",
1319942c435bSMark Brown s->name, s->rate);
1320942c435bSMark Brown
1321942c435bSMark Brown /* Disable EQ while we reconfigure */
132200a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_EQ1, WM8993_EQ_ENA, 0);
1323942c435bSMark Brown
1324942c435bSMark Brown for (i = 1; i < ARRAY_SIZE(s->config); i++)
132500a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_EQ1 + i, s->config[i]);
1326942c435bSMark Brown
132700a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_EQ1, WM8993_EQ_ENA, eq1);
1328942c435bSMark Brown }
1329942c435bSMark Brown
1330942c435bSMark Brown return 0;
1331942c435bSMark Brown }
1332942c435bSMark Brown
wm8993_mute(struct snd_soc_dai * codec_dai,int mute,int direction)133326d3c16eSKuninori Morimoto static int wm8993_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
1334942c435bSMark Brown {
133500a6941cSKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
1336942c435bSMark Brown unsigned int reg;
1337942c435bSMark Brown
13386d75dfc3SKuninori Morimoto reg = snd_soc_component_read(component, WM8993_DAC_CTRL);
1339942c435bSMark Brown
1340942c435bSMark Brown if (mute)
1341942c435bSMark Brown reg |= WM8993_DAC_MUTE;
1342942c435bSMark Brown else
1343942c435bSMark Brown reg &= ~WM8993_DAC_MUTE;
1344942c435bSMark Brown
134500a6941cSKuninori Morimoto snd_soc_component_write(component, WM8993_DAC_CTRL, reg);
1346942c435bSMark Brown
1347942c435bSMark Brown return 0;
1348942c435bSMark Brown }
1349942c435bSMark Brown
wm8993_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)1350d3c9e9a1SMark Brown static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1351d3c9e9a1SMark Brown unsigned int rx_mask, int slots, int slot_width)
1352d3c9e9a1SMark Brown {
135300a6941cSKuninori Morimoto struct snd_soc_component *component = dai->component;
135400a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
1355d3c9e9a1SMark Brown int aif1 = 0;
1356d3c9e9a1SMark Brown int aif2 = 0;
1357d3c9e9a1SMark Brown
1358d3c9e9a1SMark Brown /* Don't need to validate anything if we're turning off TDM */
1359d3c9e9a1SMark Brown if (slots == 0) {
1360d3c9e9a1SMark Brown wm8993->tdm_slots = 0;
1361d3c9e9a1SMark Brown goto out;
1362d3c9e9a1SMark Brown }
1363d3c9e9a1SMark Brown
1364d3c9e9a1SMark Brown /* Note that we allow configurations we can't handle ourselves -
1365d3c9e9a1SMark Brown * for example, we can generate clocks for slots 2 and up even if
1366d3c9e9a1SMark Brown * we can't use those slots ourselves.
1367d3c9e9a1SMark Brown */
1368d3c9e9a1SMark Brown aif1 |= WM8993_AIFADC_TDM;
1369d3c9e9a1SMark Brown aif2 |= WM8993_AIFDAC_TDM;
1370d3c9e9a1SMark Brown
1371d3c9e9a1SMark Brown switch (rx_mask) {
1372d3c9e9a1SMark Brown case 3:
1373d3c9e9a1SMark Brown break;
1374d3c9e9a1SMark Brown case 0xc:
1375d3c9e9a1SMark Brown aif1 |= WM8993_AIFADC_TDM_CHAN;
1376d3c9e9a1SMark Brown break;
1377d3c9e9a1SMark Brown default:
1378d3c9e9a1SMark Brown return -EINVAL;
1379d3c9e9a1SMark Brown }
1380d3c9e9a1SMark Brown
1381d3c9e9a1SMark Brown
1382d3c9e9a1SMark Brown switch (tx_mask) {
1383d3c9e9a1SMark Brown case 3:
1384d3c9e9a1SMark Brown break;
1385d3c9e9a1SMark Brown case 0xc:
1386d3c9e9a1SMark Brown aif2 |= WM8993_AIFDAC_TDM_CHAN;
1387d3c9e9a1SMark Brown break;
1388d3c9e9a1SMark Brown default:
1389d3c9e9a1SMark Brown return -EINVAL;
1390d3c9e9a1SMark Brown }
1391d3c9e9a1SMark Brown
1392d3c9e9a1SMark Brown out:
1393d3c9e9a1SMark Brown wm8993->tdm_width = slot_width;
1394d3c9e9a1SMark Brown wm8993->tdm_slots = slots / 2;
1395d3c9e9a1SMark Brown
139600a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_AUDIO_INTERFACE_1,
1397d3c9e9a1SMark Brown WM8993_AIFADC_TDM | WM8993_AIFADC_TDM_CHAN, aif1);
139800a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_AUDIO_INTERFACE_2,
1399d3c9e9a1SMark Brown WM8993_AIFDAC_TDM | WM8993_AIFDAC_TDM_CHAN, aif2);
1400d3c9e9a1SMark Brown
1401d3c9e9a1SMark Brown return 0;
1402d3c9e9a1SMark Brown }
1403d3c9e9a1SMark Brown
wm8993_irq(int irq,void * data)1404164548d3SMark Brown static irqreturn_t wm8993_irq(int irq, void *data)
1405164548d3SMark Brown {
1406164548d3SMark Brown struct wm8993_priv *wm8993 = data;
1407164548d3SMark Brown int mask, val, ret;
1408164548d3SMark Brown
1409164548d3SMark Brown ret = regmap_read(wm8993->regmap, WM8993_GPIO_CTRL_1, &val);
1410164548d3SMark Brown if (ret != 0) {
1411164548d3SMark Brown dev_err(wm8993->dev, "Failed to read interrupt status: %d\n",
1412164548d3SMark Brown ret);
1413164548d3SMark Brown return IRQ_NONE;
1414164548d3SMark Brown }
1415164548d3SMark Brown
1416164548d3SMark Brown ret = regmap_read(wm8993->regmap, WM8993_GPIOCTRL_2, &mask);
1417164548d3SMark Brown if (ret != 0) {
1418164548d3SMark Brown dev_err(wm8993->dev, "Failed to read interrupt mask: %d\n",
1419164548d3SMark Brown ret);
1420164548d3SMark Brown return IRQ_NONE;
1421164548d3SMark Brown }
1422164548d3SMark Brown
1423164548d3SMark Brown /* The IRQ pin status is visible in the register too */
1424164548d3SMark Brown val &= ~(mask | WM8993_IRQ);
1425164548d3SMark Brown if (!val)
1426164548d3SMark Brown return IRQ_NONE;
1427164548d3SMark Brown
1428164548d3SMark Brown if (val & WM8993_TEMPOK_EINT)
1429164548d3SMark Brown dev_crit(wm8993->dev, "Thermal warning\n");
1430164548d3SMark Brown
1431164548d3SMark Brown if (val & WM8993_FLL_LOCK_EINT) {
1432164548d3SMark Brown dev_dbg(wm8993->dev, "FLL locked\n");
1433164548d3SMark Brown complete(&wm8993->fll_lock);
1434164548d3SMark Brown }
1435164548d3SMark Brown
1436164548d3SMark Brown ret = regmap_write(wm8993->regmap, WM8993_GPIO_CTRL_1, val);
1437164548d3SMark Brown if (ret != 0)
1438164548d3SMark Brown dev_err(wm8993->dev, "Failed to ack interrupt: %d\n", ret);
1439164548d3SMark Brown
1440164548d3SMark Brown return IRQ_HANDLED;
1441164548d3SMark Brown }
1442164548d3SMark Brown
144385e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8993_ops = {
1444942c435bSMark Brown .set_sysclk = wm8993_set_sysclk,
1445942c435bSMark Brown .set_fmt = wm8993_set_dai_fmt,
1446942c435bSMark Brown .hw_params = wm8993_hw_params,
144726d3c16eSKuninori Morimoto .mute_stream = wm8993_mute,
1448942c435bSMark Brown .set_pll = wm8993_set_fll,
1449d3c9e9a1SMark Brown .set_tdm_slot = wm8993_set_tdm_slot,
145026d3c16eSKuninori Morimoto .no_capture_mute = 1,
1451942c435bSMark Brown };
1452942c435bSMark Brown
1453942c435bSMark Brown #define WM8993_RATES SNDRV_PCM_RATE_8000_48000
1454942c435bSMark Brown
1455942c435bSMark Brown #define WM8993_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
1456942c435bSMark Brown SNDRV_PCM_FMTBIT_S20_3LE |\
1457942c435bSMark Brown SNDRV_PCM_FMTBIT_S24_LE |\
1458942c435bSMark Brown SNDRV_PCM_FMTBIT_S32_LE)
1459942c435bSMark Brown
1460f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8993_dai = {
1461f0fba2adSLiam Girdwood .name = "wm8993-hifi",
1462942c435bSMark Brown .playback = {
1463942c435bSMark Brown .stream_name = "Playback",
1464942c435bSMark Brown .channels_min = 1,
1465942c435bSMark Brown .channels_max = 2,
1466942c435bSMark Brown .rates = WM8993_RATES,
1467942c435bSMark Brown .formats = WM8993_FORMATS,
146899b0292dSMark Brown .sig_bits = 24,
1469942c435bSMark Brown },
1470942c435bSMark Brown .capture = {
1471942c435bSMark Brown .stream_name = "Capture",
1472942c435bSMark Brown .channels_min = 1,
1473942c435bSMark Brown .channels_max = 2,
1474942c435bSMark Brown .rates = WM8993_RATES,
1475942c435bSMark Brown .formats = WM8993_FORMATS,
147699b0292dSMark Brown .sig_bits = 24,
1477942c435bSMark Brown },
1478942c435bSMark Brown .ops = &wm8993_ops,
147907695752SKuninori Morimoto .symmetric_rate = 1,
1480942c435bSMark Brown };
1481942c435bSMark Brown
wm8993_probe(struct snd_soc_component * component)148200a6941cSKuninori Morimoto static int wm8993_probe(struct snd_soc_component *component)
1483942c435bSMark Brown {
148400a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
148500a6941cSKuninori Morimoto struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
148653242c68SMark Brown
14873ed7074cSMark Brown wm8993->hubs_data.hp_startup_mode = 1;
14884537c4e7SMark Brown wm8993->hubs_data.dcs_codes_l = -2;
14894537c4e7SMark Brown wm8993->hubs_data.dcs_codes_r = -2;
1490f9acf9feSMark Brown wm8993->hubs_data.series_startup = 1;
14913ed7074cSMark Brown
1492942c435bSMark Brown /* Latch volume update bits and default ZC on */
149300a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
1494942c435bSMark Brown WM8993_DAC_VU, WM8993_DAC_VU);
149500a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
1496942c435bSMark Brown WM8993_ADC_VU, WM8993_ADC_VU);
1497942c435bSMark Brown
1498942c435bSMark Brown /* Manualy manage the HPOUT sequencing for independent stereo
1499942c435bSMark Brown * control. */
150000a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_ANALOGUE_HP_0,
1501942c435bSMark Brown WM8993_HPOUT1_AUTO_PU, 0);
1502942c435bSMark Brown
1503942c435bSMark Brown /* Use automatic clock configuration */
150400a6941cSKuninori Morimoto snd_soc_component_update_bits(component, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
1505942c435bSMark Brown
150600a6941cSKuninori Morimoto wm_hubs_handle_analogue_pdata(component, wm8993->pdata.lineout1_diff,
1507aa983d9dSMark Brown wm8993->pdata.lineout2_diff,
1508aa983d9dSMark Brown wm8993->pdata.lineout1fb,
1509aa983d9dSMark Brown wm8993->pdata.lineout2fb,
1510aa983d9dSMark Brown wm8993->pdata.jd_scthr,
1511aa983d9dSMark Brown wm8993->pdata.jd_thr,
151202e79476SMark Brown wm8993->pdata.micbias1_delay,
151302e79476SMark Brown wm8993->pdata.micbias2_delay,
1514aa983d9dSMark Brown wm8993->pdata.micbias1_lvl,
1515aa983d9dSMark Brown wm8993->pdata.micbias2_lvl);
1516942c435bSMark Brown
151700a6941cSKuninori Morimoto snd_soc_add_component_controls(component, wm8993_snd_controls,
1518f0fba2adSLiam Girdwood ARRAY_SIZE(wm8993_snd_controls));
1519f0fba2adSLiam Girdwood if (wm8993->pdata.num_retune_configs != 0) {
152000a6941cSKuninori Morimoto dev_dbg(component->dev, "Using ReTune Mobile\n");
1521f0fba2adSLiam Girdwood } else {
152200a6941cSKuninori Morimoto dev_dbg(component->dev, "No ReTune Mobile, using normal EQ\n");
152300a6941cSKuninori Morimoto snd_soc_add_component_controls(component, wm8993_eq_controls,
1524f0fba2adSLiam Girdwood ARRAY_SIZE(wm8993_eq_controls));
1525f0fba2adSLiam Girdwood }
1526942c435bSMark Brown
1527ce6120ccSLiam Girdwood snd_soc_dapm_new_controls(dapm, wm8993_dapm_widgets,
1528f0fba2adSLiam Girdwood ARRAY_SIZE(wm8993_dapm_widgets));
152900a6941cSKuninori Morimoto wm_hubs_add_analogue_controls(component);
1530942c435bSMark Brown
1531ce6120ccSLiam Girdwood snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
153200a6941cSKuninori Morimoto wm_hubs_add_analogue_routes(component, wm8993->pdata.lineout1_diff,
1533f0fba2adSLiam Girdwood wm8993->pdata.lineout2_diff);
1534942c435bSMark Brown
1535f959dee9SMark Brown /* If the line outputs are differential then we aren't presenting
1536f959dee9SMark Brown * VMID as an output and can disable it.
1537f959dee9SMark Brown */
1538f959dee9SMark Brown if (wm8993->pdata.lineout1_diff && wm8993->pdata.lineout2_diff)
1539f8ae3cf8SLars-Peter Clausen dapm->idle_bias_off = 1;
1540f959dee9SMark Brown
1541942c435bSMark Brown return 0;
1542942c435bSMark Brown
1543f0fba2adSLiam Girdwood }
1544f0fba2adSLiam Girdwood
1545f0fba2adSLiam Girdwood #ifdef CONFIG_PM
wm8993_suspend(struct snd_soc_component * component)154600a6941cSKuninori Morimoto static int wm8993_suspend(struct snd_soc_component *component)
1547f0fba2adSLiam Girdwood {
154800a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
1549f0fba2adSLiam Girdwood int fll_fout = wm8993->fll_fout;
1550f0fba2adSLiam Girdwood int fll_fref = wm8993->fll_fref;
1551f0fba2adSLiam Girdwood int ret;
1552f0fba2adSLiam Girdwood
1553f0fba2adSLiam Girdwood /* Stop the FLL in an orderly fashion */
155400a6941cSKuninori Morimoto ret = _wm8993_set_fll(component, 0, 0, 0, 0);
1555f0fba2adSLiam Girdwood if (ret != 0) {
155600a6941cSKuninori Morimoto dev_err(component->dev, "Failed to stop FLL\n");
1557f0fba2adSLiam Girdwood return ret;
1558f0fba2adSLiam Girdwood }
1559f0fba2adSLiam Girdwood
1560f0fba2adSLiam Girdwood wm8993->fll_fout = fll_fout;
1561f0fba2adSLiam Girdwood wm8993->fll_fref = fll_fref;
1562f0fba2adSLiam Girdwood
156300a6941cSKuninori Morimoto snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF);
1564f0fba2adSLiam Girdwood
1565f0fba2adSLiam Girdwood return 0;
1566f0fba2adSLiam Girdwood }
1567f0fba2adSLiam Girdwood
wm8993_resume(struct snd_soc_component * component)156800a6941cSKuninori Morimoto static int wm8993_resume(struct snd_soc_component *component)
1569f0fba2adSLiam Girdwood {
157000a6941cSKuninori Morimoto struct wm8993_priv *wm8993 = snd_soc_component_get_drvdata(component);
1571f0fba2adSLiam Girdwood int ret;
1572f0fba2adSLiam Girdwood
157300a6941cSKuninori Morimoto snd_soc_component_force_bias_level(component, SND_SOC_BIAS_STANDBY);
1574f0fba2adSLiam Girdwood
1575f0fba2adSLiam Girdwood /* Restart the FLL? */
1576f0fba2adSLiam Girdwood if (wm8993->fll_fout) {
1577f0fba2adSLiam Girdwood int fll_fout = wm8993->fll_fout;
1578f0fba2adSLiam Girdwood int fll_fref = wm8993->fll_fref;
1579f0fba2adSLiam Girdwood
1580f0fba2adSLiam Girdwood wm8993->fll_fref = 0;
1581f0fba2adSLiam Girdwood wm8993->fll_fout = 0;
1582f0fba2adSLiam Girdwood
158300a6941cSKuninori Morimoto ret = _wm8993_set_fll(component, 0, wm8993->fll_src,
1584f0fba2adSLiam Girdwood fll_fref, fll_fout);
1585f0fba2adSLiam Girdwood if (ret != 0)
158600a6941cSKuninori Morimoto dev_err(component->dev, "Failed to restart FLL\n");
1587f0fba2adSLiam Girdwood }
1588f0fba2adSLiam Girdwood
1589f0fba2adSLiam Girdwood return 0;
1590f0fba2adSLiam Girdwood }
1591f0fba2adSLiam Girdwood #else
1592f0fba2adSLiam Girdwood #define wm8993_suspend NULL
1593f0fba2adSLiam Girdwood #define wm8993_resume NULL
1594f0fba2adSLiam Girdwood #endif
1595f0fba2adSLiam Girdwood
1596489773c2SMark Brown /* Tune DC servo configuration */
159741a5fefeSMark Brown static const struct reg_sequence wm8993_regmap_patch[] = {
1598489773c2SMark Brown { 0x44, 3 },
1599489773c2SMark Brown { 0x56, 3 },
1600489773c2SMark Brown { 0x44, 0 },
1601489773c2SMark Brown };
1602489773c2SMark Brown
1603d0ad0af0SMark Brown static const struct regmap_config wm8993_regmap = {
1604d0ad0af0SMark Brown .reg_bits = 8,
1605d0ad0af0SMark Brown .val_bits = 16,
1606d0ad0af0SMark Brown
1607d0ad0af0SMark Brown .max_register = WM8993_MAX_REGISTER,
1608d0ad0af0SMark Brown .volatile_reg = wm8993_volatile,
1609d0ad0af0SMark Brown .readable_reg = wm8993_readable,
1610d0ad0af0SMark Brown
1611*663aa332SMark Brown .cache_type = REGCACHE_MAPLE,
1612d0ad0af0SMark Brown .reg_defaults = wm8993_reg_defaults,
1613d0ad0af0SMark Brown .num_reg_defaults = ARRAY_SIZE(wm8993_reg_defaults),
1614d0ad0af0SMark Brown };
1615d0ad0af0SMark Brown
161600a6941cSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8993 = {
1617f0fba2adSLiam Girdwood .probe = wm8993_probe,
1618f0fba2adSLiam Girdwood .suspend = wm8993_suspend,
1619f0fba2adSLiam Girdwood .resume = wm8993_resume,
1620f0fba2adSLiam Girdwood .set_bias_level = wm8993_set_bias_level,
162100a6941cSKuninori Morimoto .idle_bias_on = 1,
162200a6941cSKuninori Morimoto .use_pmdown_time = 1,
162300a6941cSKuninori Morimoto .endianness = 1,
1624f0fba2adSLiam Girdwood };
1625f0fba2adSLiam Girdwood
wm8993_i2c_probe(struct i2c_client * i2c)162697b0b6e3SStephen Kitt static int wm8993_i2c_probe(struct i2c_client *i2c)
1627f0fba2adSLiam Girdwood {
1628f0fba2adSLiam Girdwood struct wm8993_priv *wm8993;
1629bfea3abbSMark Brown unsigned int reg;
1630bfea3abbSMark Brown int ret, i;
1631f0fba2adSLiam Girdwood
1632ec641c45SMark Brown wm8993 = devm_kzalloc(&i2c->dev, sizeof(struct wm8993_priv),
1633f6a93368SMark Brown GFP_KERNEL);
1634f0fba2adSLiam Girdwood if (wm8993 == NULL)
1635f0fba2adSLiam Girdwood return -ENOMEM;
1636f0fba2adSLiam Girdwood
1637164548d3SMark Brown wm8993->dev = &i2c->dev;
1638164548d3SMark Brown init_completion(&wm8993->fll_lock);
1639164548d3SMark Brown
16406dff9b3bSSachin Kamat wm8993->regmap = devm_regmap_init_i2c(i2c, &wm8993_regmap);
1641d0ad0af0SMark Brown if (IS_ERR(wm8993->regmap)) {
1642d0ad0af0SMark Brown ret = PTR_ERR(wm8993->regmap);
1643d0ad0af0SMark Brown dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
1644d0ad0af0SMark Brown return ret;
1645d0ad0af0SMark Brown }
1646d0ad0af0SMark Brown
1647f0fba2adSLiam Girdwood i2c_set_clientdata(i2c, wm8993);
1648f0fba2adSLiam Girdwood
1649bfea3abbSMark Brown for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
1650bfea3abbSMark Brown wm8993->supplies[i].supply = wm8993_supply_names[i];
1651bfea3abbSMark Brown
1652877fa971SSachin Kamat ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8993->supplies),
1653bfea3abbSMark Brown wm8993->supplies);
1654bfea3abbSMark Brown if (ret != 0) {
1655bfea3abbSMark Brown dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
16566dff9b3bSSachin Kamat return ret;
1657bfea3abbSMark Brown }
1658bfea3abbSMark Brown
1659bfea3abbSMark Brown ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
1660bfea3abbSMark Brown wm8993->supplies);
1661bfea3abbSMark Brown if (ret != 0) {
1662bfea3abbSMark Brown dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
16636dff9b3bSSachin Kamat return ret;
1664bfea3abbSMark Brown }
1665bfea3abbSMark Brown
1666bfea3abbSMark Brown ret = regmap_read(wm8993->regmap, WM8993_SOFTWARE_RESET, ®);
1667bfea3abbSMark Brown if (ret != 0) {
1668bfea3abbSMark Brown dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
1669bfea3abbSMark Brown goto err_enable;
1670bfea3abbSMark Brown }
1671bfea3abbSMark Brown
1672bfea3abbSMark Brown if (reg != 0x8993) {
1673bfea3abbSMark Brown dev_err(&i2c->dev, "Invalid ID register value %x\n", reg);
1674bfea3abbSMark Brown ret = -EINVAL;
1675bfea3abbSMark Brown goto err_enable;
1676bfea3abbSMark Brown }
1677bfea3abbSMark Brown
1678bfea3abbSMark Brown ret = regmap_write(wm8993->regmap, WM8993_SOFTWARE_RESET, 0xffff);
1679bfea3abbSMark Brown if (ret != 0)
1680bfea3abbSMark Brown goto err_enable;
1681bfea3abbSMark Brown
1682489773c2SMark Brown ret = regmap_register_patch(wm8993->regmap, wm8993_regmap_patch,
1683489773c2SMark Brown ARRAY_SIZE(wm8993_regmap_patch));
1684489773c2SMark Brown if (ret != 0)
1685489773c2SMark Brown dev_warn(wm8993->dev, "Failed to apply regmap patch: %d\n",
1686489773c2SMark Brown ret);
1687489773c2SMark Brown
1688164548d3SMark Brown if (i2c->irq) {
1689164548d3SMark Brown /* Put GPIO1 into interrupt mode (only GPIO1 can output IRQ) */
1690164548d3SMark Brown ret = regmap_update_bits(wm8993->regmap, WM8993_GPIO1,
1691164548d3SMark Brown WM8993_GPIO1_PD |
1692164548d3SMark Brown WM8993_GPIO1_SEL_MASK, 7);
1693164548d3SMark Brown if (ret != 0)
1694164548d3SMark Brown goto err_enable;
1695164548d3SMark Brown
1696164548d3SMark Brown ret = request_threaded_irq(i2c->irq, NULL, wm8993_irq,
1697164548d3SMark Brown IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
1698164548d3SMark Brown "wm8993", wm8993);
1699164548d3SMark Brown if (ret != 0)
1700164548d3SMark Brown goto err_enable;
1701164548d3SMark Brown
1702164548d3SMark Brown }
1703164548d3SMark Brown
1704bfea3abbSMark Brown regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
1705bfea3abbSMark Brown
1706bfea3abbSMark Brown regcache_cache_only(wm8993->regmap, true);
1707bfea3abbSMark Brown
170800a6941cSKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev,
170900a6941cSKuninori Morimoto &soc_component_dev_wm8993, &wm8993_dai, 1);
1710d0ad0af0SMark Brown if (ret != 0) {
1711d0ad0af0SMark Brown dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
1712164548d3SMark Brown goto err_irq;
1713d0ad0af0SMark Brown }
1714d0ad0af0SMark Brown
1715bfea3abbSMark Brown return 0;
1716d0ad0af0SMark Brown
1717164548d3SMark Brown err_irq:
1718164548d3SMark Brown if (i2c->irq)
1719164548d3SMark Brown free_irq(i2c->irq, wm8993);
1720bfea3abbSMark Brown err_enable:
1721bfea3abbSMark Brown regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
1722942c435bSMark Brown return ret;
1723942c435bSMark Brown }
1724942c435bSMark Brown
wm8993_i2c_remove(struct i2c_client * i2c)1725ed5c2f5fSUwe Kleine-König static void wm8993_i2c_remove(struct i2c_client *i2c)
1726942c435bSMark Brown {
1727164548d3SMark Brown struct wm8993_priv *wm8993 = i2c_get_clientdata(i2c);
1728d0ad0af0SMark Brown
1729164548d3SMark Brown if (i2c->irq)
1730164548d3SMark Brown free_irq(i2c->irq, wm8993);
1731bfea3abbSMark Brown regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
1732942c435bSMark Brown }
1733942c435bSMark Brown
1734942c435bSMark Brown static const struct i2c_device_id wm8993_i2c_id[] = {
1735942c435bSMark Brown { "wm8993", 0 },
1736942c435bSMark Brown { }
1737942c435bSMark Brown };
1738942c435bSMark Brown MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
1739942c435bSMark Brown
1740942c435bSMark Brown static struct i2c_driver wm8993_i2c_driver = {
1741942c435bSMark Brown .driver = {
1742091edccfSMark Brown .name = "wm8993",
1743942c435bSMark Brown },
17449abcd240SUwe Kleine-König .probe = wm8993_i2c_probe,
17457a79e94eSBill Pemberton .remove = wm8993_i2c_remove,
1746942c435bSMark Brown .id_table = wm8993_i2c_id,
1747942c435bSMark Brown };
1748942c435bSMark Brown
17497813561aSMark Brown module_i2c_driver(wm8993_i2c_driver);
1750942c435bSMark Brown
1751942c435bSMark Brown MODULE_DESCRIPTION("ASoC WM8993 driver");
1752942c435bSMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1753942c435bSMark Brown MODULE_LICENSE("GPL");
1754