xref: /openbmc/linux/sound/soc/codecs/wm9081.c (revision 1a37aa41)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
286ed3669SMark Brown /*
386ed3669SMark Brown  * wm9081.c  --  WM9081 ALSA SoC Audio driver
486ed3669SMark Brown  *
586ed3669SMark Brown  * Author: Mark Brown
686ed3669SMark Brown  *
7656baaebSMark Brown  * Copyright 2009-12 Wolfson Microelectronics plc
886ed3669SMark Brown  */
986ed3669SMark Brown 
1086ed3669SMark Brown #include <linux/module.h>
1186ed3669SMark Brown #include <linux/moduleparam.h>
1286ed3669SMark Brown #include <linux/init.h>
1386ed3669SMark Brown #include <linux/delay.h>
143ee845acSMark Brown #include <linux/device.h>
1586ed3669SMark Brown #include <linux/pm.h>
1686ed3669SMark Brown #include <linux/i2c.h>
177cfa467bSMark Brown #include <linux/regmap.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
1986ed3669SMark Brown #include <sound/core.h>
2086ed3669SMark Brown #include <sound/pcm.h>
2186ed3669SMark Brown #include <sound/pcm_params.h>
2286ed3669SMark Brown #include <sound/soc.h>
2386ed3669SMark Brown #include <sound/initval.h>
2486ed3669SMark Brown #include <sound/tlv.h>
2586ed3669SMark Brown 
2686ed3669SMark Brown #include <sound/wm9081.h>
2786ed3669SMark Brown #include "wm9081.h"
2886ed3669SMark Brown 
29c418a84aSAxel Lin static const struct reg_default wm9081_reg[] = {
307cfa467bSMark Brown 	{  2, 0x00B9 },     /* R2  - Analogue Lineout */
317cfa467bSMark Brown 	{  3, 0x00B9 },     /* R3  - Analogue Speaker PGA */
327cfa467bSMark Brown 	{  4, 0x0001 },     /* R4  - VMID Control */
337cfa467bSMark Brown 	{  5, 0x0068 },     /* R5  - Bias Control 1 */
347cfa467bSMark Brown 	{  7, 0x0000 },     /* R7  - Analogue Mixer */
357cfa467bSMark Brown 	{  8, 0x0000 },     /* R8  - Anti Pop Control */
367cfa467bSMark Brown 	{  9, 0x01DB },     /* R9  - Analogue Speaker 1 */
377cfa467bSMark Brown 	{ 10, 0x0018 },     /* R10 - Analogue Speaker 2 */
387cfa467bSMark Brown 	{ 11, 0x0180 },     /* R11 - Power Management */
397cfa467bSMark Brown 	{ 12, 0x0000 },     /* R12 - Clock Control 1 */
407cfa467bSMark Brown 	{ 13, 0x0038 },     /* R13 - Clock Control 2 */
417cfa467bSMark Brown 	{ 14, 0x4000 },     /* R14 - Clock Control 3 */
427cfa467bSMark Brown 	{ 16, 0x0000 },     /* R16 - FLL Control 1 */
437cfa467bSMark Brown 	{ 17, 0x0200 },     /* R17 - FLL Control 2 */
447cfa467bSMark Brown 	{ 18, 0x0000 },     /* R18 - FLL Control 3 */
457cfa467bSMark Brown 	{ 19, 0x0204 },     /* R19 - FLL Control 4 */
467cfa467bSMark Brown 	{ 20, 0x0000 },     /* R20 - FLL Control 5 */
477cfa467bSMark Brown 	{ 22, 0x0000 },     /* R22 - Audio Interface 1 */
487cfa467bSMark Brown 	{ 23, 0x0002 },     /* R23 - Audio Interface 2 */
497cfa467bSMark Brown 	{ 24, 0x0008 },     /* R24 - Audio Interface 3 */
507cfa467bSMark Brown 	{ 25, 0x0022 },     /* R25 - Audio Interface 4 */
517cfa467bSMark Brown 	{ 27, 0x0006 },     /* R27 - Interrupt Status Mask */
527cfa467bSMark Brown 	{ 28, 0x0000 },     /* R28 - Interrupt Polarity */
537cfa467bSMark Brown 	{ 29, 0x0000 },     /* R29 - Interrupt Control */
547cfa467bSMark Brown 	{ 30, 0x00C0 },     /* R30 - DAC Digital 1 */
557cfa467bSMark Brown 	{ 31, 0x0008 },     /* R31 - DAC Digital 2 */
567cfa467bSMark Brown 	{ 32, 0x09AF },     /* R32 - DRC 1 */
577cfa467bSMark Brown 	{ 33, 0x4201 },     /* R33 - DRC 2 */
587cfa467bSMark Brown 	{ 34, 0x0000 },     /* R34 - DRC 3 */
597cfa467bSMark Brown 	{ 35, 0x0000 },     /* R35 - DRC 4 */
607cfa467bSMark Brown 	{ 38, 0x0000 },     /* R38 - Write Sequencer 1 */
617cfa467bSMark Brown 	{ 39, 0x0000 },     /* R39 - Write Sequencer 2 */
627cfa467bSMark Brown 	{ 40, 0x0002 },     /* R40 - MW Slave 1 */
637cfa467bSMark Brown 	{ 42, 0x0000 },     /* R42 - EQ 1 */
647cfa467bSMark Brown 	{ 43, 0x0000 },     /* R43 - EQ 2 */
657cfa467bSMark Brown 	{ 44, 0x0FCA },     /* R44 - EQ 3 */
667cfa467bSMark Brown 	{ 45, 0x0400 },     /* R45 - EQ 4 */
677cfa467bSMark Brown 	{ 46, 0x00B8 },     /* R46 - EQ 5 */
687cfa467bSMark Brown 	{ 47, 0x1EB5 },     /* R47 - EQ 6 */
697cfa467bSMark Brown 	{ 48, 0xF145 },     /* R48 - EQ 7 */
707cfa467bSMark Brown 	{ 49, 0x0B75 },     /* R49 - EQ 8 */
717cfa467bSMark Brown 	{ 50, 0x01C5 },     /* R50 - EQ 9 */
727cfa467bSMark Brown 	{ 51, 0x169E },     /* R51 - EQ 10 */
737cfa467bSMark Brown 	{ 52, 0xF829 },     /* R52 - EQ 11 */
747cfa467bSMark Brown 	{ 53, 0x07AD },     /* R53 - EQ 12 */
757cfa467bSMark Brown 	{ 54, 0x1103 },     /* R54 - EQ 13 */
767cfa467bSMark Brown 	{ 55, 0x1C58 },     /* R55 - EQ 14 */
777cfa467bSMark Brown 	{ 56, 0xF373 },     /* R56 - EQ 15 */
787cfa467bSMark Brown 	{ 57, 0x0A54 },     /* R57 - EQ 16 */
797cfa467bSMark Brown 	{ 58, 0x0558 },     /* R58 - EQ 17 */
807cfa467bSMark Brown 	{ 59, 0x0564 },     /* R59 - EQ 18 */
817cfa467bSMark Brown 	{ 60, 0x0559 },     /* R60 - EQ 19 */
827cfa467bSMark Brown 	{ 61, 0x4000 },     /* R61 - EQ 20 */
8386ed3669SMark Brown };
8486ed3669SMark Brown 
8586ed3669SMark Brown static struct {
8686ed3669SMark Brown 	int ratio;
8786ed3669SMark Brown 	int clk_sys_rate;
8886ed3669SMark Brown } clk_sys_rates[] = {
8986ed3669SMark Brown 	{ 64,   0 },
9086ed3669SMark Brown 	{ 128,  1 },
9186ed3669SMark Brown 	{ 192,  2 },
9286ed3669SMark Brown 	{ 256,  3 },
9386ed3669SMark Brown 	{ 384,  4 },
9486ed3669SMark Brown 	{ 512,  5 },
9586ed3669SMark Brown 	{ 768,  6 },
9686ed3669SMark Brown 	{ 1024, 7 },
9786ed3669SMark Brown 	{ 1408, 8 },
9886ed3669SMark Brown 	{ 1536, 9 },
9986ed3669SMark Brown };
10086ed3669SMark Brown 
10186ed3669SMark Brown static struct {
10286ed3669SMark Brown 	int rate;
10386ed3669SMark Brown 	int sample_rate;
10486ed3669SMark Brown } sample_rates[] = {
10586ed3669SMark Brown 	{ 8000,  0  },
10686ed3669SMark Brown 	{ 11025, 1  },
10786ed3669SMark Brown 	{ 12000, 2  },
10886ed3669SMark Brown 	{ 16000, 3  },
10986ed3669SMark Brown 	{ 22050, 4  },
11086ed3669SMark Brown 	{ 24000, 5  },
11186ed3669SMark Brown 	{ 32000, 6  },
11286ed3669SMark Brown 	{ 44100, 7  },
11386ed3669SMark Brown 	{ 48000, 8  },
11486ed3669SMark Brown 	{ 88200, 9  },
11586ed3669SMark Brown 	{ 96000, 10 },
11686ed3669SMark Brown };
11786ed3669SMark Brown 
11886ed3669SMark Brown static struct {
11986ed3669SMark Brown 	int div; /* *10 due to .5s */
12086ed3669SMark Brown 	int bclk_div;
12186ed3669SMark Brown } bclk_divs[] = {
12286ed3669SMark Brown 	{ 10,  0  },
12386ed3669SMark Brown 	{ 15,  1  },
12486ed3669SMark Brown 	{ 20,  2  },
12586ed3669SMark Brown 	{ 30,  3  },
12686ed3669SMark Brown 	{ 40,  4  },
12786ed3669SMark Brown 	{ 50,  5  },
12886ed3669SMark Brown 	{ 55,  6  },
12986ed3669SMark Brown 	{ 60,  7  },
13086ed3669SMark Brown 	{ 80,  8  },
13186ed3669SMark Brown 	{ 100, 9  },
13286ed3669SMark Brown 	{ 110, 10 },
13386ed3669SMark Brown 	{ 120, 11 },
13486ed3669SMark Brown 	{ 160, 12 },
13586ed3669SMark Brown 	{ 200, 13 },
13686ed3669SMark Brown 	{ 220, 14 },
13786ed3669SMark Brown 	{ 240, 15 },
13886ed3669SMark Brown 	{ 250, 16 },
13986ed3669SMark Brown 	{ 300, 17 },
14086ed3669SMark Brown 	{ 320, 18 },
14186ed3669SMark Brown 	{ 440, 19 },
14286ed3669SMark Brown 	{ 480, 20 },
14386ed3669SMark Brown };
14486ed3669SMark Brown 
14586ed3669SMark Brown struct wm9081_priv {
1467cfa467bSMark Brown 	struct regmap *regmap;
14786ed3669SMark Brown 	int sysclk_source;
14886ed3669SMark Brown 	int mclk_rate;
14986ed3669SMark Brown 	int sysclk_rate;
15086ed3669SMark Brown 	int fs;
15186ed3669SMark Brown 	int bclk;
15286ed3669SMark Brown 	int master;
15386ed3669SMark Brown 	int fll_fref;
15486ed3669SMark Brown 	int fll_fout;
155e0026beaSMark Brown 	int tdm_width;
1564a5f7bdaSMark Brown 	struct wm9081_pdata pdata;
15786ed3669SMark Brown };
15886ed3669SMark Brown 
wm9081_volatile_register(struct device * dev,unsigned int reg)1597cfa467bSMark Brown static bool wm9081_volatile_register(struct device *dev, unsigned int reg)
16086ed3669SMark Brown {
16186ed3669SMark Brown 	switch (reg) {
1628d50e447SMark Brown 	case WM9081_SOFTWARE_RESET:
163f8faadb6SMark Brown 	case WM9081_INTERRUPT_STATUS:
1647cfa467bSMark Brown 		return true;
16586ed3669SMark Brown 	default:
1667cfa467bSMark Brown 		return false;
16786ed3669SMark Brown 	}
16886ed3669SMark Brown }
16986ed3669SMark Brown 
wm9081_readable_register(struct device * dev,unsigned int reg)1707cfa467bSMark Brown static bool wm9081_readable_register(struct device *dev, unsigned int reg)
17186ed3669SMark Brown {
1727cfa467bSMark Brown 	switch (reg) {
1737cfa467bSMark Brown 	case WM9081_SOFTWARE_RESET:
1747cfa467bSMark Brown 	case WM9081_ANALOGUE_LINEOUT:
1757cfa467bSMark Brown 	case WM9081_ANALOGUE_SPEAKER_PGA:
1767cfa467bSMark Brown 	case WM9081_VMID_CONTROL:
1777cfa467bSMark Brown 	case WM9081_BIAS_CONTROL_1:
1787cfa467bSMark Brown 	case WM9081_ANALOGUE_MIXER:
1797cfa467bSMark Brown 	case WM9081_ANTI_POP_CONTROL:
1807cfa467bSMark Brown 	case WM9081_ANALOGUE_SPEAKER_1:
1817cfa467bSMark Brown 	case WM9081_ANALOGUE_SPEAKER_2:
1827cfa467bSMark Brown 	case WM9081_POWER_MANAGEMENT:
1837cfa467bSMark Brown 	case WM9081_CLOCK_CONTROL_1:
1847cfa467bSMark Brown 	case WM9081_CLOCK_CONTROL_2:
1857cfa467bSMark Brown 	case WM9081_CLOCK_CONTROL_3:
1867cfa467bSMark Brown 	case WM9081_FLL_CONTROL_1:
1877cfa467bSMark Brown 	case WM9081_FLL_CONTROL_2:
1887cfa467bSMark Brown 	case WM9081_FLL_CONTROL_3:
1897cfa467bSMark Brown 	case WM9081_FLL_CONTROL_4:
1907cfa467bSMark Brown 	case WM9081_FLL_CONTROL_5:
1917cfa467bSMark Brown 	case WM9081_AUDIO_INTERFACE_1:
1927cfa467bSMark Brown 	case WM9081_AUDIO_INTERFACE_2:
1937cfa467bSMark Brown 	case WM9081_AUDIO_INTERFACE_3:
1947cfa467bSMark Brown 	case WM9081_AUDIO_INTERFACE_4:
1957cfa467bSMark Brown 	case WM9081_INTERRUPT_STATUS:
1967cfa467bSMark Brown 	case WM9081_INTERRUPT_STATUS_MASK:
1977cfa467bSMark Brown 	case WM9081_INTERRUPT_POLARITY:
1987cfa467bSMark Brown 	case WM9081_INTERRUPT_CONTROL:
1997cfa467bSMark Brown 	case WM9081_DAC_DIGITAL_1:
2007cfa467bSMark Brown 	case WM9081_DAC_DIGITAL_2:
2017cfa467bSMark Brown 	case WM9081_DRC_1:
2027cfa467bSMark Brown 	case WM9081_DRC_2:
2037cfa467bSMark Brown 	case WM9081_DRC_3:
2047cfa467bSMark Brown 	case WM9081_DRC_4:
2057cfa467bSMark Brown 	case WM9081_WRITE_SEQUENCER_1:
2067cfa467bSMark Brown 	case WM9081_WRITE_SEQUENCER_2:
2077cfa467bSMark Brown 	case WM9081_MW_SLAVE_1:
2087cfa467bSMark Brown 	case WM9081_EQ_1:
2097cfa467bSMark Brown 	case WM9081_EQ_2:
2107cfa467bSMark Brown 	case WM9081_EQ_3:
2117cfa467bSMark Brown 	case WM9081_EQ_4:
2127cfa467bSMark Brown 	case WM9081_EQ_5:
2137cfa467bSMark Brown 	case WM9081_EQ_6:
2147cfa467bSMark Brown 	case WM9081_EQ_7:
2157cfa467bSMark Brown 	case WM9081_EQ_8:
2167cfa467bSMark Brown 	case WM9081_EQ_9:
2177cfa467bSMark Brown 	case WM9081_EQ_10:
2187cfa467bSMark Brown 	case WM9081_EQ_11:
2197cfa467bSMark Brown 	case WM9081_EQ_12:
2207cfa467bSMark Brown 	case WM9081_EQ_13:
2217cfa467bSMark Brown 	case WM9081_EQ_14:
2227cfa467bSMark Brown 	case WM9081_EQ_15:
2237cfa467bSMark Brown 	case WM9081_EQ_16:
2247cfa467bSMark Brown 	case WM9081_EQ_17:
2257cfa467bSMark Brown 	case WM9081_EQ_18:
2267cfa467bSMark Brown 	case WM9081_EQ_19:
2277cfa467bSMark Brown 	case WM9081_EQ_20:
2287cfa467bSMark Brown 		return true;
2297cfa467bSMark Brown 	default:
2307cfa467bSMark Brown 		return false;
2317cfa467bSMark Brown 	}
2327cfa467bSMark Brown }
2337cfa467bSMark Brown 
wm9081_reset(struct regmap * map)2347cfa467bSMark Brown static int wm9081_reset(struct regmap *map)
2357cfa467bSMark Brown {
2367cfa467bSMark Brown 	return regmap_write(map, WM9081_SOFTWARE_RESET, 0x9081);
23786ed3669SMark Brown }
23886ed3669SMark Brown 
23986ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0);
24086ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(drc_out_tlv, -2250, 75, 0);
24186ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(drc_min_tlv, -1800, 600, 0);
2425d9a5e60SLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(drc_max_tlv,
24386ed3669SMark Brown 	0, 0, TLV_DB_SCALE_ITEM(1200, 0, 0),
24486ed3669SMark Brown 	1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
24586ed3669SMark Brown 	2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
2465d9a5e60SLars-Peter Clausen 	3, 3, TLV_DB_SCALE_ITEM(3600, 0, 0)
2475d9a5e60SLars-Peter Clausen );
24886ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(drc_qr_tlv, 1200, 600, 0);
24986ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(drc_startup_tlv, -300, 50, 0);
25086ed3669SMark Brown 
25186ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
25286ed3669SMark Brown 
25386ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(in_tlv, -600, 600, 0);
25486ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(dac_tlv, -7200, 75, 1);
25586ed3669SMark Brown static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
25686ed3669SMark Brown 
25786ed3669SMark Brown static const char *drc_high_text[] = {
25886ed3669SMark Brown 	"1",
25986ed3669SMark Brown 	"1/2",
26086ed3669SMark Brown 	"1/4",
26186ed3669SMark Brown 	"1/8",
26286ed3669SMark Brown 	"1/16",
26386ed3669SMark Brown 	"0",
26486ed3669SMark Brown };
26586ed3669SMark Brown 
266aedbfd96STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_high, WM9081_DRC_3, 3, drc_high_text);
26786ed3669SMark Brown 
26886ed3669SMark Brown static const char *drc_low_text[] = {
26986ed3669SMark Brown 	"1",
27086ed3669SMark Brown 	"1/2",
27186ed3669SMark Brown 	"1/4",
27286ed3669SMark Brown 	"1/8",
27386ed3669SMark Brown 	"0",
27486ed3669SMark Brown };
27586ed3669SMark Brown 
276aedbfd96STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_low, WM9081_DRC_3, 0, drc_low_text);
27786ed3669SMark Brown 
27886ed3669SMark Brown static const char *drc_atk_text[] = {
27986ed3669SMark Brown 	"181us",
28086ed3669SMark Brown 	"181us",
28186ed3669SMark Brown 	"363us",
28286ed3669SMark Brown 	"726us",
28386ed3669SMark Brown 	"1.45ms",
28486ed3669SMark Brown 	"2.9ms",
28586ed3669SMark Brown 	"5.8ms",
28686ed3669SMark Brown 	"11.6ms",
28786ed3669SMark Brown 	"23.2ms",
28886ed3669SMark Brown 	"46.4ms",
28986ed3669SMark Brown 	"92.8ms",
29086ed3669SMark Brown 	"185.6ms",
29186ed3669SMark Brown };
29286ed3669SMark Brown 
293aedbfd96STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_atk, WM9081_DRC_2, 12, drc_atk_text);
29486ed3669SMark Brown 
29586ed3669SMark Brown static const char *drc_dcy_text[] = {
29686ed3669SMark Brown 	"186ms",
29786ed3669SMark Brown 	"372ms",
29886ed3669SMark Brown 	"743ms",
29986ed3669SMark Brown 	"1.49s",
30086ed3669SMark Brown 	"2.97s",
30186ed3669SMark Brown 	"5.94s",
30286ed3669SMark Brown 	"11.89s",
30386ed3669SMark Brown 	"23.78s",
30486ed3669SMark Brown 	"47.56s",
30586ed3669SMark Brown };
30686ed3669SMark Brown 
307aedbfd96STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_dcy, WM9081_DRC_2, 8, drc_dcy_text);
30886ed3669SMark Brown 
30986ed3669SMark Brown static const char *drc_qr_dcy_text[] = {
31086ed3669SMark Brown 	"0.725ms",
31186ed3669SMark Brown 	"1.45ms",
31286ed3669SMark Brown 	"5.8ms",
31386ed3669SMark Brown };
31486ed3669SMark Brown 
315aedbfd96STakashi Iwai static SOC_ENUM_SINGLE_DECL(drc_qr_dcy, WM9081_DRC_2, 4, drc_qr_dcy_text);
31686ed3669SMark Brown 
31786ed3669SMark Brown static const char *dac_deemph_text[] = {
31886ed3669SMark Brown 	"None",
31986ed3669SMark Brown 	"32kHz",
32086ed3669SMark Brown 	"44.1kHz",
32186ed3669SMark Brown 	"48kHz",
32286ed3669SMark Brown };
32386ed3669SMark Brown 
324aedbfd96STakashi Iwai static SOC_ENUM_SINGLE_DECL(dac_deemph, WM9081_DAC_DIGITAL_2, 1,
325aedbfd96STakashi Iwai 			    dac_deemph_text);
32686ed3669SMark Brown 
32786ed3669SMark Brown static const char *speaker_mode_text[] = {
32886ed3669SMark Brown 	"Class D",
32986ed3669SMark Brown 	"Class AB",
33086ed3669SMark Brown };
33186ed3669SMark Brown 
332aedbfd96STakashi Iwai static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6,
333aedbfd96STakashi Iwai 			    speaker_mode_text);
33486ed3669SMark Brown 
speaker_mode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)33586ed3669SMark Brown static int speaker_mode_get(struct snd_kcontrol *kcontrol,
33686ed3669SMark Brown 			    struct snd_ctl_elem_value *ucontrol)
33786ed3669SMark Brown {
33848c33876SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
33986ed3669SMark Brown 	unsigned int reg;
34086ed3669SMark Brown 
3416d75dfc3SKuninori Morimoto 	reg = snd_soc_component_read(component, WM9081_ANALOGUE_SPEAKER_2);
34286ed3669SMark Brown 	if (reg & WM9081_SPK_MODE)
34339a79fe1STakashi Iwai 		ucontrol->value.enumerated.item[0] = 1;
34486ed3669SMark Brown 	else
34539a79fe1STakashi Iwai 		ucontrol->value.enumerated.item[0] = 0;
34686ed3669SMark Brown 
34786ed3669SMark Brown 	return 0;
34886ed3669SMark Brown }
34986ed3669SMark Brown 
35086ed3669SMark Brown /*
35186ed3669SMark Brown  * Stop any attempts to change speaker mode while the speaker is enabled.
35286ed3669SMark Brown  *
35325985edcSLucas De Marchi  * We also have some special anti-pop controls dependent on speaker
35486ed3669SMark Brown  * mode which must be changed along with the mode.
35586ed3669SMark Brown  */
speaker_mode_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)35686ed3669SMark Brown static int speaker_mode_put(struct snd_kcontrol *kcontrol,
35786ed3669SMark Brown 			    struct snd_ctl_elem_value *ucontrol)
35886ed3669SMark Brown {
35948c33876SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
3606d75dfc3SKuninori Morimoto 	unsigned int reg_pwr = snd_soc_component_read(component, WM9081_POWER_MANAGEMENT);
3616d75dfc3SKuninori Morimoto 	unsigned int reg2 = snd_soc_component_read(component, WM9081_ANALOGUE_SPEAKER_2);
36286ed3669SMark Brown 
36386ed3669SMark Brown 	/* Are we changing anything? */
36439a79fe1STakashi Iwai 	if (ucontrol->value.enumerated.item[0] ==
36586ed3669SMark Brown 	    ((reg2 & WM9081_SPK_MODE) != 0))
36686ed3669SMark Brown 		return 0;
36786ed3669SMark Brown 
36886ed3669SMark Brown 	/* Don't try to change modes while enabled */
36986ed3669SMark Brown 	if (reg_pwr & WM9081_SPK_ENA)
37086ed3669SMark Brown 		return -EINVAL;
37186ed3669SMark Brown 
37239a79fe1STakashi Iwai 	if (ucontrol->value.enumerated.item[0]) {
37386ed3669SMark Brown 		/* Class AB */
37486ed3669SMark Brown 		reg2 &= ~(WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL);
37586ed3669SMark Brown 		reg2 |= WM9081_SPK_MODE;
37686ed3669SMark Brown 	} else {
37786ed3669SMark Brown 		/* Class D */
37886ed3669SMark Brown 		reg2 |= WM9081_SPK_INV_MUTE | WM9081_OUT_SPK_CTRL;
37986ed3669SMark Brown 		reg2 &= ~WM9081_SPK_MODE;
38086ed3669SMark Brown 	}
38186ed3669SMark Brown 
38248c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_ANALOGUE_SPEAKER_2, reg2);
38386ed3669SMark Brown 
38486ed3669SMark Brown 	return 0;
38586ed3669SMark Brown }
38686ed3669SMark Brown 
38786ed3669SMark Brown static const struct snd_kcontrol_new wm9081_snd_controls[] = {
38886ed3669SMark Brown SOC_SINGLE_TLV("IN1 Volume", WM9081_ANALOGUE_MIXER, 1, 1, 1, in_tlv),
38986ed3669SMark Brown SOC_SINGLE_TLV("IN2 Volume", WM9081_ANALOGUE_MIXER, 3, 1, 1, in_tlv),
39086ed3669SMark Brown 
39186ed3669SMark Brown SOC_SINGLE_TLV("Playback Volume", WM9081_DAC_DIGITAL_1, 1, 96, 0, dac_tlv),
39286ed3669SMark Brown 
39386ed3669SMark Brown SOC_SINGLE("LINEOUT Switch", WM9081_ANALOGUE_LINEOUT, 7, 1, 1),
39486ed3669SMark Brown SOC_SINGLE("LINEOUT ZC Switch", WM9081_ANALOGUE_LINEOUT, 6, 1, 0),
39586ed3669SMark Brown SOC_SINGLE_TLV("LINEOUT Volume", WM9081_ANALOGUE_LINEOUT, 0, 63, 0, out_tlv),
39686ed3669SMark Brown 
39786ed3669SMark Brown SOC_SINGLE("DRC Switch", WM9081_DRC_1, 15, 1, 0),
39886ed3669SMark Brown SOC_ENUM("DRC High Slope", drc_high),
39986ed3669SMark Brown SOC_ENUM("DRC Low Slope", drc_low),
40086ed3669SMark Brown SOC_SINGLE_TLV("DRC Input Volume", WM9081_DRC_4, 5, 60, 1, drc_in_tlv),
40186ed3669SMark Brown SOC_SINGLE_TLV("DRC Output Volume", WM9081_DRC_4, 0, 30, 1, drc_out_tlv),
40286ed3669SMark Brown SOC_SINGLE_TLV("DRC Minimum Volume", WM9081_DRC_2, 2, 3, 1, drc_min_tlv),
40386ed3669SMark Brown SOC_SINGLE_TLV("DRC Maximum Volume", WM9081_DRC_2, 0, 3, 0, drc_max_tlv),
40486ed3669SMark Brown SOC_ENUM("DRC Attack", drc_atk),
40586ed3669SMark Brown SOC_ENUM("DRC Decay", drc_dcy),
40686ed3669SMark Brown SOC_SINGLE("DRC Quick Release Switch", WM9081_DRC_1, 2, 1, 0),
40786ed3669SMark Brown SOC_SINGLE_TLV("DRC Quick Release Volume", WM9081_DRC_2, 6, 3, 0, drc_qr_tlv),
40886ed3669SMark Brown SOC_ENUM("DRC Quick Release Decay", drc_qr_dcy),
40986ed3669SMark Brown SOC_SINGLE_TLV("DRC Startup Volume", WM9081_DRC_1, 6, 18, 0, drc_startup_tlv),
41086ed3669SMark Brown 
41186ed3669SMark Brown SOC_SINGLE("EQ Switch", WM9081_EQ_1, 0, 1, 0),
41286ed3669SMark Brown 
41386ed3669SMark Brown SOC_SINGLE("Speaker DC Volume", WM9081_ANALOGUE_SPEAKER_1, 3, 5, 0),
41486ed3669SMark Brown SOC_SINGLE("Speaker AC Volume", WM9081_ANALOGUE_SPEAKER_1, 0, 5, 0),
41586ed3669SMark Brown SOC_SINGLE("Speaker Switch", WM9081_ANALOGUE_SPEAKER_PGA, 7, 1, 1),
41686ed3669SMark Brown SOC_SINGLE("Speaker ZC Switch", WM9081_ANALOGUE_SPEAKER_PGA, 6, 1, 0),
41786ed3669SMark Brown SOC_SINGLE_TLV("Speaker Volume", WM9081_ANALOGUE_SPEAKER_PGA, 0, 63, 0,
41886ed3669SMark Brown 	       out_tlv),
41986ed3669SMark Brown SOC_ENUM("DAC Deemphasis", dac_deemph),
42086ed3669SMark Brown SOC_ENUM_EXT("Speaker Mode", speaker_mode, speaker_mode_get, speaker_mode_put),
42186ed3669SMark Brown };
42286ed3669SMark Brown 
42386ed3669SMark Brown static const struct snd_kcontrol_new wm9081_eq_controls[] = {
42486ed3669SMark Brown SOC_SINGLE_TLV("EQ1 Volume", WM9081_EQ_1, 11, 24, 0, eq_tlv),
42586ed3669SMark Brown SOC_SINGLE_TLV("EQ2 Volume", WM9081_EQ_1, 6, 24, 0, eq_tlv),
42686ed3669SMark Brown SOC_SINGLE_TLV("EQ3 Volume", WM9081_EQ_1, 1, 24, 0, eq_tlv),
42786ed3669SMark Brown SOC_SINGLE_TLV("EQ4 Volume", WM9081_EQ_2, 11, 24, 0, eq_tlv),
42886ed3669SMark Brown SOC_SINGLE_TLV("EQ5 Volume", WM9081_EQ_2, 6, 24, 0, eq_tlv),
42986ed3669SMark Brown };
43086ed3669SMark Brown 
43186ed3669SMark Brown static const struct snd_kcontrol_new mixer[] = {
43286ed3669SMark Brown SOC_DAPM_SINGLE("IN1 Switch", WM9081_ANALOGUE_MIXER, 0, 1, 0),
43386ed3669SMark Brown SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0),
43486ed3669SMark Brown SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0),
43586ed3669SMark Brown };
43686ed3669SMark Brown 
43786ed3669SMark Brown struct _fll_div {
43886ed3669SMark Brown 	u16 fll_fratio;
43986ed3669SMark Brown 	u16 fll_outdiv;
44086ed3669SMark Brown 	u16 fll_clk_ref_div;
44186ed3669SMark Brown 	u16 n;
44286ed3669SMark Brown 	u16 k;
44386ed3669SMark Brown };
44486ed3669SMark Brown 
44586ed3669SMark Brown /* The size in bits of the FLL divide multiplied by 10
44686ed3669SMark Brown  * to allow rounding later */
44786ed3669SMark Brown #define FIXED_FLL_SIZE ((1 << 16) * 10)
44886ed3669SMark Brown 
44986ed3669SMark Brown static struct {
45086ed3669SMark Brown 	unsigned int min;
45186ed3669SMark Brown 	unsigned int max;
45286ed3669SMark Brown 	u16 fll_fratio;
45386ed3669SMark Brown 	int ratio;
45486ed3669SMark Brown } fll_fratios[] = {
45586ed3669SMark Brown 	{       0,    64000, 4, 16 },
45686ed3669SMark Brown 	{   64000,   128000, 3,  8 },
45786ed3669SMark Brown 	{  128000,   256000, 2,  4 },
45886ed3669SMark Brown 	{  256000,  1000000, 1,  2 },
45986ed3669SMark Brown 	{ 1000000, 13500000, 0,  1 },
46086ed3669SMark Brown };
46186ed3669SMark Brown 
fll_factors(struct _fll_div * fll_div,unsigned int Fref,unsigned int Fout)46286ed3669SMark Brown static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
46386ed3669SMark Brown 		       unsigned int Fout)
46486ed3669SMark Brown {
46586ed3669SMark Brown 	u64 Kpart;
46686ed3669SMark Brown 	unsigned int K, Ndiv, Nmod, target;
46786ed3669SMark Brown 	unsigned int div;
46886ed3669SMark Brown 	int i;
46986ed3669SMark Brown 
47086ed3669SMark Brown 	/* Fref must be <=13.5MHz */
47186ed3669SMark Brown 	div = 1;
47286ed3669SMark Brown 	while ((Fref / div) > 13500000) {
47386ed3669SMark Brown 		div *= 2;
47486ed3669SMark Brown 
47586ed3669SMark Brown 		if (div > 8) {
47686ed3669SMark Brown 			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
47786ed3669SMark Brown 			       Fref);
47886ed3669SMark Brown 			return -EINVAL;
47986ed3669SMark Brown 		}
48086ed3669SMark Brown 	}
48186ed3669SMark Brown 	fll_div->fll_clk_ref_div = div / 2;
48286ed3669SMark Brown 
48386ed3669SMark Brown 	pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
48486ed3669SMark Brown 
48586ed3669SMark Brown 	/* Apply the division for our remaining calculations */
48686ed3669SMark Brown 	Fref /= div;
48786ed3669SMark Brown 
48886ed3669SMark Brown 	/* Fvco should be 90-100MHz; don't check the upper bound */
48986ed3669SMark Brown 	div = 0;
49086ed3669SMark Brown 	target = Fout * 2;
49186ed3669SMark Brown 	while (target < 90000000) {
49286ed3669SMark Brown 		div++;
49386ed3669SMark Brown 		target *= 2;
49486ed3669SMark Brown 		if (div > 7) {
49586ed3669SMark Brown 			pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
49686ed3669SMark Brown 			       Fout);
49786ed3669SMark Brown 			return -EINVAL;
49886ed3669SMark Brown 		}
49986ed3669SMark Brown 	}
50086ed3669SMark Brown 	fll_div->fll_outdiv = div;
50186ed3669SMark Brown 
50286ed3669SMark Brown 	pr_debug("Fvco=%dHz\n", target);
50386ed3669SMark Brown 
50425985edcSLucas De Marchi 	/* Find an appropriate FLL_FRATIO and factor it out of the target */
50586ed3669SMark Brown 	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
50686ed3669SMark Brown 		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
50786ed3669SMark Brown 			fll_div->fll_fratio = fll_fratios[i].fll_fratio;
50886ed3669SMark Brown 			target /= fll_fratios[i].ratio;
50986ed3669SMark Brown 			break;
51086ed3669SMark Brown 		}
51186ed3669SMark Brown 	}
51286ed3669SMark Brown 	if (i == ARRAY_SIZE(fll_fratios)) {
51386ed3669SMark Brown 		pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
51486ed3669SMark Brown 		return -EINVAL;
51586ed3669SMark Brown 	}
51686ed3669SMark Brown 
51786ed3669SMark Brown 	/* Now, calculate N.K */
51886ed3669SMark Brown 	Ndiv = target / Fref;
51986ed3669SMark Brown 
52086ed3669SMark Brown 	fll_div->n = Ndiv;
52186ed3669SMark Brown 	Nmod = target % Fref;
52286ed3669SMark Brown 	pr_debug("Nmod=%d\n", Nmod);
52386ed3669SMark Brown 
52486ed3669SMark Brown 	/* Calculate fractional part - scale up so we can round. */
52586ed3669SMark Brown 	Kpart = FIXED_FLL_SIZE * (long long)Nmod;
52686ed3669SMark Brown 
52786ed3669SMark Brown 	do_div(Kpart, Fref);
52886ed3669SMark Brown 
52986ed3669SMark Brown 	K = Kpart & 0xFFFFFFFF;
53086ed3669SMark Brown 
53186ed3669SMark Brown 	if ((K % 10) >= 5)
53286ed3669SMark Brown 		K += 5;
53386ed3669SMark Brown 
53486ed3669SMark Brown 	/* Move down to proper range now rounding is done */
53586ed3669SMark Brown 	fll_div->k = K / 10;
53686ed3669SMark Brown 
53786ed3669SMark Brown 	pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
53886ed3669SMark Brown 		 fll_div->n, fll_div->k,
53986ed3669SMark Brown 		 fll_div->fll_fratio, fll_div->fll_outdiv,
54086ed3669SMark Brown 		 fll_div->fll_clk_ref_div);
54186ed3669SMark Brown 
54286ed3669SMark Brown 	return 0;
54386ed3669SMark Brown }
54486ed3669SMark Brown 
wm9081_set_fll(struct snd_soc_component * component,int fll_id,unsigned int Fref,unsigned int Fout)54548c33876SKuninori Morimoto static int wm9081_set_fll(struct snd_soc_component *component, int fll_id,
54686ed3669SMark Brown 			  unsigned int Fref, unsigned int Fout)
54786ed3669SMark Brown {
54848c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
54986ed3669SMark Brown 	u16 reg1, reg4, reg5;
55086ed3669SMark Brown 	struct _fll_div fll_div;
55186ed3669SMark Brown 	int ret;
55286ed3669SMark Brown 	int clk_sys_reg;
55386ed3669SMark Brown 
55486ed3669SMark Brown 	/* Any change? */
55586ed3669SMark Brown 	if (Fref == wm9081->fll_fref && Fout == wm9081->fll_fout)
55686ed3669SMark Brown 		return 0;
55786ed3669SMark Brown 
55886ed3669SMark Brown 	/* Disable the FLL */
55986ed3669SMark Brown 	if (Fout == 0) {
56048c33876SKuninori Morimoto 		dev_dbg(component->dev, "FLL disabled\n");
56186ed3669SMark Brown 		wm9081->fll_fref = 0;
56286ed3669SMark Brown 		wm9081->fll_fout = 0;
56386ed3669SMark Brown 
56486ed3669SMark Brown 		return 0;
56586ed3669SMark Brown 	}
56686ed3669SMark Brown 
56786ed3669SMark Brown 	ret = fll_factors(&fll_div, Fref, Fout);
56886ed3669SMark Brown 	if (ret != 0)
56986ed3669SMark Brown 		return ret;
57086ed3669SMark Brown 
5716d75dfc3SKuninori Morimoto 	reg5 = snd_soc_component_read(component, WM9081_FLL_CONTROL_5);
57286ed3669SMark Brown 	reg5 &= ~WM9081_FLL_CLK_SRC_MASK;
57386ed3669SMark Brown 
57486ed3669SMark Brown 	switch (fll_id) {
57586ed3669SMark Brown 	case WM9081_SYSCLK_FLL_MCLK:
57686ed3669SMark Brown 		reg5 |= 0x1;
57786ed3669SMark Brown 		break;
57886ed3669SMark Brown 
57986ed3669SMark Brown 	default:
58048c33876SKuninori Morimoto 		dev_err(component->dev, "Unknown FLL ID %d\n", fll_id);
58186ed3669SMark Brown 		return -EINVAL;
58286ed3669SMark Brown 	}
58386ed3669SMark Brown 
58486ed3669SMark Brown 	/* Disable CLK_SYS while we reconfigure */
5856d75dfc3SKuninori Morimoto 	clk_sys_reg = snd_soc_component_read(component, WM9081_CLOCK_CONTROL_3);
58686ed3669SMark Brown 	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
58748c33876SKuninori Morimoto 		snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3,
58886ed3669SMark Brown 			     clk_sys_reg & ~WM9081_CLK_SYS_ENA);
58986ed3669SMark Brown 
59086ed3669SMark Brown 	/* Any FLL configuration change requires that the FLL be
59186ed3669SMark Brown 	 * disabled first. */
5926d75dfc3SKuninori Morimoto 	reg1 = snd_soc_component_read(component, WM9081_FLL_CONTROL_1);
59386ed3669SMark Brown 	reg1 &= ~WM9081_FLL_ENA;
59448c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1);
59586ed3669SMark Brown 
59686ed3669SMark Brown 	/* Apply the configuration */
59786ed3669SMark Brown 	if (fll_div.k)
59886ed3669SMark Brown 		reg1 |= WM9081_FLL_FRAC_MASK;
59986ed3669SMark Brown 	else
60086ed3669SMark Brown 		reg1 &= ~WM9081_FLL_FRAC_MASK;
60148c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1);
60286ed3669SMark Brown 
60348c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_FLL_CONTROL_2,
60486ed3669SMark Brown 		     (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) |
60586ed3669SMark Brown 		     (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT));
60648c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_FLL_CONTROL_3, fll_div.k);
60786ed3669SMark Brown 
6086d75dfc3SKuninori Morimoto 	reg4 = snd_soc_component_read(component, WM9081_FLL_CONTROL_4);
60986ed3669SMark Brown 	reg4 &= ~WM9081_FLL_N_MASK;
61086ed3669SMark Brown 	reg4 |= fll_div.n << WM9081_FLL_N_SHIFT;
61148c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_FLL_CONTROL_4, reg4);
61286ed3669SMark Brown 
61386ed3669SMark Brown 	reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK;
61486ed3669SMark Brown 	reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
61548c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_FLL_CONTROL_5, reg5);
61686ed3669SMark Brown 
617249c5156SMario Becroft 	/* Set gain to the recommended value */
61848c33876SKuninori Morimoto 	snd_soc_component_update_bits(component, WM9081_FLL_CONTROL_4,
619249c5156SMario Becroft 			    WM9081_FLL_GAIN_MASK, 0);
620249c5156SMario Becroft 
62186ed3669SMark Brown 	/* Enable the FLL */
62248c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
62386ed3669SMark Brown 
62486ed3669SMark Brown 	/* Then bring CLK_SYS up again if it was disabled */
62586ed3669SMark Brown 	if (clk_sys_reg & WM9081_CLK_SYS_ENA)
62648c33876SKuninori Morimoto 		snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3, clk_sys_reg);
62786ed3669SMark Brown 
62848c33876SKuninori Morimoto 	dev_dbg(component->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout);
62986ed3669SMark Brown 
63086ed3669SMark Brown 	wm9081->fll_fref = Fref;
63186ed3669SMark Brown 	wm9081->fll_fout = Fout;
63286ed3669SMark Brown 
63386ed3669SMark Brown 	return 0;
63486ed3669SMark Brown }
63586ed3669SMark Brown 
configure_clock(struct snd_soc_component * component)63648c33876SKuninori Morimoto static int configure_clock(struct snd_soc_component *component)
63786ed3669SMark Brown {
63848c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
63986ed3669SMark Brown 	int new_sysclk, i, target;
64086ed3669SMark Brown 	unsigned int reg;
64186ed3669SMark Brown 	int ret = 0;
64286ed3669SMark Brown 	int mclkdiv = 0;
64386ed3669SMark Brown 	int fll = 0;
64486ed3669SMark Brown 
64586ed3669SMark Brown 	switch (wm9081->sysclk_source) {
64686ed3669SMark Brown 	case WM9081_SYSCLK_MCLK:
64786ed3669SMark Brown 		if (wm9081->mclk_rate > 12225000) {
64886ed3669SMark Brown 			mclkdiv = 1;
64986ed3669SMark Brown 			wm9081->sysclk_rate = wm9081->mclk_rate / 2;
65086ed3669SMark Brown 		} else {
65186ed3669SMark Brown 			wm9081->sysclk_rate = wm9081->mclk_rate;
65286ed3669SMark Brown 		}
65348c33876SKuninori Morimoto 		wm9081_set_fll(component, WM9081_SYSCLK_FLL_MCLK, 0, 0);
65486ed3669SMark Brown 		break;
65586ed3669SMark Brown 
65686ed3669SMark Brown 	case WM9081_SYSCLK_FLL_MCLK:
65786ed3669SMark Brown 		/* If we have a sample rate calculate a CLK_SYS that
65886ed3669SMark Brown 		 * gives us a suitable DAC configuration, plus BCLK.
65986ed3669SMark Brown 		 * Ideally we would check to see if we can clock
66086ed3669SMark Brown 		 * directly from MCLK and only use the FLL if this is
66186ed3669SMark Brown 		 * not the case, though care must be taken with free
66286ed3669SMark Brown 		 * running mode.
66386ed3669SMark Brown 		 */
66486ed3669SMark Brown 		if (wm9081->master && wm9081->bclk) {
66586ed3669SMark Brown 			/* Make sure we can generate CLK_SYS and BCLK
66686ed3669SMark Brown 			 * and that we've got 3MHz for optimal
66786ed3669SMark Brown 			 * performance. */
66886ed3669SMark Brown 			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
66986ed3669SMark Brown 				target = wm9081->fs * clk_sys_rates[i].ratio;
6700154724dSMark Brown 				new_sysclk = target;
67186ed3669SMark Brown 				if (target >= wm9081->bclk &&
67286ed3669SMark Brown 				    target > 3000000)
6730154724dSMark Brown 					break;
67486ed3669SMark Brown 			}
6754b75e947SMark Brown 
6764b75e947SMark Brown 			if (i == ARRAY_SIZE(clk_sys_rates))
6774b75e947SMark Brown 				return -EINVAL;
6784b75e947SMark Brown 
67986ed3669SMark Brown 		} else if (wm9081->fs) {
68086ed3669SMark Brown 			for (i = 0; i < ARRAY_SIZE(clk_sys_rates); i++) {
68186ed3669SMark Brown 				new_sysclk = clk_sys_rates[i].ratio
68286ed3669SMark Brown 					* wm9081->fs;
68386ed3669SMark Brown 				if (new_sysclk > 3000000)
68486ed3669SMark Brown 					break;
68586ed3669SMark Brown 			}
6864b75e947SMark Brown 
6874b75e947SMark Brown 			if (i == ARRAY_SIZE(clk_sys_rates))
6884b75e947SMark Brown 				return -EINVAL;
6894b75e947SMark Brown 
69086ed3669SMark Brown 		} else {
69186ed3669SMark Brown 			new_sysclk = 12288000;
69286ed3669SMark Brown 		}
69386ed3669SMark Brown 
69448c33876SKuninori Morimoto 		ret = wm9081_set_fll(component, WM9081_SYSCLK_FLL_MCLK,
69586ed3669SMark Brown 				     wm9081->mclk_rate, new_sysclk);
69686ed3669SMark Brown 		if (ret == 0) {
69786ed3669SMark Brown 			wm9081->sysclk_rate = new_sysclk;
69886ed3669SMark Brown 
69986ed3669SMark Brown 			/* Switch SYSCLK over to FLL */
70086ed3669SMark Brown 			fll = 1;
70186ed3669SMark Brown 		} else {
70286ed3669SMark Brown 			wm9081->sysclk_rate = wm9081->mclk_rate;
70386ed3669SMark Brown 		}
70486ed3669SMark Brown 		break;
70586ed3669SMark Brown 
70686ed3669SMark Brown 	default:
70786ed3669SMark Brown 		return -EINVAL;
70886ed3669SMark Brown 	}
70986ed3669SMark Brown 
7106d75dfc3SKuninori Morimoto 	reg = snd_soc_component_read(component, WM9081_CLOCK_CONTROL_1);
71186ed3669SMark Brown 	if (mclkdiv)
71286ed3669SMark Brown 		reg |= WM9081_MCLKDIV2;
71386ed3669SMark Brown 	else
71486ed3669SMark Brown 		reg &= ~WM9081_MCLKDIV2;
71548c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_1, reg);
71686ed3669SMark Brown 
7176d75dfc3SKuninori Morimoto 	reg = snd_soc_component_read(component, WM9081_CLOCK_CONTROL_3);
71886ed3669SMark Brown 	if (fll)
71986ed3669SMark Brown 		reg |= WM9081_CLK_SRC_SEL;
72086ed3669SMark Brown 	else
72186ed3669SMark Brown 		reg &= ~WM9081_CLK_SRC_SEL;
72248c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_3, reg);
72386ed3669SMark Brown 
72448c33876SKuninori Morimoto 	dev_dbg(component->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate);
72586ed3669SMark Brown 
72686ed3669SMark Brown 	return ret;
72786ed3669SMark Brown }
72886ed3669SMark Brown 
clk_sys_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)72986ed3669SMark Brown static int clk_sys_event(struct snd_soc_dapm_widget *w,
73086ed3669SMark Brown 			 struct snd_kcontrol *kcontrol, int event)
73186ed3669SMark Brown {
73248c33876SKuninori Morimoto 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
73348c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
73486ed3669SMark Brown 
73586ed3669SMark Brown 	/* This should be done on init() for bypass paths */
73686ed3669SMark Brown 	switch (wm9081->sysclk_source) {
73786ed3669SMark Brown 	case WM9081_SYSCLK_MCLK:
73848c33876SKuninori Morimoto 		dev_dbg(component->dev, "Using %dHz MCLK\n", wm9081->mclk_rate);
73986ed3669SMark Brown 		break;
74086ed3669SMark Brown 	case WM9081_SYSCLK_FLL_MCLK:
74148c33876SKuninori Morimoto 		dev_dbg(component->dev, "Using %dHz MCLK with FLL\n",
74286ed3669SMark Brown 			wm9081->mclk_rate);
74386ed3669SMark Brown 		break;
74486ed3669SMark Brown 	default:
74548c33876SKuninori Morimoto 		dev_err(component->dev, "System clock not configured\n");
74686ed3669SMark Brown 		return -EINVAL;
74786ed3669SMark Brown 	}
74886ed3669SMark Brown 
74986ed3669SMark Brown 	switch (event) {
75086ed3669SMark Brown 	case SND_SOC_DAPM_PRE_PMU:
75148c33876SKuninori Morimoto 		configure_clock(component);
75286ed3669SMark Brown 		break;
75386ed3669SMark Brown 
75486ed3669SMark Brown 	case SND_SOC_DAPM_POST_PMD:
75586ed3669SMark Brown 		/* Disable the FLL if it's running */
75648c33876SKuninori Morimoto 		wm9081_set_fll(component, 0, 0, 0);
75786ed3669SMark Brown 		break;
75886ed3669SMark Brown 	}
75986ed3669SMark Brown 
76086ed3669SMark Brown 	return 0;
76186ed3669SMark Brown }
76286ed3669SMark Brown 
76386ed3669SMark Brown static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = {
76486ed3669SMark Brown SND_SOC_DAPM_INPUT("IN1"),
76586ed3669SMark Brown SND_SOC_DAPM_INPUT("IN2"),
76686ed3669SMark Brown 
7670fb7d0c3SMark Brown SND_SOC_DAPM_DAC("DAC", NULL, WM9081_POWER_MANAGEMENT, 0, 0),
76886ed3669SMark Brown 
76986ed3669SMark Brown SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
77086ed3669SMark Brown 			     mixer, ARRAY_SIZE(mixer)),
77186ed3669SMark Brown 
77286ed3669SMark Brown SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0),
77386ed3669SMark Brown 
774378a90f4SMark Brown SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0),
7754e8e78e3SMark Brown SND_SOC_DAPM_OUT_DRV("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0),
77686ed3669SMark Brown 
77786ed3669SMark Brown SND_SOC_DAPM_OUTPUT("LINEOUT"),
77886ed3669SMark Brown SND_SOC_DAPM_OUTPUT("SPKN"),
77986ed3669SMark Brown SND_SOC_DAPM_OUTPUT("SPKP"),
78086ed3669SMark Brown 
78186ed3669SMark Brown SND_SOC_DAPM_SUPPLY("CLK_SYS", WM9081_CLOCK_CONTROL_3, 0, 0, clk_sys_event,
78286ed3669SMark Brown 		    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
78386ed3669SMark Brown SND_SOC_DAPM_SUPPLY("CLK_DSP", WM9081_CLOCK_CONTROL_3, 1, 0, NULL, 0),
78486ed3669SMark Brown SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0),
785a04e0c86SMark Brown SND_SOC_DAPM_SUPPLY("TSENSE", WM9081_POWER_MANAGEMENT, 7, 0, NULL, 0),
78686ed3669SMark Brown };
78786ed3669SMark Brown 
78886ed3669SMark Brown 
789149c7b44SMark Brown static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
79086ed3669SMark Brown 	{ "DAC", NULL, "CLK_SYS" },
79186ed3669SMark Brown 	{ "DAC", NULL, "CLK_DSP" },
7920fb7d0c3SMark Brown 	{ "DAC", NULL, "AIF" },
79386ed3669SMark Brown 
79486ed3669SMark Brown 	{ "Mixer", "IN1 Switch", "IN1" },
79586ed3669SMark Brown 	{ "Mixer", "IN2 Switch", "IN2" },
79686ed3669SMark Brown 	{ "Mixer", "Playback Switch", "DAC" },
79786ed3669SMark Brown 
79886ed3669SMark Brown 	{ "LINEOUT PGA", NULL, "Mixer" },
79986ed3669SMark Brown 	{ "LINEOUT PGA", NULL, "TOCLK" },
80086ed3669SMark Brown 	{ "LINEOUT PGA", NULL, "CLK_SYS" },
80186ed3669SMark Brown 
80286ed3669SMark Brown 	{ "LINEOUT", NULL, "LINEOUT PGA" },
80386ed3669SMark Brown 
80486ed3669SMark Brown 	{ "Speaker PGA", NULL, "Mixer" },
80586ed3669SMark Brown 	{ "Speaker PGA", NULL, "TOCLK" },
80686ed3669SMark Brown 	{ "Speaker PGA", NULL, "CLK_SYS" },
80786ed3669SMark Brown 
808378a90f4SMark Brown 	{ "Speaker", NULL, "Speaker PGA" },
809a04e0c86SMark Brown 	{ "Speaker", NULL, "TSENSE" },
810378a90f4SMark Brown 
811378a90f4SMark Brown 	{ "SPKN", NULL, "Speaker" },
812378a90f4SMark Brown 	{ "SPKP", NULL, "Speaker" },
81386ed3669SMark Brown };
81486ed3669SMark Brown 
wm9081_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)81548c33876SKuninori Morimoto static int wm9081_set_bias_level(struct snd_soc_component *component,
81686ed3669SMark Brown 				 enum snd_soc_bias_level level)
81786ed3669SMark Brown {
81848c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
819da157875SMark Brown 
82086ed3669SMark Brown 	switch (level) {
82186ed3669SMark Brown 	case SND_SOC_BIAS_ON:
82286ed3669SMark Brown 		break;
82386ed3669SMark Brown 
82486ed3669SMark Brown 	case SND_SOC_BIAS_PREPARE:
82586ed3669SMark Brown 		/* VMID=2*40k */
82648c33876SKuninori Morimoto 		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
827b4027358SAxel Lin 				    WM9081_VMID_SEL_MASK, 0x2);
82886ed3669SMark Brown 
82986ed3669SMark Brown 		/* Normal bias current */
83048c33876SKuninori Morimoto 		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
831b4027358SAxel Lin 				    WM9081_STBY_BIAS_ENA, 0);
83286ed3669SMark Brown 		break;
83386ed3669SMark Brown 
83486ed3669SMark Brown 	case SND_SOC_BIAS_STANDBY:
83586ed3669SMark Brown 		/* Initial cold start */
83648c33876SKuninori Morimoto 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
837da157875SMark Brown 			regcache_cache_only(wm9081->regmap, false);
838da157875SMark Brown 			regcache_sync(wm9081->regmap);
839da157875SMark Brown 
84086ed3669SMark Brown 			/* Disable LINEOUT discharge */
84148c33876SKuninori Morimoto 			snd_soc_component_update_bits(component, WM9081_ANTI_POP_CONTROL,
842b4027358SAxel Lin 					    WM9081_LINEOUT_DISCH, 0);
84386ed3669SMark Brown 
84486ed3669SMark Brown 			/* Select startup bias source */
84548c33876SKuninori Morimoto 			snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
846b4027358SAxel Lin 					    WM9081_BIAS_SRC | WM9081_BIAS_ENA,
847b4027358SAxel Lin 					    WM9081_BIAS_SRC | WM9081_BIAS_ENA);
84886ed3669SMark Brown 
84986ed3669SMark Brown 			/* VMID 2*4k; Soft VMID ramp enable */
85048c33876SKuninori Morimoto 			snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
851b4027358SAxel Lin 					    WM9081_VMID_RAMP |
852b4027358SAxel Lin 					    WM9081_VMID_SEL_MASK,
853b4027358SAxel Lin 					    WM9081_VMID_RAMP | 0x6);
85486ed3669SMark Brown 
85586ed3669SMark Brown 			mdelay(100);
85686ed3669SMark Brown 
85786ed3669SMark Brown 			/* Normal bias enable & soft start off */
85848c33876SKuninori Morimoto 			snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
859b4027358SAxel Lin 					    WM9081_VMID_RAMP, 0);
86086ed3669SMark Brown 
86186ed3669SMark Brown 			/* Standard bias source */
86248c33876SKuninori Morimoto 			snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
863b4027358SAxel Lin 					    WM9081_BIAS_SRC, 0);
86486ed3669SMark Brown 		}
86586ed3669SMark Brown 
86686ed3669SMark Brown 		/* VMID 2*240k */
86748c33876SKuninori Morimoto 		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
868b4027358SAxel Lin 				    WM9081_VMID_SEL_MASK, 0x04);
86986ed3669SMark Brown 
87086ed3669SMark Brown 		/* Standby bias current on */
87148c33876SKuninori Morimoto 		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
872b4027358SAxel Lin 				    WM9081_STBY_BIAS_ENA,
873b4027358SAxel Lin 				    WM9081_STBY_BIAS_ENA);
87486ed3669SMark Brown 		break;
87586ed3669SMark Brown 
87686ed3669SMark Brown 	case SND_SOC_BIAS_OFF:
877adf46362SAxel Lin 		/* Startup bias source and disable bias */
87848c33876SKuninori Morimoto 		snd_soc_component_update_bits(component, WM9081_BIAS_CONTROL_1,
879b4027358SAxel Lin 				    WM9081_BIAS_SRC | WM9081_BIAS_ENA,
880b4027358SAxel Lin 				    WM9081_BIAS_SRC);
88186ed3669SMark Brown 
882adf46362SAxel Lin 		/* Disable VMID with soft ramping */
88348c33876SKuninori Morimoto 		snd_soc_component_update_bits(component, WM9081_VMID_CONTROL,
884b4027358SAxel Lin 				    WM9081_VMID_RAMP | WM9081_VMID_SEL_MASK,
885b4027358SAxel Lin 				    WM9081_VMID_RAMP);
88686ed3669SMark Brown 
88786ed3669SMark Brown 		/* Actively discharge LINEOUT */
88848c33876SKuninori Morimoto 		snd_soc_component_update_bits(component, WM9081_ANTI_POP_CONTROL,
889b4027358SAxel Lin 				    WM9081_LINEOUT_DISCH,
890b4027358SAxel Lin 				    WM9081_LINEOUT_DISCH);
891da157875SMark Brown 
892da157875SMark Brown 		regcache_cache_only(wm9081->regmap, true);
89386ed3669SMark Brown 		break;
89486ed3669SMark Brown 	}
89586ed3669SMark Brown 
89686ed3669SMark Brown 	return 0;
89786ed3669SMark Brown }
89886ed3669SMark Brown 
wm9081_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)89986ed3669SMark Brown static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
90086ed3669SMark Brown 			      unsigned int fmt)
90186ed3669SMark Brown {
90248c33876SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
90348c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
9046d75dfc3SKuninori Morimoto 	unsigned int aif2 = snd_soc_component_read(component, WM9081_AUDIO_INTERFACE_2);
90586ed3669SMark Brown 
90686ed3669SMark Brown 	aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
90786ed3669SMark Brown 		  WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
90886ed3669SMark Brown 
90986ed3669SMark Brown 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
91086ed3669SMark Brown 	case SND_SOC_DAIFMT_CBS_CFS:
91186ed3669SMark Brown 		wm9081->master = 0;
91286ed3669SMark Brown 		break;
91386ed3669SMark Brown 	case SND_SOC_DAIFMT_CBS_CFM:
91486ed3669SMark Brown 		aif2 |= WM9081_LRCLK_DIR;
91586ed3669SMark Brown 		wm9081->master = 1;
91686ed3669SMark Brown 		break;
91786ed3669SMark Brown 	case SND_SOC_DAIFMT_CBM_CFS:
91886ed3669SMark Brown 		aif2 |= WM9081_BCLK_DIR;
91986ed3669SMark Brown 		wm9081->master = 1;
92086ed3669SMark Brown 		break;
92186ed3669SMark Brown 	case SND_SOC_DAIFMT_CBM_CFM:
92286ed3669SMark Brown 		aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR;
92386ed3669SMark Brown 		wm9081->master = 1;
92486ed3669SMark Brown 		break;
92586ed3669SMark Brown 	default:
92686ed3669SMark Brown 		return -EINVAL;
92786ed3669SMark Brown 	}
92886ed3669SMark Brown 
92986ed3669SMark Brown 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
93086ed3669SMark Brown 	case SND_SOC_DAIFMT_DSP_B:
93186ed3669SMark Brown 		aif2 |= WM9081_AIF_LRCLK_INV;
9323e146b55SGustavo A. R. Silva 		fallthrough;
93386ed3669SMark Brown 	case SND_SOC_DAIFMT_DSP_A:
93486ed3669SMark Brown 		aif2 |= 0x3;
93586ed3669SMark Brown 		break;
93686ed3669SMark Brown 	case SND_SOC_DAIFMT_I2S:
93786ed3669SMark Brown 		aif2 |= 0x2;
93886ed3669SMark Brown 		break;
93986ed3669SMark Brown 	case SND_SOC_DAIFMT_RIGHT_J:
94086ed3669SMark Brown 		break;
94186ed3669SMark Brown 	case SND_SOC_DAIFMT_LEFT_J:
94286ed3669SMark Brown 		aif2 |= 0x1;
94386ed3669SMark Brown 		break;
94486ed3669SMark Brown 	default:
94586ed3669SMark Brown 		return -EINVAL;
94686ed3669SMark Brown 	}
94786ed3669SMark Brown 
94886ed3669SMark Brown 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
94986ed3669SMark Brown 	case SND_SOC_DAIFMT_DSP_A:
95086ed3669SMark Brown 	case SND_SOC_DAIFMT_DSP_B:
95186ed3669SMark Brown 		/* frame inversion not valid for DSP modes */
95286ed3669SMark Brown 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
95386ed3669SMark Brown 		case SND_SOC_DAIFMT_NB_NF:
95486ed3669SMark Brown 			break;
95586ed3669SMark Brown 		case SND_SOC_DAIFMT_IB_NF:
95686ed3669SMark Brown 			aif2 |= WM9081_AIF_BCLK_INV;
95786ed3669SMark Brown 			break;
95886ed3669SMark Brown 		default:
95986ed3669SMark Brown 			return -EINVAL;
96086ed3669SMark Brown 		}
96186ed3669SMark Brown 		break;
96286ed3669SMark Brown 
96386ed3669SMark Brown 	case SND_SOC_DAIFMT_I2S:
96486ed3669SMark Brown 	case SND_SOC_DAIFMT_RIGHT_J:
96586ed3669SMark Brown 	case SND_SOC_DAIFMT_LEFT_J:
96686ed3669SMark Brown 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
96786ed3669SMark Brown 		case SND_SOC_DAIFMT_NB_NF:
96886ed3669SMark Brown 			break;
96986ed3669SMark Brown 		case SND_SOC_DAIFMT_IB_IF:
97086ed3669SMark Brown 			aif2 |= WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV;
97186ed3669SMark Brown 			break;
97286ed3669SMark Brown 		case SND_SOC_DAIFMT_IB_NF:
97386ed3669SMark Brown 			aif2 |= WM9081_AIF_BCLK_INV;
97486ed3669SMark Brown 			break;
97586ed3669SMark Brown 		case SND_SOC_DAIFMT_NB_IF:
97686ed3669SMark Brown 			aif2 |= WM9081_AIF_LRCLK_INV;
97786ed3669SMark Brown 			break;
97886ed3669SMark Brown 		default:
97986ed3669SMark Brown 			return -EINVAL;
98086ed3669SMark Brown 		}
98186ed3669SMark Brown 		break;
98286ed3669SMark Brown 	default:
98386ed3669SMark Brown 		return -EINVAL;
98486ed3669SMark Brown 	}
98586ed3669SMark Brown 
98648c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_2, aif2);
98786ed3669SMark Brown 
98886ed3669SMark Brown 	return 0;
98986ed3669SMark Brown }
99086ed3669SMark Brown 
wm9081_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)99186ed3669SMark Brown static int wm9081_hw_params(struct snd_pcm_substream *substream,
99286ed3669SMark Brown 			    struct snd_pcm_hw_params *params,
99386ed3669SMark Brown 			    struct snd_soc_dai *dai)
99486ed3669SMark Brown {
99548c33876SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
99648c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
99786ed3669SMark Brown 	int ret, i, best, best_val, cur_val;
99886ed3669SMark Brown 	unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
99986ed3669SMark Brown 
10006d75dfc3SKuninori Morimoto 	clk_ctrl2 = snd_soc_component_read(component, WM9081_CLOCK_CONTROL_2);
100186ed3669SMark Brown 	clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK);
100286ed3669SMark Brown 
10036d75dfc3SKuninori Morimoto 	aif1 = snd_soc_component_read(component, WM9081_AUDIO_INTERFACE_1);
100486ed3669SMark Brown 
10056d75dfc3SKuninori Morimoto 	aif2 = snd_soc_component_read(component, WM9081_AUDIO_INTERFACE_2);
100686ed3669SMark Brown 	aif2 &= ~WM9081_AIF_WL_MASK;
100786ed3669SMark Brown 
10086d75dfc3SKuninori Morimoto 	aif3 = snd_soc_component_read(component, WM9081_AUDIO_INTERFACE_3);
100986ed3669SMark Brown 	aif3 &= ~WM9081_BCLK_DIV_MASK;
101086ed3669SMark Brown 
10116d75dfc3SKuninori Morimoto 	aif4 = snd_soc_component_read(component, WM9081_AUDIO_INTERFACE_4);
101286ed3669SMark Brown 	aif4 &= ~WM9081_LRCLK_RATE_MASK;
101386ed3669SMark Brown 
101486ed3669SMark Brown 	wm9081->fs = params_rate(params);
1015e0026beaSMark Brown 
1016e0026beaSMark Brown 	if (wm9081->tdm_width) {
1017e0026beaSMark Brown 		/* If TDM is set up then that fixes our BCLK. */
1018e0026beaSMark Brown 		int slots = ((aif1 & WM9081_AIFDAC_TDM_MODE_MASK) >>
1019e0026beaSMark Brown 			     WM9081_AIFDAC_TDM_MODE_SHIFT) + 1;
1020e0026beaSMark Brown 
1021e0026beaSMark Brown 		wm9081->bclk = wm9081->fs * wm9081->tdm_width * slots;
1022e0026beaSMark Brown 	} else {
1023e0026beaSMark Brown 		/* Otherwise work out a BCLK from the sample size */
102486ed3669SMark Brown 		wm9081->bclk = 2 * wm9081->fs;
1025e0026beaSMark Brown 
10269572696dSMark Brown 		switch (params_width(params)) {
10279572696dSMark Brown 		case 16:
102886ed3669SMark Brown 			wm9081->bclk *= 16;
102986ed3669SMark Brown 			break;
10309572696dSMark Brown 		case 20:
103186ed3669SMark Brown 			wm9081->bclk *= 20;
103286ed3669SMark Brown 			aif2 |= 0x4;
103386ed3669SMark Brown 			break;
10349572696dSMark Brown 		case 24:
103586ed3669SMark Brown 			wm9081->bclk *= 24;
103686ed3669SMark Brown 			aif2 |= 0x8;
103786ed3669SMark Brown 			break;
10389572696dSMark Brown 		case 32:
103986ed3669SMark Brown 			wm9081->bclk *= 32;
104086ed3669SMark Brown 			aif2 |= 0xc;
104186ed3669SMark Brown 			break;
104286ed3669SMark Brown 		default:
104386ed3669SMark Brown 			return -EINVAL;
104486ed3669SMark Brown 		}
104586ed3669SMark Brown 	}
104686ed3669SMark Brown 
104748c33876SKuninori Morimoto 	dev_dbg(component->dev, "Target BCLK is %dHz\n", wm9081->bclk);
104886ed3669SMark Brown 
104948c33876SKuninori Morimoto 	ret = configure_clock(component);
105086ed3669SMark Brown 	if (ret != 0)
105186ed3669SMark Brown 		return ret;
105286ed3669SMark Brown 
105386ed3669SMark Brown 	/* Select nearest CLK_SYS_RATE */
105486ed3669SMark Brown 	best = 0;
105586ed3669SMark Brown 	best_val = abs((wm9081->sysclk_rate / clk_sys_rates[0].ratio)
105686ed3669SMark Brown 		       - wm9081->fs);
105786ed3669SMark Brown 	for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
105886ed3669SMark Brown 		cur_val = abs((wm9081->sysclk_rate /
1059a419aef8SJoe Perches 			       clk_sys_rates[i].ratio) - wm9081->fs);
106086ed3669SMark Brown 		if (cur_val < best_val) {
106186ed3669SMark Brown 			best = i;
106286ed3669SMark Brown 			best_val = cur_val;
106386ed3669SMark Brown 		}
106486ed3669SMark Brown 	}
106548c33876SKuninori Morimoto 	dev_dbg(component->dev, "Selected CLK_SYS_RATIO of %d\n",
106686ed3669SMark Brown 		clk_sys_rates[best].ratio);
106786ed3669SMark Brown 	clk_ctrl2 |= (clk_sys_rates[best].clk_sys_rate
106886ed3669SMark Brown 		      << WM9081_CLK_SYS_RATE_SHIFT);
106986ed3669SMark Brown 
107086ed3669SMark Brown 	/* SAMPLE_RATE */
107186ed3669SMark Brown 	best = 0;
107286ed3669SMark Brown 	best_val = abs(wm9081->fs - sample_rates[0].rate);
107386ed3669SMark Brown 	for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
107486ed3669SMark Brown 		/* Closest match */
107586ed3669SMark Brown 		cur_val = abs(wm9081->fs - sample_rates[i].rate);
107686ed3669SMark Brown 		if (cur_val < best_val) {
107786ed3669SMark Brown 			best = i;
107886ed3669SMark Brown 			best_val = cur_val;
107986ed3669SMark Brown 		}
108086ed3669SMark Brown 	}
108148c33876SKuninori Morimoto 	dev_dbg(component->dev, "Selected SAMPLE_RATE of %dHz\n",
108286ed3669SMark Brown 		sample_rates[best].rate);
10830154724dSMark Brown 	clk_ctrl2 |= (sample_rates[best].sample_rate
10840154724dSMark Brown 			<< WM9081_SAMPLE_RATE_SHIFT);
108586ed3669SMark Brown 
108686ed3669SMark Brown 	/* BCLK_DIV */
108786ed3669SMark Brown 	best = 0;
108886ed3669SMark Brown 	best_val = INT_MAX;
108986ed3669SMark Brown 	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
109086ed3669SMark Brown 		cur_val = ((wm9081->sysclk_rate * 10) / bclk_divs[i].div)
109186ed3669SMark Brown 			- wm9081->bclk;
109286ed3669SMark Brown 		if (cur_val < 0) /* Table is sorted */
109386ed3669SMark Brown 			break;
109486ed3669SMark Brown 		if (cur_val < best_val) {
109586ed3669SMark Brown 			best = i;
109686ed3669SMark Brown 			best_val = cur_val;
109786ed3669SMark Brown 		}
109886ed3669SMark Brown 	}
109986ed3669SMark Brown 	wm9081->bclk = (wm9081->sysclk_rate * 10) / bclk_divs[best].div;
110048c33876SKuninori Morimoto 	dev_dbg(component->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
110186ed3669SMark Brown 		bclk_divs[best].div, wm9081->bclk);
110286ed3669SMark Brown 	aif3 |= bclk_divs[best].bclk_div;
110386ed3669SMark Brown 
110486ed3669SMark Brown 	/* LRCLK is a simple fraction of BCLK */
110548c33876SKuninori Morimoto 	dev_dbg(component->dev, "LRCLK_RATE is %d\n", wm9081->bclk / wm9081->fs);
110686ed3669SMark Brown 	aif4 |= wm9081->bclk / wm9081->fs;
110786ed3669SMark Brown 
110886ed3669SMark Brown 	/* Apply a ReTune Mobile configuration if it's in use */
11094a5f7bdaSMark Brown 	if (wm9081->pdata.num_retune_configs) {
11104a5f7bdaSMark Brown 		struct wm9081_pdata *pdata = &wm9081->pdata;
111186ed3669SMark Brown 		struct wm9081_retune_mobile_setting *s;
111286ed3669SMark Brown 		int eq1;
111386ed3669SMark Brown 
111486ed3669SMark Brown 		best = 0;
11154a5f7bdaSMark Brown 		best_val = abs(pdata->retune_configs[0].rate - wm9081->fs);
11164a5f7bdaSMark Brown 		for (i = 0; i < pdata->num_retune_configs; i++) {
11174a5f7bdaSMark Brown 			cur_val = abs(pdata->retune_configs[i].rate -
11184a5f7bdaSMark Brown 				      wm9081->fs);
111986ed3669SMark Brown 			if (cur_val < best_val) {
112086ed3669SMark Brown 				best_val = cur_val;
112186ed3669SMark Brown 				best = i;
112286ed3669SMark Brown 			}
112386ed3669SMark Brown 		}
11244a5f7bdaSMark Brown 		s = &pdata->retune_configs[best];
112586ed3669SMark Brown 
112648c33876SKuninori Morimoto 		dev_dbg(component->dev, "ReTune Mobile %s tuned for %dHz\n",
112786ed3669SMark Brown 			s->name, s->rate);
112886ed3669SMark Brown 
112986ed3669SMark Brown 		/* If the EQ is enabled then disable it while we write out */
11306d75dfc3SKuninori Morimoto 		eq1 = snd_soc_component_read(component, WM9081_EQ_1) & WM9081_EQ_ENA;
113186ed3669SMark Brown 		if (eq1 & WM9081_EQ_ENA)
113248c33876SKuninori Morimoto 			snd_soc_component_write(component, WM9081_EQ_1, 0);
113386ed3669SMark Brown 
113486ed3669SMark Brown 		/* Write out the other values */
113586ed3669SMark Brown 		for (i = 1; i < ARRAY_SIZE(s->config); i++)
113648c33876SKuninori Morimoto 			snd_soc_component_write(component, WM9081_EQ_1 + i, s->config[i]);
113786ed3669SMark Brown 
113886ed3669SMark Brown 		eq1 |= (s->config[0] & ~WM9081_EQ_ENA);
113948c33876SKuninori Morimoto 		snd_soc_component_write(component, WM9081_EQ_1, eq1);
114086ed3669SMark Brown 	}
114186ed3669SMark Brown 
114248c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_CLOCK_CONTROL_2, clk_ctrl2);
114348c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_2, aif2);
114448c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_3, aif3);
114548c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_4, aif4);
114686ed3669SMark Brown 
114786ed3669SMark Brown 	return 0;
114886ed3669SMark Brown }
114986ed3669SMark Brown 
wm9081_mute(struct snd_soc_dai * codec_dai,int mute,int direction)115026d3c16eSKuninori Morimoto static int wm9081_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
115186ed3669SMark Brown {
115248c33876SKuninori Morimoto 	struct snd_soc_component *component = codec_dai->component;
115386ed3669SMark Brown 	unsigned int reg;
115486ed3669SMark Brown 
11556d75dfc3SKuninori Morimoto 	reg = snd_soc_component_read(component, WM9081_DAC_DIGITAL_2);
115686ed3669SMark Brown 
115786ed3669SMark Brown 	if (mute)
115886ed3669SMark Brown 		reg |= WM9081_DAC_MUTE;
115986ed3669SMark Brown 	else
116086ed3669SMark Brown 		reg &= ~WM9081_DAC_MUTE;
116186ed3669SMark Brown 
116248c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_DAC_DIGITAL_2, reg);
116386ed3669SMark Brown 
116486ed3669SMark Brown 	return 0;
116586ed3669SMark Brown }
116686ed3669SMark Brown 
wm9081_set_sysclk(struct snd_soc_component * component,int clk_id,int source,unsigned int freq,int dir)116748c33876SKuninori Morimoto static int wm9081_set_sysclk(struct snd_soc_component *component, int clk_id,
1168da1c6ea6SMark Brown 			     int source, unsigned int freq, int dir)
116986ed3669SMark Brown {
117048c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
117186ed3669SMark Brown 
117286ed3669SMark Brown 	switch (clk_id) {
117386ed3669SMark Brown 	case WM9081_SYSCLK_MCLK:
117486ed3669SMark Brown 	case WM9081_SYSCLK_FLL_MCLK:
117586ed3669SMark Brown 		wm9081->sysclk_source = clk_id;
117686ed3669SMark Brown 		wm9081->mclk_rate = freq;
117786ed3669SMark Brown 		break;
117886ed3669SMark Brown 
117986ed3669SMark Brown 	default:
118086ed3669SMark Brown 		return -EINVAL;
118186ed3669SMark Brown 	}
118286ed3669SMark Brown 
118386ed3669SMark Brown 	return 0;
118486ed3669SMark Brown }
118586ed3669SMark Brown 
wm9081_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)118686ed3669SMark Brown static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
1187a5479e38SDaniel Ribeiro 	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
118886ed3669SMark Brown {
118948c33876SKuninori Morimoto 	struct snd_soc_component *component = dai->component;
119048c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
11916d75dfc3SKuninori Morimoto 	unsigned int aif1 = snd_soc_component_read(component, WM9081_AUDIO_INTERFACE_1);
119286ed3669SMark Brown 
119386ed3669SMark Brown 	aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
119486ed3669SMark Brown 
1195e0026beaSMark Brown 	if (slots < 0 || slots > 4)
119686ed3669SMark Brown 		return -EINVAL;
119786ed3669SMark Brown 
1198e0026beaSMark Brown 	wm9081->tdm_width = slot_width;
1199e0026beaSMark Brown 
1200e0026beaSMark Brown 	if (slots == 0)
1201e0026beaSMark Brown 		slots = 1;
1202e0026beaSMark Brown 
120386ed3669SMark Brown 	aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
120486ed3669SMark Brown 
1205a5479e38SDaniel Ribeiro 	switch (rx_mask) {
120686ed3669SMark Brown 	case 1:
120786ed3669SMark Brown 		break;
120886ed3669SMark Brown 	case 2:
120986ed3669SMark Brown 		aif1 |= 0x10;
121086ed3669SMark Brown 		break;
121186ed3669SMark Brown 	case 4:
121286ed3669SMark Brown 		aif1 |= 0x20;
121386ed3669SMark Brown 		break;
121486ed3669SMark Brown 	case 8:
121586ed3669SMark Brown 		aif1 |= 0x30;
121686ed3669SMark Brown 		break;
121786ed3669SMark Brown 	default:
121886ed3669SMark Brown 		return -EINVAL;
121986ed3669SMark Brown 	}
122086ed3669SMark Brown 
122148c33876SKuninori Morimoto 	snd_soc_component_write(component, WM9081_AUDIO_INTERFACE_1, aif1);
122286ed3669SMark Brown 
122386ed3669SMark Brown 	return 0;
122486ed3669SMark Brown }
122586ed3669SMark Brown 
122686ed3669SMark Brown #define WM9081_RATES SNDRV_PCM_RATE_8000_96000
122786ed3669SMark Brown 
122886ed3669SMark Brown #define WM9081_FORMATS \
122986ed3669SMark Brown 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
123086ed3669SMark Brown 	 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
123186ed3669SMark Brown 
123285e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm9081_dai_ops = {
123386ed3669SMark Brown 	.hw_params = wm9081_hw_params,
123486ed3669SMark Brown 	.set_fmt = wm9081_set_dai_fmt,
123526d3c16eSKuninori Morimoto 	.mute_stream = wm9081_mute,
123686ed3669SMark Brown 	.set_tdm_slot = wm9081_set_tdm_slot,
123726d3c16eSKuninori Morimoto 	.no_capture_mute = 1,
123886ed3669SMark Brown };
123986ed3669SMark Brown 
124086ed3669SMark Brown /* We report two channels because the CODEC processes a stereo signal, even
124186ed3669SMark Brown  * though it is only capable of handling a mono output.
124286ed3669SMark Brown  */
1243f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm9081_dai = {
1244f0fba2adSLiam Girdwood 	.name = "wm9081-hifi",
124586ed3669SMark Brown 	.playback = {
12460fb7d0c3SMark Brown 		.stream_name = "AIF",
124786ed3669SMark Brown 		.channels_min = 1,
124886ed3669SMark Brown 		.channels_max = 2,
124986ed3669SMark Brown 		.rates = WM9081_RATES,
125086ed3669SMark Brown 		.formats = WM9081_FORMATS,
125186ed3669SMark Brown 	},
125286ed3669SMark Brown 	.ops = &wm9081_dai_ops,
125386ed3669SMark Brown };
125486ed3669SMark Brown 
wm9081_probe(struct snd_soc_component * component)125548c33876SKuninori Morimoto static int wm9081_probe(struct snd_soc_component *component)
125686ed3669SMark Brown {
125748c33876SKuninori Morimoto 	struct wm9081_priv *wm9081 = snd_soc_component_get_drvdata(component);
125886ed3669SMark Brown 
1259f0fba2adSLiam Girdwood 	/* Enable zero cross by default */
126048c33876SKuninori Morimoto 	snd_soc_component_update_bits(component, WM9081_ANALOGUE_LINEOUT,
1261b4027358SAxel Lin 			    WM9081_LINEOUTZC, WM9081_LINEOUTZC);
126248c33876SKuninori Morimoto 	snd_soc_component_update_bits(component, WM9081_ANALOGUE_SPEAKER_PGA,
1263b4027358SAxel Lin 			    WM9081_SPKPGAZC, WM9081_SPKPGAZC);
1264f0fba2adSLiam Girdwood 
12654a5f7bdaSMark Brown 	if (!wm9081->pdata.num_retune_configs) {
126648c33876SKuninori Morimoto 		dev_dbg(component->dev,
126786ed3669SMark Brown 			"No ReTune Mobile data, using normal EQ\n");
126848c33876SKuninori Morimoto 		snd_soc_add_component_controls(component, wm9081_eq_controls,
126986ed3669SMark Brown 				     ARRAY_SIZE(wm9081_eq_controls));
127086ed3669SMark Brown 	}
127186ed3669SMark Brown 
12725d6be5aaSXiubo Li 	return 0;
127386ed3669SMark Brown }
127486ed3669SMark Brown 
127548c33876SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm9081 = {
127686ed3669SMark Brown 	.probe			= wm9081_probe,
127763d24b79SMark Brown 	.set_sysclk		= wm9081_set_sysclk,
1278f0fba2adSLiam Girdwood 	.set_bias_level		= wm9081_set_bias_level,
1279680fa1f8SMark Brown 	.controls		= wm9081_snd_controls,
1280680fa1f8SMark Brown 	.num_controls		= ARRAY_SIZE(wm9081_snd_controls),
1281149c7b44SMark Brown 	.dapm_widgets		= wm9081_dapm_widgets,
1282149c7b44SMark Brown 	.num_dapm_widgets	= ARRAY_SIZE(wm9081_dapm_widgets),
1283149c7b44SMark Brown 	.dapm_routes		= wm9081_audio_paths,
1284149c7b44SMark Brown 	.num_dapm_routes	= ARRAY_SIZE(wm9081_audio_paths),
128548c33876SKuninori Morimoto 	.use_pmdown_time	= 1,
128648c33876SKuninori Morimoto 	.endianness		= 1,
128786ed3669SMark Brown };
128886ed3669SMark Brown 
12897cfa467bSMark Brown static const struct regmap_config wm9081_regmap = {
12907cfa467bSMark Brown 	.reg_bits = 8,
12917cfa467bSMark Brown 	.val_bits = 16,
12927cfa467bSMark Brown 
12937cfa467bSMark Brown 	.max_register = WM9081_MAX_REGISTER,
12947cfa467bSMark Brown 	.reg_defaults = wm9081_reg,
12957cfa467bSMark Brown 	.num_reg_defaults = ARRAY_SIZE(wm9081_reg),
12967cfa467bSMark Brown 	.volatile_reg = wm9081_volatile_register,
12977cfa467bSMark Brown 	.readable_reg = wm9081_readable_register,
1298*1a37aa41SMark Brown 	.cache_type = REGCACHE_MAPLE,
12997cfa467bSMark Brown };
13007cfa467bSMark Brown 
wm9081_i2c_probe(struct i2c_client * i2c)130197b0b6e3SStephen Kitt static int wm9081_i2c_probe(struct i2c_client *i2c)
130286ed3669SMark Brown {
130386ed3669SMark Brown 	struct wm9081_priv *wm9081;
13047cfa467bSMark Brown 	unsigned int reg;
1305f0fba2adSLiam Girdwood 	int ret;
130686ed3669SMark Brown 
1307897f7847SMark Brown 	wm9081 = devm_kzalloc(&i2c->dev, sizeof(struct wm9081_priv),
1308897f7847SMark Brown 			      GFP_KERNEL);
130986ed3669SMark Brown 	if (wm9081 == NULL)
131086ed3669SMark Brown 		return -ENOMEM;
131186ed3669SMark Brown 
131286ed3669SMark Brown 	i2c_set_clientdata(i2c, wm9081);
13137cfa467bSMark Brown 
1314a5710c01SSachin Kamat 	wm9081->regmap = devm_regmap_init_i2c(i2c, &wm9081_regmap);
13157cfa467bSMark Brown 	if (IS_ERR(wm9081->regmap)) {
13167cfa467bSMark Brown 		ret = PTR_ERR(wm9081->regmap);
13177cfa467bSMark Brown 		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
1318a5710c01SSachin Kamat 		return ret;
13197cfa467bSMark Brown 	}
13207cfa467bSMark Brown 
13217cfa467bSMark Brown 	ret = regmap_read(wm9081->regmap, WM9081_SOFTWARE_RESET, &reg);
13227cfa467bSMark Brown 	if (ret != 0) {
13237cfa467bSMark Brown 		dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
1324a5710c01SSachin Kamat 		return ret;
13257cfa467bSMark Brown 	}
13267cfa467bSMark Brown 	if (reg != 0x9081) {
13277cfa467bSMark Brown 		dev_err(&i2c->dev, "Device is not a WM9081: ID=0x%x\n", reg);
1328a5710c01SSachin Kamat 		return -EINVAL;
13297cfa467bSMark Brown 	}
13307cfa467bSMark Brown 
13317cfa467bSMark Brown 	ret = wm9081_reset(wm9081->regmap);
13327cfa467bSMark Brown 	if (ret < 0) {
13337cfa467bSMark Brown 		dev_err(&i2c->dev, "Failed to issue reset\n");
1334a5710c01SSachin Kamat 		return ret;
13357cfa467bSMark Brown 	}
133686ed3669SMark Brown 
13373ee845acSMark Brown 	if (dev_get_platdata(&i2c->dev))
13384a5f7bdaSMark Brown 		memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev),
13394a5f7bdaSMark Brown 		       sizeof(wm9081->pdata));
13403ee845acSMark Brown 
134168fcde97SMark Brown 	reg = 0;
134268fcde97SMark Brown 	if (wm9081->pdata.irq_high)
134368fcde97SMark Brown 		reg |= WM9081_IRQ_POL;
134468fcde97SMark Brown 	if (!wm9081->pdata.irq_cmos)
134568fcde97SMark Brown 		reg |= WM9081_IRQ_OP_CTRL;
134668fcde97SMark Brown 	regmap_update_bits(wm9081->regmap, WM9081_INTERRUPT_CONTROL,
134768fcde97SMark Brown 			   WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg);
134868fcde97SMark Brown 
1349da157875SMark Brown 	regcache_cache_only(wm9081->regmap, true);
135068fcde97SMark Brown 
135148c33876SKuninori Morimoto 	ret = devm_snd_soc_register_component(&i2c->dev,
135248c33876SKuninori Morimoto 			&soc_component_dev_wm9081, &wm9081_dai, 1);
1353f0fba2adSLiam Girdwood 	if (ret < 0)
1354a5710c01SSachin Kamat 		return ret;
13557cfa467bSMark Brown 
13567cfa467bSMark Brown 	return 0;
135786ed3669SMark Brown }
135886ed3669SMark Brown 
wm9081_i2c_remove(struct i2c_client * client)1359ed5c2f5fSUwe Kleine-König static void wm9081_i2c_remove(struct i2c_client *client)
1360ed5c2f5fSUwe Kleine-König {}
136186ed3669SMark Brown 
136286ed3669SMark Brown static const struct i2c_device_id wm9081_i2c_id[] = {
136386ed3669SMark Brown 	{ "wm9081", 0 },
136486ed3669SMark Brown 	{ }
136586ed3669SMark Brown };
136686ed3669SMark Brown MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
136786ed3669SMark Brown 
136886ed3669SMark Brown static struct i2c_driver wm9081_i2c_driver = {
136986ed3669SMark Brown 	.driver = {
13702031c064SMark Brown 		.name = "wm9081",
137186ed3669SMark Brown 	},
13729abcd240SUwe Kleine-König 	.probe =    wm9081_i2c_probe,
13737a79e94eSBill Pemberton 	.remove =   wm9081_i2c_remove,
137486ed3669SMark Brown 	.id_table = wm9081_i2c_id,
137586ed3669SMark Brown };
137686ed3669SMark Brown 
13772dbc34d8SMark Brown module_i2c_driver(wm9081_i2c_driver);
137886ed3669SMark Brown 
137986ed3669SMark Brown MODULE_DESCRIPTION("ASoC WM9081 driver");
138086ed3669SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
138186ed3669SMark Brown MODULE_LICENSE("GPL");
1382