15 #include <linux/module.h>
17 #include <linux/kernel.h>
21 #include <linux/i2c.h>
23 #include <linux/slab.h>
45 static const struct reg_default cs42l73_reg_defaults[] = {
138 static bool cs42l73_volatile_register(
struct device *
dev,
unsigned int reg)
149 static bool cs42l73_readable_register(
struct device *dev,
unsigned int reg)
252 static const unsigned int hpaloa_tlv[] = {
266 static const unsigned int limiter_tlv[] = {
274 static const char *
const cs42l73_pgaa_text[] = {
"Line A",
"Mic 1" };
275 static const char *
const cs42l73_pgab_text[] = {
"Line B",
"Mic 2" };
277 static const struct soc_enum pgaa_enum =
279 ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text);
281 static const struct soc_enum pgab_enum =
283 ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text);
305 static const char *
const cs42l73_ng_delay_text[] = {
306 "50ms",
"100ms",
"150ms",
"200ms" };
308 static const struct soc_enum ng_delay_enum =
310 ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text);
312 static const char *
const charge_pump_freq_text[] = {
313 "0",
"1",
"2",
"3",
"4",
314 "5",
"6",
"7",
"8",
"9",
315 "10",
"11",
"12",
"13",
"14",
"15" };
317 static const struct soc_enum charge_pump_enum =
319 ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text);
321 static const char *
const cs42l73_mono_mix_texts[] = {
322 "Left",
"Right",
"Mono Mix"};
324 static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
326 static const struct soc_enum spk_asp_enum =
329 cs42l73_mono_mix_texts,
330 cs42l73_mono_mix_values);
335 static const struct soc_enum spk_xsp_enum =
338 cs42l73_mono_mix_texts,
339 cs42l73_mono_mix_values);
344 static const struct soc_enum esl_asp_enum =
347 cs42l73_mono_mix_texts,
348 cs42l73_mono_mix_values);
353 static const struct soc_enum esl_xsp_enum =
356 cs42l73_mono_mix_texts,
357 cs42l73_mono_mix_values);
362 static const char *
const cs42l73_ip_swap_text[] = {
363 "Stereo",
"Mono A",
"Mono B",
"Swap A-B"};
365 static const struct soc_enum ip_swap_enum =
367 ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text);
369 static const char *
const cs42l73_spo_mixer_text[] = {
"Mono",
"Stereo"};
371 static const struct soc_enum vsp_output_mux_enum =
373 ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
375 static const struct soc_enum xsp_output_mux_enum =
377 ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text);
403 0x41, 0x4B, hpaloa_tlv),
420 0, 0x34, 0xE4, hl_tlv),
511 SOC_ENUM(
"NG Delay", ng_delay_enum),
513 SOC_ENUM(
"Charge Pump Frequency", charge_pump_enum),
585 SOC_ENUM(
"IP Digital Swap/Mono Select", ip_swap_enum),
587 SOC_ENUM(
"VSPOUT Mono/Stereo Select", vsp_output_mux_enum),
588 SOC_ENUM(
"XSPOUT Mono/Stereo Select", xsp_output_mux_enum),
624 0, 0, input_left_mixer,
628 0, 0, input_right_mixer,
661 0, 0, &esl_xsp_mixer),
664 0, 0, &esl_asp_mixer),
667 0, 0, &spk_asp_mixer),
670 0, 0, &spk_xsp_mixer),
700 {
"EAROUT",
NULL,
"EAR Amp"},
701 {
"SPKLINEOUT",
NULL,
"SPKLO Amp"},
703 {
"EAR Amp",
"Switch",
"ESL DAC"},
704 {
"SPKLO Amp",
"Switch",
"ESL DAC"},
706 {
"ESL DAC",
"ESL-ASP Mono Volume",
"ESL Mixer"},
707 {
"ESL DAC",
"ESL-XSP Mono Volume",
"ESL Mixer"},
708 {
"ESL DAC",
"ESL-VSP Mono Volume",
"VSPIN"},
710 {
"ESL DAC",
"ESL-IP Mono Volume",
"Input Left Capture"},
711 {
"ESL DAC",
"ESL-IP Mono Volume",
"Input Right Capture"},
713 {
"ESL Mixer",
NULL,
"ESL-ASP Mux"},
714 {
"ESL Mixer",
NULL,
"ESL-XSP Mux"},
716 {
"ESL-ASP Mux",
"Left",
"ASPINL"},
717 {
"ESL-ASP Mux",
"Right",
"ASPINR"},
718 {
"ESL-ASP Mux",
"Mono Mix",
"ASPINM"},
720 {
"ESL-XSP Mux",
"Left",
"XSPINL"},
721 {
"ESL-XSP Mux",
"Right",
"XSPINR"},
722 {
"ESL-XSP Mux",
"Mono Mix",
"XSPINM"},
725 {
"SPKOUT",
NULL,
"SPK Amp"},
726 {
"SPK Amp",
"Switch",
"SPK DAC"},
728 {
"SPK DAC",
"SPK-ASP Mono Volume",
"SPK Mixer"},
729 {
"SPK DAC",
"SPK-XSP Mono Volume",
"SPK Mixer"},
730 {
"SPK DAC",
"SPK-VSP Mono Volume",
"VSPIN"},
732 {
"SPK DAC",
"SPK-IP Mono Volume",
"Input Left Capture"},
733 {
"SPK DAC",
"SPK-IP Mono Volume",
"Input Right Capture"},
735 {
"SPK Mixer",
NULL,
"SPK-ASP Mux"},
736 {
"SPK Mixer",
NULL,
"SPK-XSP Mux"},
738 {
"SPK-ASP Mux",
"Left",
"ASPINL"},
739 {
"SPK-ASP Mux",
"Mono Mix",
"ASPINM"},
740 {
"SPK-ASP Mux",
"Right",
"ASPINR"},
742 {
"SPK-XSP Mux",
"Left",
"XSPINL"},
743 {
"SPK-XSP Mux",
"Mono Mix",
"XSPINM"},
744 {
"SPK-XSP Mux",
"Right",
"XSPINR"},
747 {
"HPOUTA",
NULL,
"HP Amp"},
748 {
"HPOUTB",
NULL,
"HP Amp"},
749 {
"LINEOUTA",
NULL,
"LO Amp"},
750 {
"LINEOUTB",
NULL,
"LO Amp"},
752 {
"HP Amp",
"Switch",
"HL Left DAC"},
753 {
"HP Amp",
"Switch",
"HL Right DAC"},
754 {
"LO Amp",
"Switch",
"HL Left DAC"},
755 {
"LO Amp",
"Switch",
"HL Right DAC"},
757 {
"HL Left DAC",
"HL-XSP Volume",
"HL Left Mixer"},
758 {
"HL Right DAC",
"HL-XSP Volume",
"HL Right Mixer"},
759 {
"HL Left DAC",
"HL-ASP Volume",
"HL Left Mixer"},
760 {
"HL Right DAC",
"HL-ASP Volume",
"HL Right Mixer"},
761 {
"HL Left DAC",
"HL-VSP Volume",
"HL Left Mixer"},
762 {
"HL Right DAC",
"HL-VSP Volume",
"HL Right Mixer"},
764 {
"HL Left DAC",
"HL-IP Volume",
"HL Left Mixer"},
765 {
"HL Right DAC",
"HL-IP Volume",
"HL Right Mixer"},
766 {
"HL Left Mixer",
NULL,
"Input Left Capture"},
767 {
"HL Right Mixer",
NULL,
"Input Right Capture"},
769 {
"HL Left Mixer",
NULL,
"ASPINL"},
770 {
"HL Right Mixer",
NULL,
"ASPINR"},
771 {
"HL Left Mixer",
NULL,
"XSPINL"},
772 {
"HL Right Mixer",
NULL,
"XSPINR"},
773 {
"HL Left Mixer",
NULL,
"VSPIN"},
774 {
"HL Right Mixer",
NULL,
"VSPIN"},
776 {
"ASPINL",
NULL,
"ASP Playback"},
777 {
"ASPINM",
NULL,
"ASP Playback"},
778 {
"ASPINR",
NULL,
"ASP Playback"},
779 {
"XSPINL",
NULL,
"XSP Playback"},
780 {
"XSPINM",
NULL,
"XSP Playback"},
781 {
"XSPINR",
NULL,
"XSP Playback"},
782 {
"VSPIN",
NULL,
"VSP Playback"},
785 {
"MIC1",
NULL,
"MIC1 Bias"},
786 {
"PGA Left Mux",
"Mic 1",
"MIC1"},
787 {
"MIC2",
NULL,
"MIC2 Bias"},
788 {
"PGA Right Mux",
"Mic 2",
"MIC2"},
790 {
"PGA Left Mux",
"Line A",
"LINEINA"},
791 {
"PGA Right Mux",
"Line B",
"LINEINB"},
793 {
"PGA Left",
NULL,
"PGA Left Mux"},
794 {
"PGA Right",
NULL,
"PGA Right Mux"},
796 {
"ADC Left",
NULL,
"PGA Left"},
797 {
"ADC Right",
NULL,
"PGA Right"},
799 {
"Input Left Capture",
"ADC Left Input",
"ADC Left"},
800 {
"Input Right Capture",
"ADC Right Input",
"ADC Right"},
801 {
"Input Left Capture",
"DMIC Left Input",
"DMIC Left"},
802 {
"Input Right Capture",
"DMIC Right Input",
"DMIC Right"},
805 {
"ASPL Output Mixer",
NULL,
"Input Left Capture"},
806 {
"ASPR Output Mixer",
NULL,
"Input Right Capture"},
808 {
"ASPOUTL",
"ASP-IP Volume",
"ASPL Output Mixer"},
809 {
"ASPOUTR",
"ASP-IP Volume",
"ASPR Output Mixer"},
812 {
"XSPL Output Mixer",
NULL,
"Input Left Capture"},
813 {
"XSPR Output Mixer",
NULL,
"Input Right Capture"},
815 {
"XSPOUTL",
"XSP-IP Volume",
"XSPL Output Mixer"},
816 {
"XSPOUTR",
"XSP-IP Volume",
"XSPR Output Mixer"},
818 {
"XSPOUTL",
NULL,
"XSPL Output Mixer"},
819 {
"XSPOUTR",
NULL,
"XSPR Output Mixer"},
822 {
"VSPL Output Mixer",
NULL,
"Input Left Capture"},
823 {
"VSPR Output Mixer",
NULL,
"Input Left Capture"},
825 {
"VSPOUTL",
"VSP-IP Volume",
"VSPL Output Mixer"},
826 {
"VSPOUTR",
"VSP-IP Volume",
"VSPR Output Mixer"},
828 {
"VSPOUTL",
NULL,
"VSPL Output Mixer"},
829 {
"VSPOUTR",
NULL,
"VSPR Output Mixer"},
831 {
"ASP Capture",
NULL,
"ASPOUTL"},
832 {
"ASP Capture",
NULL,
"ASPOUTR"},
833 {
"XSP Capture",
NULL,
"XSPOUTL"},
834 {
"XSP Capture",
NULL,
"XSPOUTR"},
835 {
"VSP Capture",
NULL,
"VSPOUTL"},
836 {
"VSP Capture",
NULL,
"VSPOUTR"},
847 {5644800, 11025, 0x30},
848 {5644800, 22050, 0x20},
849 {5644800, 44100, 0x10},
851 {6000000, 8000, 0x39},
852 {6000000, 11025, 0x33},
853 {6000000, 12000, 0x31},
854 {6000000, 16000, 0x29},
855 {6000000, 22050, 0x23},
856 {6000000, 24000, 0x21},
857 {6000000, 32000, 0x19},
858 {6000000, 44100, 0x13},
859 {6000000, 48000, 0x11},
861 {6144000, 8000, 0x38},
862 {6144000, 12000, 0x30},
863 {6144000, 16000, 0x28},
864 {6144000, 24000, 0x20},
865 {6144000, 32000, 0x18},
866 {6144000, 48000, 0x10},
868 {6500000, 8000, 0x3C},
869 {6500000, 11025, 0x35},
870 {6500000, 12000, 0x34},
871 {6500000, 16000, 0x2C},
872 {6500000, 22050, 0x25},
873 {6500000, 24000, 0x24},
874 {6500000, 32000, 0x1C},
875 {6500000, 44100, 0x15},
876 {6500000, 48000, 0x14},
878 {6400000, 8000, 0x3E},
879 {6400000, 11025, 0x37},
880 {6400000, 12000, 0x36},
881 {6400000, 16000, 0x2E},
882 {6400000, 22050, 0x27},
883 {6400000, 24000, 0x26},
884 {6400000, 32000, 0x1E},
885 {6400000, 44100, 0x17},
886 {6400000, 48000, 0x16},
909 static int cs42l73_get_mclkx_coeff(
int mclkx)
913 for (i = 0; i <
ARRAY_SIZE(cs42l73_mclkx_coeffs); i++) {
914 if (cs42l73_mclkx_coeffs[i].mclkx == mclkx)
920 static int cs42l73_get_mclk_coeff(
int mclk,
int srate)
924 for (i = 0; i <
ARRAY_SIZE(cs42l73_mclk_coeffs); i++) {
925 if (cs42l73_mclk_coeffs[i].mclk == mclk &&
926 cs42l73_mclk_coeffs[i].srate == srate)
943 mclkx_coeff = cs42l73_get_mclkx_coeff(freq);
947 mclk = cs42l73_mclkx_coeffs[mclkx_coeff].
mclkx /
948 cs42l73_mclkx_coeffs[mclkx_coeff].
ratio;
950 dev_dbg(codec->
dev,
"MCLK%u %u <-> internal MCLK %u\n",
951 priv->
mclksel + 1, cs42l73_mclkx_coeffs[mclkx_coeff].
mclkx,
955 (cs42l73_mclkx_coeffs[mclkx_coeff].
mclkdiv << 1);
959 priv->
sysclk = mclkx_coeff;
965 static int cs42l73_set_sysclk(
struct snd_soc_dai *dai,
966 int clk_id,
unsigned int freq,
int dir)
980 if ((cs42l73_set_mclk(dai, freq)) < 0) {
981 dev_err(codec->
dev,
"Unable to set MCLK for dai %s\n",
991 static int cs42l73_set_dai_fmt(
struct snd_soc_dai *codec_dai,
unsigned int fmt)
995 u8 id = codec_dai->
id;
1026 "PCM format in slave mode only\n");
1031 "PCM format is not supported on ASP port\n");
1065 static u32 cs42l73_asrc_rates[] = {
1066 8000, 11025, 12000, 16000, 22050,
1067 24000, 32000, 44100, 48000
1070 static unsigned int cs42l73_get_xspfs_coeff(
u32 rate)
1073 for (i = 0; i <
ARRAY_SIZE(cs42l73_asrc_rates); i++) {
1074 if (cs42l73_asrc_rates[i] == rate)
1080 static void cs42l73_update_asrc(
struct snd_soc_codec *codec,
int id,
int srate)
1085 spfs = cs42l73_get_xspfs_coeff(srate);
1112 if (priv->
config[
id].mmcc & MS_MASTER) {
1116 cs42l73_get_mclk_coeff(priv->
mclk, srate);
1122 "DAI[%d]: MCLK %u, srate %u, MMCC[5:0] = %x\n",
1123 id, priv->
mclk, srate,
1124 cs42l73_mclk_coeffs[mclk_coeff].
mmcc);
1127 priv->
config[
id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].
mmcc;
1141 cs42l73_update_asrc(codec,
id, srate);
1146 static int cs42l73_set_bias_level(
struct snd_soc_codec *codec,
1183 0x7F, tristate << 7);
1188 .list = cs42l73_asrc_rates,
1196 &constraints_12_24);
1201 #define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
1204 #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
1205 SNDRV_PCM_FMTBIT_S24_LE)
1208 .startup = cs42l73_pcm_startup,
1209 .hw_params = cs42l73_pcm_hw_params,
1210 .set_fmt = cs42l73_set_dai_fmt,
1211 .set_sysclk = cs42l73_set_sysclk,
1212 .set_tristate = cs42l73_set_tristate,
1217 .name =
"cs42l73-xsp",
1220 .stream_name =
"XSP Playback",
1227 .stream_name =
"XSP Capture",
1233 .ops = &cs42l73_ops,
1234 .symmetric_rates = 1,
1237 .name =
"cs42l73-asp",
1240 .stream_name =
"ASP Playback",
1247 .stream_name =
"ASP Capture",
1253 .ops = &cs42l73_ops,
1254 .symmetric_rates = 1,
1257 .name =
"cs42l73-vsp",
1260 .stream_name =
"VSP Playback",
1267 .stream_name =
"VSP Capture",
1273 .ops = &cs42l73_ops,
1274 .symmetric_rates = 1,
1300 dev_err(codec->
dev,
"Failed to set cache I/O: %d\n", ret);
1321 .probe = cs42l73_probe,
1322 .remove = cs42l73_remove,
1323 .suspend = cs42l73_suspend,
1324 .resume = cs42l73_resume,
1325 .set_bias_level = cs42l73_set_bias_level,
1327 .dapm_widgets = cs42l73_dapm_widgets,
1328 .num_dapm_widgets =
ARRAY_SIZE(cs42l73_dapm_widgets),
1329 .dapm_routes = cs42l73_audio_map,
1330 .num_dapm_routes =
ARRAY_SIZE(cs42l73_audio_map),
1332 .controls = cs42l73_snd_controls,
1333 .num_controls =
ARRAY_SIZE(cs42l73_snd_controls),
1336 static struct regmap_config cs42l73_regmap = {
1341 .reg_defaults = cs42l73_reg_defaults,
1342 .num_reg_defaults =
ARRAY_SIZE(cs42l73_reg_defaults),
1343 .volatile_reg = cs42l73_volatile_register,
1344 .readable_reg = cs42l73_readable_register,
1353 unsigned int devid = 0;
1359 dev_err(&i2c_client->
dev,
"could not allocate codec\n");
1363 i2c_set_clientdata(i2c_client, cs42l73);
1366 if (IS_ERR(cs42l73->
regmap)) {
1367 ret = PTR_ERR(cs42l73->
regmap);
1368 dev_err(&i2c_client->
dev,
"regmap_init() failed: %d\n", ret);
1373 devid = (reg & 0xFF) << 12;
1376 devid |= (reg & 0xFF) << 4;
1379 devid |= (reg & 0xF0) >> 4;
1385 "CS42L73 Device ID (%X). Expected %X\n",
1392 dev_err(&i2c_client->
dev,
"Get Revision ID failed\n");
1397 "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
1402 &soc_codec_dev_cs42l73, cs42l73_dai,
1422 static struct i2c_driver cs42l73_i2c_driver = {
1427 .id_table = cs42l73_id,
1428 .probe = cs42l73_i2c_probe,