1abadfc92SRichard Purdie /* 2abadfc92SRichard Purdie * wm8750.c -- WM8750 ALSA SoC audio driver 3abadfc92SRichard Purdie * 4abadfc92SRichard Purdie * Copyright 2005 Openedhand Ltd. 5abadfc92SRichard Purdie * 6abadfc92SRichard Purdie * Author: Richard Purdie <richard@openedhand.com> 7abadfc92SRichard Purdie * 8abadfc92SRichard Purdie * Based on WM8753.c 9abadfc92SRichard Purdie * 10abadfc92SRichard Purdie * This program is free software; you can redistribute it and/or modify 11abadfc92SRichard Purdie * it under the terms of the GNU General Public License version 2 as 12abadfc92SRichard Purdie * published by the Free Software Foundation. 13abadfc92SRichard Purdie */ 14abadfc92SRichard Purdie 15abadfc92SRichard Purdie #include <linux/module.h> 16abadfc92SRichard Purdie #include <linux/moduleparam.h> 17abadfc92SRichard Purdie #include <linux/init.h> 18abadfc92SRichard Purdie #include <linux/delay.h> 19abadfc92SRichard Purdie #include <linux/pm.h> 20abadfc92SRichard Purdie #include <linux/i2c.h> 21ed79edacSMark Brown #include <linux/regmap.h> 222f3dfaf5SMark Brown #include <linux/spi/spi.h> 235a0e3ad6STejun Heo #include <linux/slab.h> 24ce31a0f5SMark Brown #include <linux/of_device.h> 25abadfc92SRichard Purdie #include <sound/core.h> 26abadfc92SRichard Purdie #include <sound/pcm.h> 27abadfc92SRichard Purdie #include <sound/pcm_params.h> 28abadfc92SRichard Purdie #include <sound/soc.h> 29abadfc92SRichard Purdie #include <sound/initval.h> 30abadfc92SRichard Purdie 31abadfc92SRichard Purdie #include "wm8750.h" 32abadfc92SRichard Purdie 33abadfc92SRichard Purdie /* 34abadfc92SRichard Purdie * wm8750 register cache 35abadfc92SRichard Purdie * We can't read the WM8750 register space when we 36abadfc92SRichard Purdie * are using 2 wire for device control, so we cache them instead. 37abadfc92SRichard Purdie */ 38ed79edacSMark Brown static const struct reg_default wm8750_reg_defaults[] = { 39ed79edacSMark Brown { 0, 0x0097 }, 40ed79edacSMark Brown { 1, 0x0097 }, 41ed79edacSMark Brown { 2, 0x0079 }, 42ed79edacSMark Brown { 3, 0x0079 }, 43ed79edacSMark Brown { 4, 0x0000 }, 44ed79edacSMark Brown { 5, 0x0008 }, 45ed79edacSMark Brown { 6, 0x0000 }, 46ed79edacSMark Brown { 7, 0x000a }, 47ed79edacSMark Brown { 8, 0x0000 }, 48ed79edacSMark Brown { 9, 0x0000 }, 49ed79edacSMark Brown { 10, 0x00ff }, 50ed79edacSMark Brown { 11, 0x00ff }, 51ed79edacSMark Brown { 12, 0x000f }, 52ed79edacSMark Brown { 13, 0x000f }, 53ed79edacSMark Brown { 14, 0x0000 }, 54ed79edacSMark Brown { 15, 0x0000 }, 55ed79edacSMark Brown { 16, 0x0000 }, 56ed79edacSMark Brown { 17, 0x007b }, 57ed79edacSMark Brown { 18, 0x0000 }, 58ed79edacSMark Brown { 19, 0x0032 }, 59ed79edacSMark Brown { 20, 0x0000 }, 60ed79edacSMark Brown { 21, 0x00c3 }, 61ed79edacSMark Brown { 22, 0x00c3 }, 62ed79edacSMark Brown { 23, 0x00c0 }, 63ed79edacSMark Brown { 24, 0x0000 }, 64ed79edacSMark Brown { 25, 0x0000 }, 65ed79edacSMark Brown { 26, 0x0000 }, 66ed79edacSMark Brown { 27, 0x0000 }, 67ed79edacSMark Brown { 28, 0x0000 }, 68ed79edacSMark Brown { 29, 0x0000 }, 69ed79edacSMark Brown { 30, 0x0000 }, 70ed79edacSMark Brown { 31, 0x0000 }, 71ed79edacSMark Brown { 32, 0x0000 }, 72ed79edacSMark Brown { 33, 0x0000 }, 73ed79edacSMark Brown { 34, 0x0050 }, 74ed79edacSMark Brown { 35, 0x0050 }, 75ed79edacSMark Brown { 36, 0x0050 }, 76ed79edacSMark Brown { 37, 0x0050 }, 77ed79edacSMark Brown { 38, 0x0050 }, 78ed79edacSMark Brown { 39, 0x0050 }, 79ed79edacSMark Brown { 40, 0x0079 }, 80ed79edacSMark Brown { 41, 0x0079 }, 81ed79edacSMark Brown { 42, 0x0079 }, 82abadfc92SRichard Purdie }; 83abadfc92SRichard Purdie 846ca0c22eSMarek Vasut /* codec private data */ 856ca0c22eSMarek Vasut struct wm8750_priv { 866ca0c22eSMarek Vasut unsigned int sysclk; 876ca0c22eSMarek Vasut }; 886ca0c22eSMarek Vasut 89*f081a227SKuninori Morimoto #define wm8750_reset(c) snd_soc_component_write(c, WM8750_RESET, 0) 90abadfc92SRichard Purdie 91abadfc92SRichard Purdie /* 92abadfc92SRichard Purdie * WM8750 Controls 93abadfc92SRichard Purdie */ 94abadfc92SRichard Purdie static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"}; 95abadfc92SRichard Purdie static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; 96abadfc92SRichard Purdie static const char *wm8750_treble[] = {"8kHz", "4kHz"}; 97abadfc92SRichard Purdie static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"}; 98abadfc92SRichard Purdie static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"}; 99abadfc92SRichard Purdie static const char *wm8750_3d_func[] = {"Capture", "Playback"}; 100abadfc92SRichard Purdie static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"}; 101abadfc92SRichard Purdie static const char *wm8750_ng_type[] = {"Constant PGA Gain", 102abadfc92SRichard Purdie "Mute ADC Output"}; 103abadfc92SRichard Purdie static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA", 104abadfc92SRichard Purdie "Differential"}; 105abadfc92SRichard Purdie static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3", 106abadfc92SRichard Purdie "Differential"}; 107abadfc92SRichard Purdie static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", 108abadfc92SRichard Purdie "ROUT1"}; 109abadfc92SRichard Purdie static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"}; 110abadfc92SRichard Purdie static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert", 111abadfc92SRichard Purdie "L + R Invert"}; 112abadfc92SRichard Purdie static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; 113abadfc92SRichard Purdie static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)", 114abadfc92SRichard Purdie "Mono (Right)", "Digital Mono"}; 115abadfc92SRichard Purdie 116abadfc92SRichard Purdie static const struct soc_enum wm8750_enum[] = { 117abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass), 118abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter), 119abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble), 120abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc), 121abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc), 122abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func), 123abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func), 124abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type), 125abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux), 126abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux), 127abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */ 128abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel), 129abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3), 130abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel), 131abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol), 132abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph), 133abadfc92SRichard Purdie SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */ 134abadfc92SRichard Purdie 135abadfc92SRichard Purdie }; 136abadfc92SRichard Purdie 137abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_snd_controls[] = { 138abadfc92SRichard Purdie 139abadfc92SRichard Purdie SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0), 140abadfc92SRichard Purdie SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0), 141abadfc92SRichard Purdie SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1), 142abadfc92SRichard Purdie 143bd903b6eSLiam Girdwood SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V, 144abadfc92SRichard Purdie WM8750_ROUT1V, 7, 1, 0), 145bd903b6eSLiam Girdwood SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V, 146abadfc92SRichard Purdie WM8750_ROUT2V, 7, 1, 0), 147abadfc92SRichard Purdie 148abadfc92SRichard Purdie SOC_ENUM("Playback De-emphasis", wm8750_enum[15]), 149abadfc92SRichard Purdie 150abadfc92SRichard Purdie SOC_ENUM("Capture Polarity", wm8750_enum[14]), 151abadfc92SRichard Purdie SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0), 152abadfc92SRichard Purdie SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0), 153abadfc92SRichard Purdie 154abadfc92SRichard Purdie SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0), 155abadfc92SRichard Purdie 156abadfc92SRichard Purdie SOC_ENUM("Bass Boost", wm8750_enum[0]), 157abadfc92SRichard Purdie SOC_ENUM("Bass Filter", wm8750_enum[1]), 158abadfc92SRichard Purdie SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), 159abadfc92SRichard Purdie 1606a7b8cf4SStanislav Brabec SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1), 161abadfc92SRichard Purdie SOC_ENUM("Treble Cut-off", wm8750_enum[2]), 162abadfc92SRichard Purdie 163abadfc92SRichard Purdie SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), 164abadfc92SRichard Purdie SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0), 165abadfc92SRichard Purdie SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]), 166abadfc92SRichard Purdie SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]), 167abadfc92SRichard Purdie SOC_ENUM("3D Mode", wm8750_enum[5]), 168abadfc92SRichard Purdie 169abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0), 170abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0), 171abadfc92SRichard Purdie SOC_ENUM("ALC Capture Function", wm8750_enum[6]), 172abadfc92SRichard Purdie SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0), 173abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0), 174abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0), 175abadfc92SRichard Purdie SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0), 176abadfc92SRichard Purdie SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0), 177abadfc92SRichard Purdie SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]), 178abadfc92SRichard Purdie SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0), 179abadfc92SRichard Purdie 180abadfc92SRichard Purdie SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0), 181abadfc92SRichard Purdie SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0), 182abadfc92SRichard Purdie 183abadfc92SRichard Purdie SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0), 184abadfc92SRichard Purdie SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0), 185abadfc92SRichard Purdie 186bd903b6eSLiam Girdwood SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), 187abadfc92SRichard Purdie 188abadfc92SRichard Purdie /* Unimplemented */ 189abadfc92SRichard Purdie /* ADCDAC Bit 0 - ADCHPD */ 190abadfc92SRichard Purdie /* ADCDAC Bit 4 - HPOR */ 191abadfc92SRichard Purdie /* ADCTL1 Bit 2,3 - DATSEL */ 192abadfc92SRichard Purdie /* ADCTL1 Bit 4,5 - DMONOMIX */ 193abadfc92SRichard Purdie /* ADCTL1 Bit 6,7 - VSEL */ 194abadfc92SRichard Purdie /* ADCTL2 Bit 2 - LRCM */ 195abadfc92SRichard Purdie /* ADCTL2 Bit 3 - TRI */ 196abadfc92SRichard Purdie /* ADCTL3 Bit 5 - HPFLREN */ 197abadfc92SRichard Purdie /* ADCTL3 Bit 6 - VROI */ 198abadfc92SRichard Purdie /* ADCTL3 Bit 7,8 - ADCLRM */ 199abadfc92SRichard Purdie /* ADCIN Bit 4 - LDCM */ 200abadfc92SRichard Purdie /* ADCIN Bit 5 - RDCM */ 201abadfc92SRichard Purdie 202abadfc92SRichard Purdie SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0), 203abadfc92SRichard Purdie 204abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1, 205abadfc92SRichard Purdie WM8750_LOUTM2, 4, 7, 1), 206abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1, 207abadfc92SRichard Purdie WM8750_ROUTM2, 4, 7, 1), 208abadfc92SRichard Purdie SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1, 209abadfc92SRichard Purdie WM8750_MOUTM2, 4, 7, 1), 210abadfc92SRichard Purdie 211abadfc92SRichard Purdie SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0), 212abadfc92SRichard Purdie 213bd903b6eSLiam Girdwood SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, 214bd903b6eSLiam Girdwood 0, 127, 0), 215bd903b6eSLiam Girdwood SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, 216bd903b6eSLiam Girdwood 0, 127, 0), 217abadfc92SRichard Purdie 218abadfc92SRichard Purdie SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), 219abadfc92SRichard Purdie 220abadfc92SRichard Purdie }; 221abadfc92SRichard Purdie 222abadfc92SRichard Purdie /* 223abadfc92SRichard Purdie * DAPM Controls 224abadfc92SRichard Purdie */ 225abadfc92SRichard Purdie 226abadfc92SRichard Purdie /* Left Mixer */ 227abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = { 228abadfc92SRichard Purdie SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0), 229abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0), 230abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0), 231abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0), 232abadfc92SRichard Purdie }; 233abadfc92SRichard Purdie 234abadfc92SRichard Purdie /* Right Mixer */ 235abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = { 236abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0), 237abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0), 238abadfc92SRichard Purdie SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0), 239abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0), 240abadfc92SRichard Purdie }; 241abadfc92SRichard Purdie 242abadfc92SRichard Purdie /* Mono Mixer */ 243abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = { 244abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0), 245abadfc92SRichard Purdie SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0), 246abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0), 247abadfc92SRichard Purdie SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0), 248abadfc92SRichard Purdie }; 249abadfc92SRichard Purdie 250abadfc92SRichard Purdie /* Left Line Mux */ 251abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_line_controls = 252abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[8]); 253abadfc92SRichard Purdie 254abadfc92SRichard Purdie /* Right Line Mux */ 255abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_line_controls = 256abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[9]); 257abadfc92SRichard Purdie 258abadfc92SRichard Purdie /* Left PGA Mux */ 259abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_left_pga_controls = 260abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[10]); 261abadfc92SRichard Purdie 262abadfc92SRichard Purdie /* Right PGA Mux */ 263abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_right_pga_controls = 264abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[11]); 265abadfc92SRichard Purdie 266abadfc92SRichard Purdie /* Out 3 Mux */ 267abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_out3_controls = 268abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[12]); 269abadfc92SRichard Purdie 270abadfc92SRichard Purdie /* Differential Mux */ 271abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_diffmux_controls = 272abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[13]); 273abadfc92SRichard Purdie 274abadfc92SRichard Purdie /* Mono ADC Mux */ 275abadfc92SRichard Purdie static const struct snd_kcontrol_new wm8750_monomux_controls = 276abadfc92SRichard Purdie SOC_DAPM_ENUM("Route", wm8750_enum[16]); 277abadfc92SRichard Purdie 278abadfc92SRichard Purdie static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { 279abadfc92SRichard Purdie SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, 280abadfc92SRichard Purdie &wm8750_left_mixer_controls[0], 281abadfc92SRichard Purdie ARRAY_SIZE(wm8750_left_mixer_controls)), 282abadfc92SRichard Purdie SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, 283abadfc92SRichard Purdie &wm8750_right_mixer_controls[0], 284abadfc92SRichard Purdie ARRAY_SIZE(wm8750_right_mixer_controls)), 285abadfc92SRichard Purdie SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, 286abadfc92SRichard Purdie &wm8750_mono_mixer_controls[0], 287abadfc92SRichard Purdie ARRAY_SIZE(wm8750_mono_mixer_controls)), 288abadfc92SRichard Purdie 289abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0), 290abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0), 291abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0), 292abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0), 293abadfc92SRichard Purdie SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0), 294abadfc92SRichard Purdie SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0), 295abadfc92SRichard Purdie 296abadfc92SRichard Purdie SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0), 297abadfc92SRichard Purdie SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0), 298abadfc92SRichard Purdie SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0), 299abadfc92SRichard Purdie 300abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0, 301abadfc92SRichard Purdie &wm8750_left_pga_controls), 302abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0, 303abadfc92SRichard Purdie &wm8750_right_pga_controls), 304abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, 305abadfc92SRichard Purdie &wm8750_left_line_controls), 306abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, 307abadfc92SRichard Purdie &wm8750_right_line_controls), 308abadfc92SRichard Purdie 309abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls), 310abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0), 311abadfc92SRichard Purdie SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0), 312abadfc92SRichard Purdie 313abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, 314abadfc92SRichard Purdie &wm8750_diffmux_controls), 315abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, 316abadfc92SRichard Purdie &wm8750_monomux_controls), 317abadfc92SRichard Purdie SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, 318abadfc92SRichard Purdie &wm8750_monomux_controls), 319abadfc92SRichard Purdie 320abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("LOUT1"), 321abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("ROUT1"), 322abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("LOUT2"), 323abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("ROUT2"), 32423ba79bdSDmitry Baryshkov SND_SOC_DAPM_OUTPUT("MONO1"), 325abadfc92SRichard Purdie SND_SOC_DAPM_OUTPUT("OUT3"), 3265ede19c5SLars-Peter Clausen SND_SOC_DAPM_VMID("VREF"), 327abadfc92SRichard Purdie 328abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("LINPUT1"), 329abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("LINPUT2"), 330abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("LINPUT3"), 331abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("RINPUT1"), 332abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("RINPUT2"), 333abadfc92SRichard Purdie SND_SOC_DAPM_INPUT("RINPUT3"), 334abadfc92SRichard Purdie }; 335abadfc92SRichard Purdie 3360f185e3fSMark Brown static const struct snd_soc_dapm_route wm8750_dapm_routes[] = { 337abadfc92SRichard Purdie /* left mixer */ 338abadfc92SRichard Purdie {"Left Mixer", "Playback Switch", "Left DAC"}, 339abadfc92SRichard Purdie {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, 340abadfc92SRichard Purdie {"Left Mixer", "Right Playback Switch", "Right DAC"}, 341abadfc92SRichard Purdie {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, 342abadfc92SRichard Purdie 343abadfc92SRichard Purdie /* right mixer */ 344abadfc92SRichard Purdie {"Right Mixer", "Left Playback Switch", "Left DAC"}, 345abadfc92SRichard Purdie {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, 346abadfc92SRichard Purdie {"Right Mixer", "Playback Switch", "Right DAC"}, 347abadfc92SRichard Purdie {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, 348abadfc92SRichard Purdie 349abadfc92SRichard Purdie /* left out 1 */ 350abadfc92SRichard Purdie {"Left Out 1", NULL, "Left Mixer"}, 351abadfc92SRichard Purdie {"LOUT1", NULL, "Left Out 1"}, 352abadfc92SRichard Purdie 353abadfc92SRichard Purdie /* left out 2 */ 354abadfc92SRichard Purdie {"Left Out 2", NULL, "Left Mixer"}, 355abadfc92SRichard Purdie {"LOUT2", NULL, "Left Out 2"}, 356abadfc92SRichard Purdie 357abadfc92SRichard Purdie /* right out 1 */ 358abadfc92SRichard Purdie {"Right Out 1", NULL, "Right Mixer"}, 359abadfc92SRichard Purdie {"ROUT1", NULL, "Right Out 1"}, 360abadfc92SRichard Purdie 361abadfc92SRichard Purdie /* right out 2 */ 362abadfc92SRichard Purdie {"Right Out 2", NULL, "Right Mixer"}, 363abadfc92SRichard Purdie {"ROUT2", NULL, "Right Out 2"}, 364abadfc92SRichard Purdie 365abadfc92SRichard Purdie /* mono mixer */ 366abadfc92SRichard Purdie {"Mono Mixer", "Left Playback Switch", "Left DAC"}, 367abadfc92SRichard Purdie {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, 368abadfc92SRichard Purdie {"Mono Mixer", "Right Playback Switch", "Right DAC"}, 369abadfc92SRichard Purdie {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, 370abadfc92SRichard Purdie 371abadfc92SRichard Purdie /* mono out */ 372abadfc92SRichard Purdie {"Mono Out 1", NULL, "Mono Mixer"}, 373abadfc92SRichard Purdie {"MONO1", NULL, "Mono Out 1"}, 374abadfc92SRichard Purdie 375abadfc92SRichard Purdie /* out 3 */ 376abadfc92SRichard Purdie {"Out3 Mux", "VREF", "VREF"}, 377abadfc92SRichard Purdie {"Out3 Mux", "ROUT1 + Vol", "ROUT1"}, 378abadfc92SRichard Purdie {"Out3 Mux", "ROUT1", "Right Mixer"}, 379abadfc92SRichard Purdie {"Out3 Mux", "MonoOut", "MONO1"}, 380abadfc92SRichard Purdie {"Out 3", NULL, "Out3 Mux"}, 381abadfc92SRichard Purdie {"OUT3", NULL, "Out 3"}, 382abadfc92SRichard Purdie 383abadfc92SRichard Purdie /* Left Line Mux */ 384abadfc92SRichard Purdie {"Left Line Mux", "Line 1", "LINPUT1"}, 385abadfc92SRichard Purdie {"Left Line Mux", "Line 2", "LINPUT2"}, 386abadfc92SRichard Purdie {"Left Line Mux", "Line 3", "LINPUT3"}, 387abadfc92SRichard Purdie {"Left Line Mux", "PGA", "Left PGA Mux"}, 388abadfc92SRichard Purdie {"Left Line Mux", "Differential", "Differential Mux"}, 389abadfc92SRichard Purdie 390abadfc92SRichard Purdie /* Right Line Mux */ 391abadfc92SRichard Purdie {"Right Line Mux", "Line 1", "RINPUT1"}, 392abadfc92SRichard Purdie {"Right Line Mux", "Line 2", "RINPUT2"}, 393abadfc92SRichard Purdie {"Right Line Mux", "Line 3", "RINPUT3"}, 394abadfc92SRichard Purdie {"Right Line Mux", "PGA", "Right PGA Mux"}, 395abadfc92SRichard Purdie {"Right Line Mux", "Differential", "Differential Mux"}, 396abadfc92SRichard Purdie 397abadfc92SRichard Purdie /* Left PGA Mux */ 398abadfc92SRichard Purdie {"Left PGA Mux", "Line 1", "LINPUT1"}, 399abadfc92SRichard Purdie {"Left PGA Mux", "Line 2", "LINPUT2"}, 400abadfc92SRichard Purdie {"Left PGA Mux", "Line 3", "LINPUT3"}, 401abadfc92SRichard Purdie {"Left PGA Mux", "Differential", "Differential Mux"}, 402abadfc92SRichard Purdie 403abadfc92SRichard Purdie /* Right PGA Mux */ 404abadfc92SRichard Purdie {"Right PGA Mux", "Line 1", "RINPUT1"}, 405abadfc92SRichard Purdie {"Right PGA Mux", "Line 2", "RINPUT2"}, 406abadfc92SRichard Purdie {"Right PGA Mux", "Line 3", "RINPUT3"}, 407abadfc92SRichard Purdie {"Right PGA Mux", "Differential", "Differential Mux"}, 408abadfc92SRichard Purdie 409abadfc92SRichard Purdie /* Differential Mux */ 410abadfc92SRichard Purdie {"Differential Mux", "Line 1", "LINPUT1"}, 411abadfc92SRichard Purdie {"Differential Mux", "Line 1", "RINPUT1"}, 412abadfc92SRichard Purdie {"Differential Mux", "Line 2", "LINPUT2"}, 413abadfc92SRichard Purdie {"Differential Mux", "Line 2", "RINPUT2"}, 414abadfc92SRichard Purdie 415abadfc92SRichard Purdie /* Left ADC Mux */ 416abadfc92SRichard Purdie {"Left ADC Mux", "Stereo", "Left PGA Mux"}, 417abadfc92SRichard Purdie {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, 418abadfc92SRichard Purdie {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, 419abadfc92SRichard Purdie 420abadfc92SRichard Purdie /* Right ADC Mux */ 421abadfc92SRichard Purdie {"Right ADC Mux", "Stereo", "Right PGA Mux"}, 422abadfc92SRichard Purdie {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, 423abadfc92SRichard Purdie {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, 424abadfc92SRichard Purdie 425abadfc92SRichard Purdie /* ADC */ 426abadfc92SRichard Purdie {"Left ADC", NULL, "Left ADC Mux"}, 427abadfc92SRichard Purdie {"Right ADC", NULL, "Right ADC Mux"}, 428abadfc92SRichard Purdie }; 429abadfc92SRichard Purdie 430abadfc92SRichard Purdie struct _coeff_div { 431abadfc92SRichard Purdie u32 mclk; 432abadfc92SRichard Purdie u32 rate; 433abadfc92SRichard Purdie u16 fs; 434abadfc92SRichard Purdie u8 sr:5; 435abadfc92SRichard Purdie u8 usb:1; 436abadfc92SRichard Purdie }; 437abadfc92SRichard Purdie 438abadfc92SRichard Purdie /* codec hifi mclk clock divider coefficients */ 439abadfc92SRichard Purdie static const struct _coeff_div coeff_div[] = { 440abadfc92SRichard Purdie /* 8k */ 441abadfc92SRichard Purdie {12288000, 8000, 1536, 0x6, 0x0}, 442abadfc92SRichard Purdie {11289600, 8000, 1408, 0x16, 0x0}, 443abadfc92SRichard Purdie {18432000, 8000, 2304, 0x7, 0x0}, 444abadfc92SRichard Purdie {16934400, 8000, 2112, 0x17, 0x0}, 445abadfc92SRichard Purdie {12000000, 8000, 1500, 0x6, 0x1}, 446abadfc92SRichard Purdie 447abadfc92SRichard Purdie /* 11.025k */ 448abadfc92SRichard Purdie {11289600, 11025, 1024, 0x18, 0x0}, 449abadfc92SRichard Purdie {16934400, 11025, 1536, 0x19, 0x0}, 450abadfc92SRichard Purdie {12000000, 11025, 1088, 0x19, 0x1}, 451abadfc92SRichard Purdie 452abadfc92SRichard Purdie /* 16k */ 453abadfc92SRichard Purdie {12288000, 16000, 768, 0xa, 0x0}, 454abadfc92SRichard Purdie {18432000, 16000, 1152, 0xb, 0x0}, 455abadfc92SRichard Purdie {12000000, 16000, 750, 0xa, 0x1}, 456abadfc92SRichard Purdie 457abadfc92SRichard Purdie /* 22.05k */ 458abadfc92SRichard Purdie {11289600, 22050, 512, 0x1a, 0x0}, 459abadfc92SRichard Purdie {16934400, 22050, 768, 0x1b, 0x0}, 460abadfc92SRichard Purdie {12000000, 22050, 544, 0x1b, 0x1}, 461abadfc92SRichard Purdie 462abadfc92SRichard Purdie /* 32k */ 463abadfc92SRichard Purdie {12288000, 32000, 384, 0xc, 0x0}, 464abadfc92SRichard Purdie {18432000, 32000, 576, 0xd, 0x0}, 465abadfc92SRichard Purdie {12000000, 32000, 375, 0xa, 0x1}, 466abadfc92SRichard Purdie 467abadfc92SRichard Purdie /* 44.1k */ 468abadfc92SRichard Purdie {11289600, 44100, 256, 0x10, 0x0}, 469abadfc92SRichard Purdie {16934400, 44100, 384, 0x11, 0x0}, 470abadfc92SRichard Purdie {12000000, 44100, 272, 0x11, 0x1}, 471abadfc92SRichard Purdie 472abadfc92SRichard Purdie /* 48k */ 473abadfc92SRichard Purdie {12288000, 48000, 256, 0x0, 0x0}, 474abadfc92SRichard Purdie {18432000, 48000, 384, 0x1, 0x0}, 475abadfc92SRichard Purdie {12000000, 48000, 250, 0x0, 0x1}, 476abadfc92SRichard Purdie 477abadfc92SRichard Purdie /* 88.2k */ 478abadfc92SRichard Purdie {11289600, 88200, 128, 0x1e, 0x0}, 479abadfc92SRichard Purdie {16934400, 88200, 192, 0x1f, 0x0}, 480abadfc92SRichard Purdie {12000000, 88200, 136, 0x1f, 0x1}, 481abadfc92SRichard Purdie 482abadfc92SRichard Purdie /* 96k */ 483abadfc92SRichard Purdie {12288000, 96000, 128, 0xe, 0x0}, 484abadfc92SRichard Purdie {18432000, 96000, 192, 0xf, 0x0}, 485abadfc92SRichard Purdie {12000000, 96000, 125, 0xe, 0x1}, 486abadfc92SRichard Purdie }; 487abadfc92SRichard Purdie 488abadfc92SRichard Purdie static inline int get_coeff(int mclk, int rate) 489abadfc92SRichard Purdie { 490abadfc92SRichard Purdie int i; 491abadfc92SRichard Purdie 492abadfc92SRichard Purdie for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { 493abadfc92SRichard Purdie if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) 494abadfc92SRichard Purdie return i; 495abadfc92SRichard Purdie } 496a71a468aSLiam Girdwood 497a71a468aSLiam Girdwood printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n", 498a71a468aSLiam Girdwood mclk, rate); 499abadfc92SRichard Purdie return -EINVAL; 500abadfc92SRichard Purdie } 501abadfc92SRichard Purdie 502e550e17fSLiam Girdwood static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, 5034422b606SLiam Girdwood int clk_id, unsigned int freq, int dir) 504abadfc92SRichard Purdie { 505*f081a227SKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 506*f081a227SKuninori Morimoto struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component); 5074422b606SLiam Girdwood 5084422b606SLiam Girdwood switch (freq) { 5094422b606SLiam Girdwood case 11289600: 5104422b606SLiam Girdwood case 12000000: 5114422b606SLiam Girdwood case 12288000: 5124422b606SLiam Girdwood case 16934400: 5134422b606SLiam Girdwood case 18432000: 5144422b606SLiam Girdwood wm8750->sysclk = freq; 5154422b606SLiam Girdwood return 0; 5164422b606SLiam Girdwood } 5174422b606SLiam Girdwood return -EINVAL; 518abadfc92SRichard Purdie } 519abadfc92SRichard Purdie 520e550e17fSLiam Girdwood static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, 5214422b606SLiam Girdwood unsigned int fmt) 522abadfc92SRichard Purdie { 523*f081a227SKuninori Morimoto struct snd_soc_component *component = codec_dai->component; 5244422b606SLiam Girdwood u16 iface = 0; 525abadfc92SRichard Purdie 526abadfc92SRichard Purdie /* set master/slave audio interface */ 5274422b606SLiam Girdwood switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 528abadfc92SRichard Purdie case SND_SOC_DAIFMT_CBM_CFM: 529abadfc92SRichard Purdie iface = 0x0040; 530abadfc92SRichard Purdie break; 531abadfc92SRichard Purdie case SND_SOC_DAIFMT_CBS_CFS: 532abadfc92SRichard Purdie break; 5334422b606SLiam Girdwood default: 5344422b606SLiam Girdwood return -EINVAL; 535abadfc92SRichard Purdie } 536abadfc92SRichard Purdie 537abadfc92SRichard Purdie /* interface format */ 5384422b606SLiam Girdwood switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 539abadfc92SRichard Purdie case SND_SOC_DAIFMT_I2S: 540abadfc92SRichard Purdie iface |= 0x0002; 541abadfc92SRichard Purdie break; 542abadfc92SRichard Purdie case SND_SOC_DAIFMT_RIGHT_J: 543abadfc92SRichard Purdie break; 544abadfc92SRichard Purdie case SND_SOC_DAIFMT_LEFT_J: 545abadfc92SRichard Purdie iface |= 0x0001; 546abadfc92SRichard Purdie break; 547abadfc92SRichard Purdie case SND_SOC_DAIFMT_DSP_A: 548abadfc92SRichard Purdie iface |= 0x0003; 549abadfc92SRichard Purdie break; 550abadfc92SRichard Purdie case SND_SOC_DAIFMT_DSP_B: 551abadfc92SRichard Purdie iface |= 0x0013; 552abadfc92SRichard Purdie break; 5534422b606SLiam Girdwood default: 5544422b606SLiam Girdwood return -EINVAL; 555abadfc92SRichard Purdie } 556abadfc92SRichard Purdie 557abadfc92SRichard Purdie /* clock inversion */ 5584422b606SLiam Girdwood switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 559abadfc92SRichard Purdie case SND_SOC_DAIFMT_NB_NF: 560abadfc92SRichard Purdie break; 561abadfc92SRichard Purdie case SND_SOC_DAIFMT_IB_IF: 562abadfc92SRichard Purdie iface |= 0x0090; 563abadfc92SRichard Purdie break; 564abadfc92SRichard Purdie case SND_SOC_DAIFMT_IB_NF: 565abadfc92SRichard Purdie iface |= 0x0080; 566abadfc92SRichard Purdie break; 567abadfc92SRichard Purdie case SND_SOC_DAIFMT_NB_IF: 568abadfc92SRichard Purdie iface |= 0x0010; 569abadfc92SRichard Purdie break; 5704422b606SLiam Girdwood default: 5714422b606SLiam Girdwood return -EINVAL; 572abadfc92SRichard Purdie } 573abadfc92SRichard Purdie 574*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_IFACE, iface); 5754422b606SLiam Girdwood return 0; 5764422b606SLiam Girdwood } 5774422b606SLiam Girdwood 5784422b606SLiam Girdwood static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, 579dee89c4dSMark Brown struct snd_pcm_hw_params *params, 580dee89c4dSMark Brown struct snd_soc_dai *dai) 5814422b606SLiam Girdwood { 582*f081a227SKuninori Morimoto struct snd_soc_component *component = dai->component; 583*f081a227SKuninori Morimoto struct wm8750_priv *wm8750 = snd_soc_component_get_drvdata(component); 584*f081a227SKuninori Morimoto u16 iface = snd_soc_component_read32(component, WM8750_IFACE) & 0x1f3; 585*f081a227SKuninori Morimoto u16 srate = snd_soc_component_read32(component, WM8750_SRATE) & 0x1c0; 5864422b606SLiam Girdwood int coeff = get_coeff(wm8750->sysclk, params_rate(params)); 5874422b606SLiam Girdwood 5884422b606SLiam Girdwood /* bit size */ 5897e322dffSMark Brown switch (params_width(params)) { 5907e322dffSMark Brown case 16: 591abadfc92SRichard Purdie break; 5927e322dffSMark Brown case 20: 5934422b606SLiam Girdwood iface |= 0x0004; 594abadfc92SRichard Purdie break; 5957e322dffSMark Brown case 24: 5964422b606SLiam Girdwood iface |= 0x0008; 597abadfc92SRichard Purdie break; 5987e322dffSMark Brown case 32: 5994422b606SLiam Girdwood iface |= 0x000c; 600abadfc92SRichard Purdie break; 601abadfc92SRichard Purdie } 602abadfc92SRichard Purdie 603abadfc92SRichard Purdie /* set iface & srate */ 604*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_IFACE, iface); 6054422b606SLiam Girdwood if (coeff >= 0) 606*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_SRATE, srate | 6074422b606SLiam Girdwood (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); 608abadfc92SRichard Purdie 609abadfc92SRichard Purdie return 0; 610abadfc92SRichard Purdie } 611abadfc92SRichard Purdie 612e550e17fSLiam Girdwood static int wm8750_mute(struct snd_soc_dai *dai, int mute) 613abadfc92SRichard Purdie { 614*f081a227SKuninori Morimoto struct snd_soc_component *component = dai->component; 615*f081a227SKuninori Morimoto u16 mute_reg = snd_soc_component_read32(component, WM8750_ADCDAC) & 0xfff7; 6164422b606SLiam Girdwood 617abadfc92SRichard Purdie if (mute) 618*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_ADCDAC, mute_reg | 0x8); 619abadfc92SRichard Purdie else 620*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_ADCDAC, mute_reg); 621abadfc92SRichard Purdie return 0; 622abadfc92SRichard Purdie } 623abadfc92SRichard Purdie 624*f081a227SKuninori Morimoto static int wm8750_set_bias_level(struct snd_soc_component *component, 6250be9898aSMark Brown enum snd_soc_bias_level level) 626abadfc92SRichard Purdie { 627*f081a227SKuninori Morimoto u16 pwr_reg = snd_soc_component_read32(component, WM8750_PWR1) & 0xfe3e; 628abadfc92SRichard Purdie 6290be9898aSMark Brown switch (level) { 6300be9898aSMark Brown case SND_SOC_BIAS_ON: 631abadfc92SRichard Purdie /* set vmid to 50k and unmute dac */ 632*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x00c0); 633abadfc92SRichard Purdie break; 6340be9898aSMark Brown case SND_SOC_BIAS_PREPARE: 635abadfc92SRichard Purdie break; 6360be9898aSMark Brown case SND_SOC_BIAS_STANDBY: 637*f081a227SKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { 638*f081a227SKuninori Morimoto snd_soc_component_cache_sync(component); 6394d4adfc9SAxel Lin 640dd76769dSMark Brown /* Set VMID to 5k */ 641*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x01c1); 642dd76769dSMark Brown 643dd76769dSMark Brown /* ...and ramp */ 644dd76769dSMark Brown msleep(1000); 645dd76769dSMark Brown } 646dd76769dSMark Brown 647abadfc92SRichard Purdie /* mute dac and set vmid to 500k, enable VREF */ 648*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, pwr_reg | 0x0141); 649abadfc92SRichard Purdie break; 6500be9898aSMark Brown case SND_SOC_BIAS_OFF: 651*f081a227SKuninori Morimoto snd_soc_component_write(component, WM8750_PWR1, 0x0001); 652abadfc92SRichard Purdie break; 653abadfc92SRichard Purdie } 654abadfc92SRichard Purdie return 0; 655abadfc92SRichard Purdie } 656abadfc92SRichard Purdie 6574422b606SLiam Girdwood #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 6584422b606SLiam Girdwood SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ 6594422b606SLiam Girdwood SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 6604422b606SLiam Girdwood 6614422b606SLiam Girdwood #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 6624422b606SLiam Girdwood SNDRV_PCM_FMTBIT_S24_LE) 6634422b606SLiam Girdwood 66485e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops wm8750_dai_ops = { 6656335d055SEric Miao .hw_params = wm8750_pcm_hw_params, 6666335d055SEric Miao .digital_mute = wm8750_mute, 6676335d055SEric Miao .set_fmt = wm8750_set_dai_fmt, 6686335d055SEric Miao .set_sysclk = wm8750_set_dai_sysclk, 6696335d055SEric Miao }; 6706335d055SEric Miao 671f0fba2adSLiam Girdwood static struct snd_soc_dai_driver wm8750_dai = { 672f0fba2adSLiam Girdwood .name = "wm8750-hifi", 673abadfc92SRichard Purdie .playback = { 674abadfc92SRichard Purdie .stream_name = "Playback", 675abadfc92SRichard Purdie .channels_min = 1, 676abadfc92SRichard Purdie .channels_max = 2, 6774422b606SLiam Girdwood .rates = WM8750_RATES, 6784422b606SLiam Girdwood .formats = WM8750_FORMATS,}, 679abadfc92SRichard Purdie .capture = { 680abadfc92SRichard Purdie .stream_name = "Capture", 681abadfc92SRichard Purdie .channels_min = 1, 682abadfc92SRichard Purdie .channels_max = 2, 6834422b606SLiam Girdwood .rates = WM8750_RATES, 6844422b606SLiam Girdwood .formats = WM8750_FORMATS,}, 6856335d055SEric Miao .ops = &wm8750_dai_ops, 686abadfc92SRichard Purdie }; 687abadfc92SRichard Purdie 688*f081a227SKuninori Morimoto static int wm8750_probe(struct snd_soc_component *component) 6896ca0c22eSMarek Vasut { 690f5b00d02SAxel Lin int ret; 6916ca0c22eSMarek Vasut 692*f081a227SKuninori Morimoto ret = wm8750_reset(component); 69317a52fd6SMark Brown if (ret < 0) { 69417a52fd6SMark Brown printk(KERN_ERR "wm8750: failed to reset: %d\n", ret); 695f0fba2adSLiam Girdwood return ret; 69617a52fd6SMark Brown } 697abadfc92SRichard Purdie 698abadfc92SRichard Purdie /* set the update bits */ 699*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LDAC, 0x0100, 0x0100); 700*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_RDAC, 0x0100, 0x0100); 701*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LOUT1V, 0x0100, 0x0100); 702*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_ROUT1V, 0x0100, 0x0100); 703*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LOUT2V, 0x0100, 0x0100); 704*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_ROUT2V, 0x0100, 0x0100); 705*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_LINVOL, 0x0100, 0x0100); 706*f081a227SKuninori Morimoto snd_soc_component_update_bits(component, WM8750_RINVOL, 0x0100, 0x0100); 707abadfc92SRichard Purdie 708abadfc92SRichard Purdie return ret; 709abadfc92SRichard Purdie } 710abadfc92SRichard Purdie 711*f081a227SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_wm8750 = { 712f0fba2adSLiam Girdwood .probe = wm8750_probe, 713f0fba2adSLiam Girdwood .set_bias_level = wm8750_set_bias_level, 7140f185e3fSMark Brown .controls = wm8750_snd_controls, 7150f185e3fSMark Brown .num_controls = ARRAY_SIZE(wm8750_snd_controls), 7160f185e3fSMark Brown .dapm_widgets = wm8750_dapm_widgets, 7170f185e3fSMark Brown .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets), 7180f185e3fSMark Brown .dapm_routes = wm8750_dapm_routes, 7190f185e3fSMark Brown .num_dapm_routes = ARRAY_SIZE(wm8750_dapm_routes), 720*f081a227SKuninori Morimoto .suspend_bias_off = 1, 721*f081a227SKuninori Morimoto .idle_bias_on = 1, 722*f081a227SKuninori Morimoto .use_pmdown_time = 1, 723*f081a227SKuninori Morimoto .endianness = 1, 724*f081a227SKuninori Morimoto .non_legacy_dai_naming = 1, 725f0fba2adSLiam Girdwood }; 726abadfc92SRichard Purdie 727ce31a0f5SMark Brown static const struct of_device_id wm8750_of_match[] = { 728ce31a0f5SMark Brown { .compatible = "wlf,wm8750", }, 729ce31a0f5SMark Brown { .compatible = "wlf,wm8987", }, 730ce31a0f5SMark Brown { } 731ce31a0f5SMark Brown }; 732ce31a0f5SMark Brown MODULE_DEVICE_TABLE(of, wm8750_of_match); 733ce31a0f5SMark Brown 734ed79edacSMark Brown static const struct regmap_config wm8750_regmap = { 735ed79edacSMark Brown .reg_bits = 7, 736ed79edacSMark Brown .val_bits = 9, 737ed79edacSMark Brown .max_register = WM8750_MOUTV, 738ed79edacSMark Brown 739ed79edacSMark Brown .reg_defaults = wm8750_reg_defaults, 740ed79edacSMark Brown .num_reg_defaults = ARRAY_SIZE(wm8750_reg_defaults), 741ed79edacSMark Brown .cache_type = REGCACHE_RBTREE, 742ed79edacSMark Brown }; 743ed79edacSMark Brown 744f0fba2adSLiam Girdwood #if defined(CONFIG_SPI_MASTER) 7457a79e94eSBill Pemberton static int wm8750_spi_probe(struct spi_device *spi) 746abadfc92SRichard Purdie { 7476ca0c22eSMarek Vasut struct wm8750_priv *wm8750; 748ed79edacSMark Brown struct regmap *regmap; 749f0fba2adSLiam Girdwood int ret; 750abadfc92SRichard Purdie 7512edaed82SMark Brown wm8750 = devm_kzalloc(&spi->dev, sizeof(struct wm8750_priv), 7522edaed82SMark Brown GFP_KERNEL); 7536ca0c22eSMarek Vasut if (wm8750 == NULL) 7546ca0c22eSMarek Vasut return -ENOMEM; 7556ca0c22eSMarek Vasut 756ed79edacSMark Brown regmap = devm_regmap_init_spi(spi, &wm8750_regmap); 757ed79edacSMark Brown if (IS_ERR(regmap)) 758ed79edacSMark Brown return PTR_ERR(regmap); 759ed79edacSMark Brown 760f0fba2adSLiam Girdwood spi_set_drvdata(spi, wm8750); 761abadfc92SRichard Purdie 762*f081a227SKuninori Morimoto ret = devm_snd_soc_register_component(&spi->dev, 763*f081a227SKuninori Morimoto &soc_component_dev_wm8750, &wm8750_dai, 1); 764f0fba2adSLiam Girdwood return ret; 765abadfc92SRichard Purdie } 766abadfc92SRichard Purdie 76740045a85SMark Brown static const struct spi_device_id wm8750_spi_ids[] = { 76840045a85SMark Brown { "wm8750", 0 }, 76940045a85SMark Brown { "wm8987", 0 }, 770f6b864a9STakashi Iwai { }, 77140045a85SMark Brown }; 772511d8cf0SMark Brown MODULE_DEVICE_TABLE(spi, wm8750_spi_ids); 77340045a85SMark Brown 774f0fba2adSLiam Girdwood static struct spi_driver wm8750_spi_driver = { 775f0fba2adSLiam Girdwood .driver = { 776dc5de62bSMark Brown .name = "wm8750", 777ce31a0f5SMark Brown .of_match_table = wm8750_of_match, 778f0fba2adSLiam Girdwood }, 77940045a85SMark Brown .id_table = wm8750_spi_ids, 780f0fba2adSLiam Girdwood .probe = wm8750_spi_probe, 781f0fba2adSLiam Girdwood }; 782f0fba2adSLiam Girdwood #endif /* CONFIG_SPI_MASTER */ 783f0fba2adSLiam Girdwood 7849ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C) 7857a79e94eSBill Pemberton static int wm8750_i2c_probe(struct i2c_client *i2c, 786f0fba2adSLiam Girdwood const struct i2c_device_id *id) 787f0fba2adSLiam Girdwood { 788f0fba2adSLiam Girdwood struct wm8750_priv *wm8750; 789ed79edacSMark Brown struct regmap *regmap; 790f0fba2adSLiam Girdwood int ret; 791f0fba2adSLiam Girdwood 7922edaed82SMark Brown wm8750 = devm_kzalloc(&i2c->dev, sizeof(struct wm8750_priv), 7932edaed82SMark Brown GFP_KERNEL); 794f0fba2adSLiam Girdwood if (wm8750 == NULL) 795f0fba2adSLiam Girdwood return -ENOMEM; 796f0fba2adSLiam Girdwood 797f0fba2adSLiam Girdwood i2c_set_clientdata(i2c, wm8750); 798ed79edacSMark Brown 799ed79edacSMark Brown regmap = devm_regmap_init_i2c(i2c, &wm8750_regmap); 800ed79edacSMark Brown if (IS_ERR(regmap)) 801ed79edacSMark Brown return PTR_ERR(regmap); 802f0fba2adSLiam Girdwood 803*f081a227SKuninori Morimoto ret = devm_snd_soc_register_component(&i2c->dev, 804*f081a227SKuninori Morimoto &soc_component_dev_wm8750, &wm8750_dai, 1); 805f0fba2adSLiam Girdwood return ret; 806f0fba2adSLiam Girdwood } 807f0fba2adSLiam Girdwood 808ee1d0099SJean Delvare static const struct i2c_device_id wm8750_i2c_id[] = { 809ee1d0099SJean Delvare { "wm8750", 0 }, 810f0fba2adSLiam Girdwood { "wm8987", 0 }, 811ee1d0099SJean Delvare { } 812ee1d0099SJean Delvare }; 813ee1d0099SJean Delvare MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); 814abadfc92SRichard Purdie 815abadfc92SRichard Purdie static struct i2c_driver wm8750_i2c_driver = { 816abadfc92SRichard Purdie .driver = { 817dc5de62bSMark Brown .name = "wm8750", 818ce31a0f5SMark Brown .of_match_table = wm8750_of_match, 819abadfc92SRichard Purdie }, 820ee1d0099SJean Delvare .probe = wm8750_i2c_probe, 821ee1d0099SJean Delvare .id_table = wm8750_i2c_id, 822abadfc92SRichard Purdie }; 823abadfc92SRichard Purdie #endif 824abadfc92SRichard Purdie 825c9b3a40fSTakashi Iwai static int __init wm8750_modinit(void) 82664089b84SMark Brown { 827f0fba2adSLiam Girdwood int ret = 0; 8289ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C) 8296ca0c22eSMarek Vasut ret = i2c_add_driver(&wm8750_i2c_driver); 830f0fba2adSLiam Girdwood if (ret != 0) { 831f0fba2adSLiam Girdwood printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n", 832f0fba2adSLiam Girdwood ret); 833f0fba2adSLiam Girdwood } 8346ca0c22eSMarek Vasut #endif 8356ca0c22eSMarek Vasut #if defined(CONFIG_SPI_MASTER) 8366ca0c22eSMarek Vasut ret = spi_register_driver(&wm8750_spi_driver); 837f0fba2adSLiam Girdwood if (ret != 0) { 838f0fba2adSLiam Girdwood printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n", 839f0fba2adSLiam Girdwood ret); 840f0fba2adSLiam Girdwood } 8416ca0c22eSMarek Vasut #endif 842f0fba2adSLiam Girdwood return ret; 84364089b84SMark Brown } 84464089b84SMark Brown module_init(wm8750_modinit); 84564089b84SMark Brown 84664089b84SMark Brown static void __exit wm8750_exit(void) 84764089b84SMark Brown { 8489ea6fbc6SFabio Estevam #if IS_ENABLED(CONFIG_I2C) 8496ca0c22eSMarek Vasut i2c_del_driver(&wm8750_i2c_driver); 8506ca0c22eSMarek Vasut #endif 8516ca0c22eSMarek Vasut #if defined(CONFIG_SPI_MASTER) 8526ca0c22eSMarek Vasut spi_unregister_driver(&wm8750_spi_driver); 8536ca0c22eSMarek Vasut #endif 85464089b84SMark Brown } 85564089b84SMark Brown module_exit(wm8750_exit); 85664089b84SMark Brown 857abadfc92SRichard Purdie MODULE_DESCRIPTION("ASoC WM8750 driver"); 858abadfc92SRichard Purdie MODULE_AUTHOR("Liam Girdwood"); 859abadfc92SRichard Purdie MODULE_LICENSE("GPL"); 860