brintos

brintos / linux-shallow public Read only

0
0
Text · 25.7 KiB · f0e9d6e Raw
949 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * wm8988.c -- WM8988 ALSA SoC audio driver4 *5 * Copyright 2009 Wolfson Microelectronics plc6 * Copyright 2005 Openedhand Ltd.7 *8 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>9 */10 11#include <linux/module.h>12#include <linux/moduleparam.h>13#include <linux/init.h>14#include <linux/delay.h>15#include <linux/pm.h>16#include <linux/i2c.h>17#include <linux/spi/spi.h>18#include <linux/slab.h>19#include <sound/core.h>20#include <sound/pcm.h>21#include <sound/pcm_params.h>22#include <sound/tlv.h>23#include <sound/soc.h>24#include <sound/initval.h>25 26#include "wm8988.h"27 28/*29 * wm8988 register cache30 * We can't read the WM8988 register space when we31 * are using 2 wire for device control, so we cache them instead.32 */33static const struct reg_default wm8988_reg_defaults[] = {34	{ 0, 0x0097 },35	{ 1, 0x0097 },36	{ 2, 0x0079 },37	{ 3, 0x0079 },38	{ 5, 0x0008 },39	{ 7, 0x000a },40	{ 8, 0x0000 },41	{ 10, 0x00ff },42	{ 11, 0x00ff },43	{ 12, 0x000f },44	{ 13, 0x000f },45	{ 16, 0x0000 },46	{ 17, 0x007b },47	{ 18, 0x0000 },48	{ 19, 0x0032 },49	{ 20, 0x0000 },50	{ 21, 0x00c3 },51	{ 22, 0x00c3 },52	{ 23, 0x00c0 },53	{ 24, 0x0000 },54	{ 25, 0x0000 },55	{ 26, 0x0000 },56	{ 27, 0x0000 },57	{ 31, 0x0000 },58	{ 32, 0x0000 },59	{ 33, 0x0000 },60	{ 34, 0x0050 },61	{ 35, 0x0050 },62	{ 36, 0x0050 },63	{ 37, 0x0050 },64	{ 40, 0x0079 },65	{ 41, 0x0079 },66	{ 42, 0x0079 },67};68 69static bool wm8988_writeable(struct device *dev, unsigned int reg)70{71	switch (reg) {72	case WM8988_LINVOL:73	case WM8988_RINVOL:74	case WM8988_LOUT1V:75	case WM8988_ROUT1V:76	case WM8988_ADCDAC:77	case WM8988_IFACE:78	case WM8988_SRATE:79	case WM8988_LDAC:80	case WM8988_RDAC:81	case WM8988_BASS:82	case WM8988_TREBLE:83	case WM8988_RESET:84	case WM8988_3D:85	case WM8988_ALC1:86	case WM8988_ALC2:87	case WM8988_ALC3:88	case WM8988_NGATE:89	case WM8988_LADC:90	case WM8988_RADC:91	case WM8988_ADCTL1:92	case WM8988_ADCTL2:93	case WM8988_PWR1:94	case WM8988_PWR2:95	case WM8988_ADCTL3:96	case WM8988_ADCIN:97	case WM8988_LADCIN:98	case WM8988_RADCIN:99	case WM8988_LOUTM1:100	case WM8988_LOUTM2:101	case WM8988_ROUTM1:102	case WM8988_ROUTM2:103	case WM8988_LOUT2V:104	case WM8988_ROUT2V:105	case WM8988_LPPB:106		return true;107	default:108		return false;109	}110}111 112/* codec private data */113struct wm8988_priv {114	struct regmap *regmap;115	unsigned int sysclk;116	const struct snd_pcm_hw_constraint_list *sysclk_constraints;117};118 119#define wm8988_reset(c)	snd_soc_component_write(c, WM8988_RESET, 0)120 121/*122 * WM8988 Controls123 */124 125static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"};126static SOC_ENUM_SINGLE_DECL(bass_boost,127			    WM8988_BASS, 7, bass_boost_txt);128 129static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" };130static SOC_ENUM_SINGLE_DECL(bass_filter,131			    WM8988_BASS, 6, bass_filter_txt);132 133static const char *treble_txt[] = {"8kHz", "4kHz"};134static SOC_ENUM_SINGLE_DECL(treble,135			    WM8988_TREBLE, 6, treble_txt);136 137static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"};138static SOC_ENUM_SINGLE_DECL(stereo_3d_lc,139			    WM8988_3D, 5, stereo_3d_lc_txt);140 141static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"};142static SOC_ENUM_SINGLE_DECL(stereo_3d_uc,143			    WM8988_3D, 6, stereo_3d_uc_txt);144 145static const char *stereo_3d_func_txt[] = {"Capture", "Playback"};146static SOC_ENUM_SINGLE_DECL(stereo_3d_func,147			    WM8988_3D, 7, stereo_3d_func_txt);148 149static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"};150static SOC_ENUM_SINGLE_DECL(alc_func,151			    WM8988_ALC1, 7, alc_func_txt);152 153static const char *ng_type_txt[] = {"Constant PGA Gain",154				    "Mute ADC Output"};155static SOC_ENUM_SINGLE_DECL(ng_type,156			    WM8988_NGATE, 1, ng_type_txt);157 158static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"};159static SOC_ENUM_SINGLE_DECL(deemph,160			    WM8988_ADCDAC, 1, deemph_txt);161 162static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert",163				   "L + R Invert"};164static SOC_ENUM_SINGLE_DECL(adcpol,165			    WM8988_ADCDAC, 5, adcpol_txt);166 167static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0);168static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);169static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);170static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);171static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);172 173static const struct snd_kcontrol_new wm8988_snd_controls[] = {174 175SOC_ENUM("Bass Boost", bass_boost),176SOC_ENUM("Bass Filter", bass_filter),177SOC_SINGLE("Bass Volume", WM8988_BASS, 0, 15, 1),178 179SOC_SINGLE("Treble Volume", WM8988_TREBLE, 0, 15, 0),180SOC_ENUM("Treble Cut-off", treble),181 182SOC_SINGLE("3D Switch", WM8988_3D, 0, 1, 0),183SOC_SINGLE("3D Volume", WM8988_3D, 1, 15, 0),184SOC_ENUM("3D Lower Cut-off", stereo_3d_lc),185SOC_ENUM("3D Upper Cut-off", stereo_3d_uc),186SOC_ENUM("3D Mode", stereo_3d_func),187 188SOC_SINGLE("ALC Capture Target Volume", WM8988_ALC1, 0, 7, 0),189SOC_SINGLE("ALC Capture Max Volume", WM8988_ALC1, 4, 7, 0),190SOC_ENUM("ALC Capture Function", alc_func),191SOC_SINGLE("ALC Capture ZC Switch", WM8988_ALC2, 7, 1, 0),192SOC_SINGLE("ALC Capture Hold Time", WM8988_ALC2, 0, 15, 0),193SOC_SINGLE("ALC Capture Decay Time", WM8988_ALC3, 4, 15, 0),194SOC_SINGLE("ALC Capture Attack Time", WM8988_ALC3, 0, 15, 0),195SOC_SINGLE("ALC Capture NG Threshold", WM8988_NGATE, 3, 31, 0),196SOC_ENUM("ALC Capture NG Type", ng_type),197SOC_SINGLE("ALC Capture NG Switch", WM8988_NGATE, 0, 1, 0),198 199SOC_SINGLE("ZC Timeout Switch", WM8988_ADCTL1, 0, 1, 0),200 201SOC_DOUBLE_R_TLV("Capture Digital Volume", WM8988_LADC, WM8988_RADC,202		 0, 255, 0, adc_tlv),203SOC_DOUBLE_R_TLV("Capture Volume", WM8988_LINVOL, WM8988_RINVOL,204		 0, 63, 0, pga_tlv),205SOC_DOUBLE_R("Capture ZC Switch", WM8988_LINVOL, WM8988_RINVOL, 6, 1, 0),206SOC_DOUBLE_R("Capture Switch", WM8988_LINVOL, WM8988_RINVOL, 7, 1, 1),207 208SOC_ENUM("Playback De-emphasis", deemph),209 210SOC_ENUM("Capture Polarity", adcpol),211SOC_SINGLE("Playback 6dB Attenuate", WM8988_ADCDAC, 7, 1, 0),212SOC_SINGLE("Capture 6dB Attenuate", WM8988_ADCDAC, 8, 1, 0),213 214SOC_DOUBLE_R_TLV("PCM Volume", WM8988_LDAC, WM8988_RDAC, 0, 255, 0, dac_tlv),215 216SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", WM8988_LOUTM1, 4, 7, 1,217	       bypass_tlv),218SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", WM8988_LOUTM2, 4, 7, 1,219	       bypass_tlv),220SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", WM8988_ROUTM1, 4, 7, 1,221	       bypass_tlv),222SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", WM8988_ROUTM2, 4, 7, 1,223	       bypass_tlv),224 225SOC_DOUBLE_R("Output 1 Playback ZC Switch", WM8988_LOUT1V,226	     WM8988_ROUT1V, 7, 1, 0),227SOC_DOUBLE_R_TLV("Output 1 Playback Volume", WM8988_LOUT1V, WM8988_ROUT1V,228		 0, 127, 0, out_tlv),229 230SOC_DOUBLE_R("Output 2 Playback ZC Switch", WM8988_LOUT2V,231	     WM8988_ROUT2V, 7, 1, 0),232SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,233		 0, 127, 0, out_tlv),234 235};236 237/*238 * DAPM Controls239 */240 241static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,242			      struct snd_kcontrol *kcontrol, int event)243{244	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);245	u16 adctl2 = snd_soc_component_read(component, WM8988_ADCTL2);246 247	/* Use the DAC to gate LRC if active, otherwise use ADC */248	if (snd_soc_component_read(component, WM8988_PWR2) & 0x180)249		adctl2 &= ~0x4;250	else251		adctl2 |= 0x4;252 253	return snd_soc_component_write(component, WM8988_ADCTL2, adctl2);254}255 256static const char *wm8988_line_texts[] = {257	"Line 1", "Line 2", "PGA", "Differential"};258 259static const unsigned int wm8988_line_values[] = {260	0, 1, 3, 4};261 262static const struct soc_enum wm8988_lline_enum =263	SOC_VALUE_ENUM_SINGLE(WM8988_LOUTM1, 0, 7,264			      ARRAY_SIZE(wm8988_line_texts),265			      wm8988_line_texts,266			      wm8988_line_values);267static const struct snd_kcontrol_new wm8988_left_line_controls =268	SOC_DAPM_ENUM("Route", wm8988_lline_enum);269 270static const struct soc_enum wm8988_rline_enum =271	SOC_VALUE_ENUM_SINGLE(WM8988_ROUTM1, 0, 7,272			      ARRAY_SIZE(wm8988_line_texts),273			      wm8988_line_texts,274			      wm8988_line_values);275static const struct snd_kcontrol_new wm8988_right_line_controls =276	SOC_DAPM_ENUM("Route", wm8988_rline_enum);277 278/* Left Mixer */279static const struct snd_kcontrol_new wm8988_left_mixer_controls[] = {280	SOC_DAPM_SINGLE("Playback Switch", WM8988_LOUTM1, 8, 1, 0),281	SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_LOUTM1, 7, 1, 0),282	SOC_DAPM_SINGLE("Right Playback Switch", WM8988_LOUTM2, 8, 1, 0),283	SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_LOUTM2, 7, 1, 0),284};285 286/* Right Mixer */287static const struct snd_kcontrol_new wm8988_right_mixer_controls[] = {288	SOC_DAPM_SINGLE("Left Playback Switch", WM8988_ROUTM1, 8, 1, 0),289	SOC_DAPM_SINGLE("Left Bypass Switch", WM8988_ROUTM1, 7, 1, 0),290	SOC_DAPM_SINGLE("Playback Switch", WM8988_ROUTM2, 8, 1, 0),291	SOC_DAPM_SINGLE("Right Bypass Switch", WM8988_ROUTM2, 7, 1, 0),292};293 294static const char *wm8988_pga_sel[] = {"Line 1", "Line 2", "Differential"};295static const unsigned int wm8988_pga_val[] = { 0, 1, 3 };296 297/* Left PGA Mux */298static const struct soc_enum wm8988_lpga_enum =299	SOC_VALUE_ENUM_SINGLE(WM8988_LADCIN, 6, 3,300			      ARRAY_SIZE(wm8988_pga_sel),301			      wm8988_pga_sel,302			      wm8988_pga_val);303static const struct snd_kcontrol_new wm8988_left_pga_controls =304	SOC_DAPM_ENUM("Route", wm8988_lpga_enum);305 306/* Right PGA Mux */307static const struct soc_enum wm8988_rpga_enum =308	SOC_VALUE_ENUM_SINGLE(WM8988_RADCIN, 6, 3,309			      ARRAY_SIZE(wm8988_pga_sel),310			      wm8988_pga_sel,311			      wm8988_pga_val);312static const struct snd_kcontrol_new wm8988_right_pga_controls =313	SOC_DAPM_ENUM("Route", wm8988_rpga_enum);314 315/* Differential Mux */316static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"};317static SOC_ENUM_SINGLE_DECL(diffmux,318			    WM8988_ADCIN, 8, wm8988_diff_sel);319static const struct snd_kcontrol_new wm8988_diffmux_controls =320	SOC_DAPM_ENUM("Route", diffmux);321 322/* Mono ADC Mux */323static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)",324	"Mono (Right)", "Digital Mono"};325static SOC_ENUM_SINGLE_DECL(monomux,326			    WM8988_ADCIN, 6, wm8988_mono_mux);327static const struct snd_kcontrol_new wm8988_monomux_controls =328	SOC_DAPM_ENUM("Route", monomux);329 330static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = {331	SND_SOC_DAPM_SUPPLY("Mic Bias", WM8988_PWR1, 1, 0, NULL, 0),332 333	SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0,334		&wm8988_diffmux_controls),335	SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,336		&wm8988_monomux_controls),337	SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0,338		&wm8988_monomux_controls),339 340	SND_SOC_DAPM_MUX("Left PGA Mux", WM8988_PWR1, 5, 0,341		&wm8988_left_pga_controls),342	SND_SOC_DAPM_MUX("Right PGA Mux", WM8988_PWR1, 4, 0,343		&wm8988_right_pga_controls),344 345	SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0,346		&wm8988_left_line_controls),347	SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0,348		&wm8988_right_line_controls),349 350	SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0),351	SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0),352 353	SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),354	SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),355 356	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,357		&wm8988_left_mixer_controls[0],358		ARRAY_SIZE(wm8988_left_mixer_controls)),359	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,360		&wm8988_right_mixer_controls[0],361		ARRAY_SIZE(wm8988_right_mixer_controls)),362 363	SND_SOC_DAPM_PGA("Right Out 2", WM8988_PWR2, 3, 0, NULL, 0),364	SND_SOC_DAPM_PGA("Left Out 2", WM8988_PWR2, 4, 0, NULL, 0),365	SND_SOC_DAPM_PGA("Right Out 1", WM8988_PWR2, 5, 0, NULL, 0),366	SND_SOC_DAPM_PGA("Left Out 1", WM8988_PWR2, 6, 0, NULL, 0),367 368	SND_SOC_DAPM_POST("LRC control", wm8988_lrc_control),369 370	SND_SOC_DAPM_OUTPUT("LOUT1"),371	SND_SOC_DAPM_OUTPUT("ROUT1"),372	SND_SOC_DAPM_OUTPUT("LOUT2"),373	SND_SOC_DAPM_OUTPUT("ROUT2"),374	SND_SOC_DAPM_OUTPUT("VREF"),375 376	SND_SOC_DAPM_INPUT("LINPUT1"),377	SND_SOC_DAPM_INPUT("LINPUT2"),378	SND_SOC_DAPM_INPUT("RINPUT1"),379	SND_SOC_DAPM_INPUT("RINPUT2"),380};381 382static const struct snd_soc_dapm_route wm8988_dapm_routes[] = {383 384	{ "Left Line Mux", "Line 1", "LINPUT1" },385	{ "Left Line Mux", "Line 2", "LINPUT2" },386	{ "Left Line Mux", "PGA", "Left PGA Mux" },387	{ "Left Line Mux", "Differential", "Differential Mux" },388 389	{ "Right Line Mux", "Line 1", "RINPUT1" },390	{ "Right Line Mux", "Line 2", "RINPUT2" },391	{ "Right Line Mux", "PGA", "Right PGA Mux" },392	{ "Right Line Mux", "Differential", "Differential Mux" },393 394	{ "Left PGA Mux", "Line 1", "LINPUT1" },395	{ "Left PGA Mux", "Line 2", "LINPUT2" },396	{ "Left PGA Mux", "Differential", "Differential Mux" },397 398	{ "Right PGA Mux", "Line 1", "RINPUT1" },399	{ "Right PGA Mux", "Line 2", "RINPUT2" },400	{ "Right PGA Mux", "Differential", "Differential Mux" },401 402	{ "Differential Mux", "Line 1", "LINPUT1" },403	{ "Differential Mux", "Line 1", "RINPUT1" },404	{ "Differential Mux", "Line 2", "LINPUT2" },405	{ "Differential Mux", "Line 2", "RINPUT2" },406 407	{ "Left ADC Mux", "Stereo", "Left PGA Mux" },408	{ "Left ADC Mux", "Mono (Left)", "Left PGA Mux" },409	{ "Left ADC Mux", "Digital Mono", "Left PGA Mux" },410 411	{ "Right ADC Mux", "Stereo", "Right PGA Mux" },412	{ "Right ADC Mux", "Mono (Right)", "Right PGA Mux" },413	{ "Right ADC Mux", "Digital Mono", "Right PGA Mux" },414 415	{ "Left ADC", NULL, "Left ADC Mux" },416	{ "Right ADC", NULL, "Right ADC Mux" },417 418	{ "Left Line Mux", "Line 1", "LINPUT1" },419	{ "Left Line Mux", "Line 2", "LINPUT2" },420	{ "Left Line Mux", "PGA", "Left PGA Mux" },421	{ "Left Line Mux", "Differential", "Differential Mux" },422 423	{ "Right Line Mux", "Line 1", "RINPUT1" },424	{ "Right Line Mux", "Line 2", "RINPUT2" },425	{ "Right Line Mux", "PGA", "Right PGA Mux" },426	{ "Right Line Mux", "Differential", "Differential Mux" },427 428	{ "Left Mixer", "Playback Switch", "Left DAC" },429	{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },430	{ "Left Mixer", "Right Playback Switch", "Right DAC" },431	{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" },432 433	{ "Right Mixer", "Left Playback Switch", "Left DAC" },434	{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" },435	{ "Right Mixer", "Playback Switch", "Right DAC" },436	{ "Right Mixer", "Right Bypass Switch", "Right Line Mux" },437 438	{ "Left Out 1", NULL, "Left Mixer" },439	{ "LOUT1", NULL, "Left Out 1" },440	{ "Right Out 1", NULL, "Right Mixer" },441	{ "ROUT1", NULL, "Right Out 1" },442 443	{ "Left Out 2", NULL, "Left Mixer" },444	{ "LOUT2", NULL, "Left Out 2" },445	{ "Right Out 2", NULL, "Right Mixer" },446	{ "ROUT2", NULL, "Right Out 2" },447};448 449struct _coeff_div {450	u32 mclk;451	u32 rate;452	u16 fs;453	u8 sr:5;454	u8 usb:1;455};456 457/* codec hifi mclk clock divider coefficients */458static const struct _coeff_div coeff_div[] = {459	/* 8k */460	{12288000, 8000, 1536, 0x6, 0x0},461	{11289600, 8000, 1408, 0x16, 0x0},462	{18432000, 8000, 2304, 0x7, 0x0},463	{16934400, 8000, 2112, 0x17, 0x0},464	{12000000, 8000, 1500, 0x6, 0x1},465 466	/* 11.025k */467	{11289600, 11025, 1024, 0x18, 0x0},468	{16934400, 11025, 1536, 0x19, 0x0},469	{12000000, 11025, 1088, 0x19, 0x1},470 471	/* 16k */472	{12288000, 16000, 768, 0xa, 0x0},473	{18432000, 16000, 1152, 0xb, 0x0},474	{12000000, 16000, 750, 0xa, 0x1},475 476	/* 22.05k */477	{11289600, 22050, 512, 0x1a, 0x0},478	{16934400, 22050, 768, 0x1b, 0x0},479	{12000000, 22050, 544, 0x1b, 0x1},480 481	/* 32k */482	{12288000, 32000, 384, 0xc, 0x0},483	{18432000, 32000, 576, 0xd, 0x0},484	{12000000, 32000, 375, 0xa, 0x1},485 486	/* 44.1k */487	{11289600, 44100, 256, 0x10, 0x0},488	{16934400, 44100, 384, 0x11, 0x0},489	{12000000, 44100, 272, 0x11, 0x1},490 491	/* 48k */492	{12288000, 48000, 256, 0x0, 0x0},493	{18432000, 48000, 384, 0x1, 0x0},494	{12000000, 48000, 250, 0x0, 0x1},495 496	/* 88.2k */497	{11289600, 88200, 128, 0x1e, 0x0},498	{16934400, 88200, 192, 0x1f, 0x0},499	{12000000, 88200, 136, 0x1f, 0x1},500 501	/* 96k */502	{12288000, 96000, 128, 0xe, 0x0},503	{18432000, 96000, 192, 0xf, 0x0},504	{12000000, 96000, 125, 0xe, 0x1},505};506 507static inline int get_coeff(int mclk, int rate)508{509	int i;510 511	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {512		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)513			return i;514	}515 516	return -EINVAL;517}518 519/* The set of rates we can generate from the above for each SYSCLK */520 521static const unsigned int rates_12288[] = {522	8000, 12000, 16000, 24000, 32000, 48000, 96000,523};524 525static const struct snd_pcm_hw_constraint_list constraints_12288 = {526	.count	= ARRAY_SIZE(rates_12288),527	.list	= rates_12288,528};529 530static const unsigned int rates_112896[] = {531	8000, 11025, 22050, 44100,532};533 534static const struct snd_pcm_hw_constraint_list constraints_112896 = {535	.count	= ARRAY_SIZE(rates_112896),536	.list	= rates_112896,537};538 539static const unsigned int rates_12[] = {540	8000, 11025, 12000, 16000, 22050, 24000, 32000, 41100, 48000,541	48000, 88235, 96000,542};543 544static const struct snd_pcm_hw_constraint_list constraints_12 = {545	.count	= ARRAY_SIZE(rates_12),546	.list	= rates_12,547};548 549/*550 * Note that this should be called from init rather than from hw_params.551 */552static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai,553		int clk_id, unsigned int freq, int dir)554{555	struct snd_soc_component *component = codec_dai->component;556	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);557 558	switch (freq) {559	case 11289600:560	case 18432000:561	case 22579200:562	case 36864000:563		wm8988->sysclk_constraints = &constraints_112896;564		wm8988->sysclk = freq;565		return 0;566 567	case 12288000:568	case 16934400:569	case 24576000:570	case 33868800:571		wm8988->sysclk_constraints = &constraints_12288;572		wm8988->sysclk = freq;573		return 0;574 575	case 12000000:576	case 24000000:577		wm8988->sysclk_constraints = &constraints_12;578		wm8988->sysclk = freq;579		return 0;580	}581	return -EINVAL;582}583 584static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,585		unsigned int fmt)586{587	struct snd_soc_component *component = codec_dai->component;588	u16 iface = 0;589 590	/* set master/slave audio interface */591	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {592	case SND_SOC_DAIFMT_CBM_CFM:593		iface = 0x0040;594		break;595	case SND_SOC_DAIFMT_CBS_CFS:596		break;597	default:598		return -EINVAL;599	}600 601	/* interface format */602	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {603	case SND_SOC_DAIFMT_I2S:604		iface |= 0x0002;605		break;606	case SND_SOC_DAIFMT_RIGHT_J:607		break;608	case SND_SOC_DAIFMT_LEFT_J:609		iface |= 0x0001;610		break;611	case SND_SOC_DAIFMT_DSP_A:612		iface |= 0x0003;613		break;614	case SND_SOC_DAIFMT_DSP_B:615		iface |= 0x0013;616		break;617	default:618		return -EINVAL;619	}620 621	/* clock inversion */622	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {623	case SND_SOC_DAIFMT_NB_NF:624		break;625	case SND_SOC_DAIFMT_IB_IF:626		iface |= 0x0090;627		break;628	case SND_SOC_DAIFMT_IB_NF:629		iface |= 0x0080;630		break;631	case SND_SOC_DAIFMT_NB_IF:632		iface |= 0x0010;633		break;634	default:635		return -EINVAL;636	}637 638	snd_soc_component_write(component, WM8988_IFACE, iface);639	return 0;640}641 642static int wm8988_pcm_startup(struct snd_pcm_substream *substream,643			      struct snd_soc_dai *dai)644{645	struct snd_soc_component *component = dai->component;646	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);647 648	/* The set of sample rates that can be supported depends on the649	 * MCLK supplied to the CODEC - enforce this.650	 */651	if (!wm8988->sysclk) {652		dev_err(component->dev,653			"No MCLK configured, call set_sysclk() on init\n");654		return -EINVAL;655	}656 657	snd_pcm_hw_constraint_list(substream->runtime, 0,658				   SNDRV_PCM_HW_PARAM_RATE,659				   wm8988->sysclk_constraints);660 661	return 0;662}663 664static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,665				struct snd_pcm_hw_params *params,666				struct snd_soc_dai *dai)667{668	struct snd_soc_component *component = dai->component;669	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);670	u16 iface = snd_soc_component_read(component, WM8988_IFACE) & 0x1f3;671	u16 srate = snd_soc_component_read(component, WM8988_SRATE) & 0x180;672	int coeff;673 674	coeff = get_coeff(wm8988->sysclk, params_rate(params));675	if (coeff < 0) {676		coeff = get_coeff(wm8988->sysclk / 2, params_rate(params));677		srate |= 0x40;678	}679	if (coeff < 0) {680		dev_err(component->dev,681			"Unable to configure sample rate %dHz with %dHz MCLK\n",682			params_rate(params), wm8988->sysclk);683		return coeff;684	}685 686	/* bit size */687	switch (params_width(params)) {688	case 16:689		break;690	case 20:691		iface |= 0x0004;692		break;693	case 24:694		iface |= 0x0008;695		break;696	case 32:697		iface |= 0x000c;698		break;699	}700 701	/* set iface & srate */702	snd_soc_component_write(component, WM8988_IFACE, iface);703	if (coeff >= 0)704		snd_soc_component_write(component, WM8988_SRATE, srate |705			(coeff_div[coeff].sr << 1) | coeff_div[coeff].usb);706 707	return 0;708}709 710static int wm8988_mute(struct snd_soc_dai *dai, int mute, int direction)711{712	struct snd_soc_component *component = dai->component;713	u16 mute_reg = snd_soc_component_read(component, WM8988_ADCDAC) & 0xfff7;714 715	if (mute)716		snd_soc_component_write(component, WM8988_ADCDAC, mute_reg | 0x8);717	else718		snd_soc_component_write(component, WM8988_ADCDAC, mute_reg);719	return 0;720}721 722static int wm8988_set_bias_level(struct snd_soc_component *component,723				 enum snd_soc_bias_level level)724{725	struct wm8988_priv *wm8988 = snd_soc_component_get_drvdata(component);726	u16 pwr_reg = snd_soc_component_read(component, WM8988_PWR1) & ~0x1c1;727 728	switch (level) {729	case SND_SOC_BIAS_ON:730		break;731 732	case SND_SOC_BIAS_PREPARE:733		/* VREF, VMID=2x50k, digital enabled */734		snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x00c0);735		break;736 737	case SND_SOC_BIAS_STANDBY:738		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {739			regcache_sync(wm8988->regmap);740 741			/* VREF, VMID=2x5k */742			snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x1c1);743 744			/* Charge caps */745			msleep(100);746		}747 748		/* VREF, VMID=2*500k, digital stopped */749		snd_soc_component_write(component, WM8988_PWR1, pwr_reg | 0x0141);750		break;751 752	case SND_SOC_BIAS_OFF:753		snd_soc_component_write(component, WM8988_PWR1, 0x0000);754		break;755	}756	return 0;757}758 759#define WM8988_RATES SNDRV_PCM_RATE_8000_96000760 761#define WM8988_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\762	SNDRV_PCM_FMTBIT_S24_LE)763 764static const struct snd_soc_dai_ops wm8988_ops = {765	.startup = wm8988_pcm_startup,766	.hw_params = wm8988_pcm_hw_params,767	.set_fmt = wm8988_set_dai_fmt,768	.set_sysclk = wm8988_set_dai_sysclk,769	.mute_stream = wm8988_mute,770	.no_capture_mute = 1,771};772 773static struct snd_soc_dai_driver wm8988_dai = {774	.name = "wm8988-hifi",775	.playback = {776		.stream_name = "Playback",777		.channels_min = 1,778		.channels_max = 2,779		.rates = WM8988_RATES,780		.formats = WM8988_FORMATS,781	},782	.capture = {783		.stream_name = "Capture",784		.channels_min = 1,785		.channels_max = 2,786		.rates = WM8988_RATES,787		.formats = WM8988_FORMATS,788	 },789	.ops = &wm8988_ops,790	.symmetric_rate = 1,791};792 793static int wm8988_probe(struct snd_soc_component *component)794{795	int ret = 0;796 797	ret = wm8988_reset(component);798	if (ret < 0) {799		dev_err(component->dev, "Failed to issue reset\n");800		return ret;801	}802 803	/* set the update bits (we always update left then right) */804	snd_soc_component_update_bits(component, WM8988_RADC, 0x0100, 0x0100);805	snd_soc_component_update_bits(component, WM8988_RDAC, 0x0100, 0x0100);806	snd_soc_component_update_bits(component, WM8988_ROUT1V, 0x0100, 0x0100);807	snd_soc_component_update_bits(component, WM8988_ROUT2V, 0x0100, 0x0100);808	snd_soc_component_update_bits(component, WM8988_RINVOL, 0x0100, 0x0100);809 810	return 0;811}812 813static const struct snd_soc_component_driver soc_component_dev_wm8988 = {814	.probe			= wm8988_probe,815	.set_bias_level		= wm8988_set_bias_level,816	.controls		= wm8988_snd_controls,817	.num_controls		= ARRAY_SIZE(wm8988_snd_controls),818	.dapm_widgets		= wm8988_dapm_widgets,819	.num_dapm_widgets	= ARRAY_SIZE(wm8988_dapm_widgets),820	.dapm_routes		= wm8988_dapm_routes,821	.num_dapm_routes	= ARRAY_SIZE(wm8988_dapm_routes),822	.suspend_bias_off	= 1,823	.idle_bias_on		= 1,824	.use_pmdown_time	= 1,825	.endianness		= 1,826};827 828static const struct regmap_config wm8988_regmap = {829	.reg_bits = 7,830	.val_bits = 9,831 832	.max_register = WM8988_LPPB,833	.writeable_reg = wm8988_writeable,834 835	.cache_type = REGCACHE_MAPLE,836	.reg_defaults = wm8988_reg_defaults,837	.num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults),838};839 840#if defined(CONFIG_SPI_MASTER)841static int wm8988_spi_probe(struct spi_device *spi)842{843	struct wm8988_priv *wm8988;844	int ret;845 846	wm8988 = devm_kzalloc(&spi->dev, sizeof(struct wm8988_priv),847			      GFP_KERNEL);848	if (wm8988 == NULL)849		return -ENOMEM;850 851	wm8988->regmap = devm_regmap_init_spi(spi, &wm8988_regmap);852	if (IS_ERR(wm8988->regmap)) {853		ret = PTR_ERR(wm8988->regmap);854		dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);855		return ret;856	}857 858	spi_set_drvdata(spi, wm8988);859 860	ret = devm_snd_soc_register_component(&spi->dev,861			&soc_component_dev_wm8988, &wm8988_dai, 1);862	return ret;863}864 865static struct spi_driver wm8988_spi_driver = {866	.driver = {867		.name	= "wm8988",868	},869	.probe		= wm8988_spi_probe,870};871#endif /* CONFIG_SPI_MASTER */872 873#if IS_ENABLED(CONFIG_I2C)874static int wm8988_i2c_probe(struct i2c_client *i2c)875{876	struct wm8988_priv *wm8988;877	int ret;878 879	wm8988 = devm_kzalloc(&i2c->dev, sizeof(struct wm8988_priv),880			      GFP_KERNEL);881	if (wm8988 == NULL)882		return -ENOMEM;883 884	i2c_set_clientdata(i2c, wm8988);885 886	wm8988->regmap = devm_regmap_init_i2c(i2c, &wm8988_regmap);887	if (IS_ERR(wm8988->regmap)) {888		ret = PTR_ERR(wm8988->regmap);889		dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);890		return ret;891	}892 893	ret = devm_snd_soc_register_component(&i2c->dev,894			&soc_component_dev_wm8988, &wm8988_dai, 1);895	return ret;896}897 898static const struct i2c_device_id wm8988_i2c_id[] = {899	{ "wm8988" },900	{ }901};902MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);903 904static struct i2c_driver wm8988_i2c_driver = {905	.driver = {906		.name = "wm8988",907	},908	.probe = wm8988_i2c_probe,909	.id_table = wm8988_i2c_id,910};911#endif912 913static int __init wm8988_modinit(void)914{915	int ret = 0;916#if IS_ENABLED(CONFIG_I2C)917	ret = i2c_add_driver(&wm8988_i2c_driver);918	if (ret != 0) {919		printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",920		       ret);921	}922#endif923#if defined(CONFIG_SPI_MASTER)924	ret = spi_register_driver(&wm8988_spi_driver);925	if (ret != 0) {926		printk(KERN_ERR "Failed to register WM8988 SPI driver: %d\n",927		       ret);928	}929#endif930	return ret;931}932module_init(wm8988_modinit);933 934static void __exit wm8988_exit(void)935{936#if IS_ENABLED(CONFIG_I2C)937	i2c_del_driver(&wm8988_i2c_driver);938#endif939#if defined(CONFIG_SPI_MASTER)940	spi_unregister_driver(&wm8988_spi_driver);941#endif942}943module_exit(wm8988_exit);944 945 946MODULE_DESCRIPTION("ASoC WM8988 driver");947MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");948MODULE_LICENSE("GPL");949