1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26d10c914SBrian Austin /*
36d10c914SBrian Austin * cs42l73.c -- CS42L73 ALSA Soc Audio driver
46d10c914SBrian Austin *
56d10c914SBrian Austin * Copyright 2011 Cirrus Logic, Inc.
66d10c914SBrian Austin *
76d10c914SBrian Austin * Authors: Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>
86d10c914SBrian Austin * Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>
96d10c914SBrian Austin */
106d10c914SBrian Austin
116d10c914SBrian Austin #include <linux/module.h>
126d10c914SBrian Austin #include <linux/moduleparam.h>
136d10c914SBrian Austin #include <linux/kernel.h>
146d10c914SBrian Austin #include <linux/init.h>
156d10c914SBrian Austin #include <linux/delay.h>
167b09eea5SBrian Austin #include <linux/of_gpio.h>
176d10c914SBrian Austin #include <linux/pm.h>
186d10c914SBrian Austin #include <linux/i2c.h>
196d10c914SBrian Austin #include <linux/regmap.h>
206d10c914SBrian Austin #include <linux/slab.h>
216d10c914SBrian Austin #include <sound/core.h>
226d10c914SBrian Austin #include <sound/pcm.h>
236d10c914SBrian Austin #include <sound/pcm_params.h>
246d10c914SBrian Austin #include <sound/soc.h>
256d10c914SBrian Austin #include <sound/soc-dapm.h>
266d10c914SBrian Austin #include <sound/initval.h>
276d10c914SBrian Austin #include <sound/tlv.h>
283d8c8bc0SBrian Austin #include <sound/cs42l73.h>
296d10c914SBrian Austin #include "cs42l73.h"
3026495252SCharles Keepax #include "cirrus_legacy.h"
316d10c914SBrian Austin
326d10c914SBrian Austin struct sp_config {
336d10c914SBrian Austin u8 spc, mmcc, spfs;
346d10c914SBrian Austin u32 srate;
356d10c914SBrian Austin };
366d10c914SBrian Austin struct cs42l73_private {
373d8c8bc0SBrian Austin struct cs42l73_platform_data pdata;
386d10c914SBrian Austin struct sp_config config[3];
396d10c914SBrian Austin struct regmap *regmap;
406d10c914SBrian Austin u32 sysclk;
416d10c914SBrian Austin u8 mclksel;
426d10c914SBrian Austin u32 mclk;
4341df0829SPaul Handrigan int shutdwn_delay;
446d10c914SBrian Austin };
456d10c914SBrian Austin
46404417e6SMark Brown static const struct reg_default cs42l73_reg_defaults[] = {
476d10c914SBrian Austin { 6, 0xF1 }, /* r06 - Power Ctl 1 */
486d10c914SBrian Austin { 7, 0xDF }, /* r07 - Power Ctl 2 */
496d10c914SBrian Austin { 8, 0x3F }, /* r08 - Power Ctl 3 */
506d10c914SBrian Austin { 9, 0x50 }, /* r09 - Charge Pump Freq */
516d10c914SBrian Austin { 10, 0x53 }, /* r0A - Output Load MicBias Short Detect */
526d10c914SBrian Austin { 11, 0x00 }, /* r0B - DMIC Master Clock Ctl */
536d10c914SBrian Austin { 12, 0x00 }, /* r0C - Aux PCM Ctl */
546d10c914SBrian Austin { 13, 0x15 }, /* r0D - Aux PCM Master Clock Ctl */
556d10c914SBrian Austin { 14, 0x00 }, /* r0E - Audio PCM Ctl */
566d10c914SBrian Austin { 15, 0x15 }, /* r0F - Audio PCM Master Clock Ctl */
576d10c914SBrian Austin { 16, 0x00 }, /* r10 - Voice PCM Ctl */
586d10c914SBrian Austin { 17, 0x15 }, /* r11 - Voice PCM Master Clock Ctl */
596d10c914SBrian Austin { 18, 0x00 }, /* r12 - Voice/Aux Sample Rate */
606d10c914SBrian Austin { 19, 0x06 }, /* r13 - Misc I/O Path Ctl */
616d10c914SBrian Austin { 20, 0x00 }, /* r14 - ADC Input Path Ctl */
626d10c914SBrian Austin { 21, 0x00 }, /* r15 - MICA Preamp, PGA Volume */
636d10c914SBrian Austin { 22, 0x00 }, /* r16 - MICB Preamp, PGA Volume */
646d10c914SBrian Austin { 23, 0x00 }, /* r17 - Input Path A Digital Volume */
656d10c914SBrian Austin { 24, 0x00 }, /* r18 - Input Path B Digital Volume */
666d10c914SBrian Austin { 25, 0x00 }, /* r19 - Playback Digital Ctl */
676d10c914SBrian Austin { 26, 0x00 }, /* r1A - HP/LO Left Digital Volume */
686d10c914SBrian Austin { 27, 0x00 }, /* r1B - HP/LO Right Digital Volume */
696d10c914SBrian Austin { 28, 0x00 }, /* r1C - Speakerphone Digital Volume */
706d10c914SBrian Austin { 29, 0x00 }, /* r1D - Ear/SPKLO Digital Volume */
716d10c914SBrian Austin { 30, 0x00 }, /* r1E - HP Left Analog Volume */
726d10c914SBrian Austin { 31, 0x00 }, /* r1F - HP Right Analog Volume */
736d10c914SBrian Austin { 32, 0x00 }, /* r20 - LO Left Analog Volume */
746d10c914SBrian Austin { 33, 0x00 }, /* r21 - LO Right Analog Volume */
756d10c914SBrian Austin { 34, 0x00 }, /* r22 - Stereo Input Path Advisory Volume */
766d10c914SBrian Austin { 35, 0x00 }, /* r23 - Aux PCM Input Advisory Volume */
776d10c914SBrian Austin { 36, 0x00 }, /* r24 - Audio PCM Input Advisory Volume */
786d10c914SBrian Austin { 37, 0x00 }, /* r25 - Voice PCM Input Advisory Volume */
796d10c914SBrian Austin { 38, 0x00 }, /* r26 - Limiter Attack Rate HP/LO */
806d10c914SBrian Austin { 39, 0x7F }, /* r27 - Limter Ctl, Release Rate HP/LO */
816d10c914SBrian Austin { 40, 0x00 }, /* r28 - Limter Threshold HP/LO */
826d10c914SBrian Austin { 41, 0x00 }, /* r29 - Limiter Attack Rate Speakerphone */
836d10c914SBrian Austin { 42, 0x3F }, /* r2A - Limter Ctl, Release Rate Speakerphone */
846d10c914SBrian Austin { 43, 0x00 }, /* r2B - Limter Threshold Speakerphone */
856d10c914SBrian Austin { 44, 0x00 }, /* r2C - Limiter Attack Rate Ear/SPKLO */
866d10c914SBrian Austin { 45, 0x3F }, /* r2D - Limter Ctl, Release Rate Ear/SPKLO */
876d10c914SBrian Austin { 46, 0x00 }, /* r2E - Limter Threshold Ear/SPKLO */
886d10c914SBrian Austin { 47, 0x00 }, /* r2F - ALC Enable, Attack Rate Left/Right */
896d10c914SBrian Austin { 48, 0x3F }, /* r30 - ALC Release Rate Left/Right */
906d10c914SBrian Austin { 49, 0x00 }, /* r31 - ALC Threshold Left/Right */
916d10c914SBrian Austin { 50, 0x00 }, /* r32 - Noise Gate Ctl Left/Right */
926d10c914SBrian Austin { 51, 0x00 }, /* r33 - ALC/NG Misc Ctl */
936d10c914SBrian Austin { 52, 0x18 }, /* r34 - Mixer Ctl */
946d10c914SBrian Austin { 53, 0x3F }, /* r35 - HP/LO Left Mixer Input Path Volume */
956d10c914SBrian Austin { 54, 0x3F }, /* r36 - HP/LO Right Mixer Input Path Volume */
966d10c914SBrian Austin { 55, 0x3F }, /* r37 - HP/LO Left Mixer Aux PCM Volume */
976d10c914SBrian Austin { 56, 0x3F }, /* r38 - HP/LO Right Mixer Aux PCM Volume */
986d10c914SBrian Austin { 57, 0x3F }, /* r39 - HP/LO Left Mixer Audio PCM Volume */
996d10c914SBrian Austin { 58, 0x3F }, /* r3A - HP/LO Right Mixer Audio PCM Volume */
1006d10c914SBrian Austin { 59, 0x3F }, /* r3B - HP/LO Left Mixer Voice PCM Mono Volume */
1016d10c914SBrian Austin { 60, 0x3F }, /* r3C - HP/LO Right Mixer Voice PCM Mono Volume */
1026d10c914SBrian Austin { 61, 0x3F }, /* r3D - Aux PCM Left Mixer Input Path Volume */
1036d10c914SBrian Austin { 62, 0x3F }, /* r3E - Aux PCM Right Mixer Input Path Volume */
1046d10c914SBrian Austin { 63, 0x3F }, /* r3F - Aux PCM Left Mixer Volume */
1056d10c914SBrian Austin { 64, 0x3F }, /* r40 - Aux PCM Left Mixer Volume */
1066d10c914SBrian Austin { 65, 0x3F }, /* r41 - Aux PCM Left Mixer Audio PCM L Volume */
1076d10c914SBrian Austin { 66, 0x3F }, /* r42 - Aux PCM Right Mixer Audio PCM R Volume */
1086d10c914SBrian Austin { 67, 0x3F }, /* r43 - Aux PCM Left Mixer Voice PCM Volume */
1096d10c914SBrian Austin { 68, 0x3F }, /* r44 - Aux PCM Right Mixer Voice PCM Volume */
1106d10c914SBrian Austin { 69, 0x3F }, /* r45 - Audio PCM Left Input Path Volume */
1116d10c914SBrian Austin { 70, 0x3F }, /* r46 - Audio PCM Right Input Path Volume */
1126d10c914SBrian Austin { 71, 0x3F }, /* r47 - Audio PCM Left Mixer Aux PCM L Volume */
1136d10c914SBrian Austin { 72, 0x3F }, /* r48 - Audio PCM Right Mixer Aux PCM R Volume */
1146d10c914SBrian Austin { 73, 0x3F }, /* r49 - Audio PCM Left Mixer Volume */
1156d10c914SBrian Austin { 74, 0x3F }, /* r4A - Audio PCM Right Mixer Volume */
1166d10c914SBrian Austin { 75, 0x3F }, /* r4B - Audio PCM Left Mixer Voice PCM Volume */
1176d10c914SBrian Austin { 76, 0x3F }, /* r4C - Audio PCM Right Mixer Voice PCM Volume */
1186d10c914SBrian Austin { 77, 0x3F }, /* r4D - Voice PCM Left Input Path Volume */
1196d10c914SBrian Austin { 78, 0x3F }, /* r4E - Voice PCM Right Input Path Volume */
1206d10c914SBrian Austin { 79, 0x3F }, /* r4F - Voice PCM Left Mixer Aux PCM L Volume */
1216d10c914SBrian Austin { 80, 0x3F }, /* r50 - Voice PCM Right Mixer Aux PCM R Volume */
1226d10c914SBrian Austin { 81, 0x3F }, /* r51 - Voice PCM Left Mixer Audio PCM L Volume */
1236d10c914SBrian Austin { 82, 0x3F }, /* r52 - Voice PCM Right Mixer Audio PCM R Volume */
1246d10c914SBrian Austin { 83, 0x3F }, /* r53 - Voice PCM Left Mixer Voice PCM Volume */
1256d10c914SBrian Austin { 84, 0x3F }, /* r54 - Voice PCM Right Mixer Voice PCM Volume */
1266d10c914SBrian Austin { 85, 0xAA }, /* r55 - Mono Mixer Ctl */
1276d10c914SBrian Austin { 86, 0x3F }, /* r56 - SPK Mono Mixer Input Path Volume */
1286d10c914SBrian Austin { 87, 0x3F }, /* r57 - SPK Mono Mixer Aux PCM Mono/L/R Volume */
1296d10c914SBrian Austin { 88, 0x3F }, /* r58 - SPK Mono Mixer Audio PCM Mono/L/R Volume */
1306d10c914SBrian Austin { 89, 0x3F }, /* r59 - SPK Mono Mixer Voice PCM Mono Volume */
1316d10c914SBrian Austin { 90, 0x3F }, /* r5A - SPKLO Mono Mixer Input Path Mono Volume */
1326d10c914SBrian Austin { 91, 0x3F }, /* r5B - SPKLO Mono Mixer Aux Mono/L/R Volume */
1336d10c914SBrian Austin { 92, 0x3F }, /* r5C - SPKLO Mono Mixer Audio Mono/L/R Volume */
1346d10c914SBrian Austin { 93, 0x3F }, /* r5D - SPKLO Mono Mixer Voice Mono Volume */
1356d10c914SBrian Austin { 94, 0x00 }, /* r5E - Interrupt Mask 1 */
1366d10c914SBrian Austin { 95, 0x00 }, /* r5F - Interrupt Mask 2 */
1376d10c914SBrian Austin };
1386d10c914SBrian Austin
cs42l73_volatile_register(struct device * dev,unsigned int reg)1396d10c914SBrian Austin static bool cs42l73_volatile_register(struct device *dev, unsigned int reg)
1406d10c914SBrian Austin {
1416d10c914SBrian Austin switch (reg) {
1426d10c914SBrian Austin case CS42L73_IS1:
1436d10c914SBrian Austin case CS42L73_IS2:
1446d10c914SBrian Austin return true;
1456d10c914SBrian Austin default:
1466d10c914SBrian Austin return false;
1476d10c914SBrian Austin }
1486d10c914SBrian Austin }
1496d10c914SBrian Austin
cs42l73_readable_register(struct device * dev,unsigned int reg)1506d10c914SBrian Austin static bool cs42l73_readable_register(struct device *dev, unsigned int reg)
1516d10c914SBrian Austin {
1526d10c914SBrian Austin switch (reg) {
153fbf917e1SAxel Lin case CS42L73_DEVID_AB ... CS42L73_DEVID_E:
154fbf917e1SAxel Lin case CS42L73_REVID ... CS42L73_IM2:
1556d10c914SBrian Austin return true;
1566d10c914SBrian Austin default:
1576d10c914SBrian Austin return false;
1586d10c914SBrian Austin }
1596d10c914SBrian Austin }
1606d10c914SBrian Austin
1610c812915SLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(hpaloa_tlv,
1626d10c914SBrian Austin 0, 13, TLV_DB_SCALE_ITEM(-7600, 200, 0),
1630c812915SLars-Peter Clausen 14, 75, TLV_DB_SCALE_ITEM(-4900, 100, 0)
1640c812915SLars-Peter Clausen );
1656d10c914SBrian Austin
1666d10c914SBrian Austin static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2500, 0);
1676d10c914SBrian Austin
1686d10c914SBrian Austin static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
1696d10c914SBrian Austin
1706d10c914SBrian Austin static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
1716d10c914SBrian Austin
1726d10c914SBrian Austin static DECLARE_TLV_DB_SCALE(micpga_tlv, -600, 50, 0);
1736d10c914SBrian Austin
1740c812915SLars-Peter Clausen static const DECLARE_TLV_DB_RANGE(limiter_tlv,
1756d10c914SBrian Austin 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
1760c812915SLars-Peter Clausen 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0)
1770c812915SLars-Peter Clausen );
1786d10c914SBrian Austin
1796d10c914SBrian Austin static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1);
1806d10c914SBrian Austin
1816d10c914SBrian Austin static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" };
1826d10c914SBrian Austin static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" };
1836d10c914SBrian Austin
18452a5b545STakashi Iwai static SOC_ENUM_SINGLE_DECL(pgaa_enum,
18552a5b545STakashi Iwai CS42L73_ADCIPC, 3,
18652a5b545STakashi Iwai cs42l73_pgaa_text);
1876d10c914SBrian Austin
18852a5b545STakashi Iwai static SOC_ENUM_SINGLE_DECL(pgab_enum,
18952a5b545STakashi Iwai CS42L73_ADCIPC, 7,
19052a5b545STakashi Iwai cs42l73_pgab_text);
1916d10c914SBrian Austin
1926d10c914SBrian Austin static const struct snd_kcontrol_new pgaa_mux =
1936d10c914SBrian Austin SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum);
1946d10c914SBrian Austin
1956d10c914SBrian Austin static const struct snd_kcontrol_new pgab_mux =
1966d10c914SBrian Austin SOC_DAPM_ENUM("Right Analog Input Capture Mux", pgab_enum);
1976d10c914SBrian Austin
1986d10c914SBrian Austin static const struct snd_kcontrol_new input_left_mixer[] = {
1996d10c914SBrian Austin SOC_DAPM_SINGLE("ADC Left Input", CS42L73_PWRCTL1,
2006d10c914SBrian Austin 5, 1, 1),
2016d10c914SBrian Austin SOC_DAPM_SINGLE("DMIC Left Input", CS42L73_PWRCTL1,
2026d10c914SBrian Austin 4, 1, 1),
2036d10c914SBrian Austin };
2046d10c914SBrian Austin
2056d10c914SBrian Austin static const struct snd_kcontrol_new input_right_mixer[] = {
2066d10c914SBrian Austin SOC_DAPM_SINGLE("ADC Right Input", CS42L73_PWRCTL1,
2076d10c914SBrian Austin 7, 1, 1),
2086d10c914SBrian Austin SOC_DAPM_SINGLE("DMIC Right Input", CS42L73_PWRCTL1,
2096d10c914SBrian Austin 6, 1, 1),
2106d10c914SBrian Austin };
2116d10c914SBrian Austin
2126d10c914SBrian Austin static const char * const cs42l73_ng_delay_text[] = {
2136d10c914SBrian Austin "50ms", "100ms", "150ms", "200ms" };
2146d10c914SBrian Austin
21552a5b545STakashi Iwai static SOC_ENUM_SINGLE_DECL(ng_delay_enum,
21652a5b545STakashi Iwai CS42L73_NGCAB, 0,
21752a5b545STakashi Iwai cs42l73_ng_delay_text);
2186d10c914SBrian Austin
2196d10c914SBrian Austin static const char * const cs42l73_mono_mix_texts[] = {
2206d10c914SBrian Austin "Left", "Right", "Mono Mix"};
2216d10c914SBrian Austin
2226d10c914SBrian Austin static const unsigned int cs42l73_mono_mix_values[] = { 0, 1, 2 };
2236d10c914SBrian Austin
2246d10c914SBrian Austin static const struct soc_enum spk_asp_enum =
2251555b652SBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 6, 3,
2266d10c914SBrian Austin ARRAY_SIZE(cs42l73_mono_mix_texts),
2276d10c914SBrian Austin cs42l73_mono_mix_texts,
2286d10c914SBrian Austin cs42l73_mono_mix_values);
2296d10c914SBrian Austin
2306d10c914SBrian Austin static const struct snd_kcontrol_new spk_asp_mixer =
2316d10c914SBrian Austin SOC_DAPM_ENUM("Route", spk_asp_enum);
2326d10c914SBrian Austin
2336d10c914SBrian Austin static const struct soc_enum spk_xsp_enum =
2346d10c914SBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 4, 3,
2356d10c914SBrian Austin ARRAY_SIZE(cs42l73_mono_mix_texts),
2366d10c914SBrian Austin cs42l73_mono_mix_texts,
2376d10c914SBrian Austin cs42l73_mono_mix_values);
2386d10c914SBrian Austin
2396d10c914SBrian Austin static const struct snd_kcontrol_new spk_xsp_mixer =
2406d10c914SBrian Austin SOC_DAPM_ENUM("Route", spk_xsp_enum);
2416d10c914SBrian Austin
2426d10c914SBrian Austin static const struct soc_enum esl_asp_enum =
2431555b652SBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 2, 3,
2446d10c914SBrian Austin ARRAY_SIZE(cs42l73_mono_mix_texts),
2456d10c914SBrian Austin cs42l73_mono_mix_texts,
2466d10c914SBrian Austin cs42l73_mono_mix_values);
2476d10c914SBrian Austin
2486d10c914SBrian Austin static const struct snd_kcontrol_new esl_asp_mixer =
2496d10c914SBrian Austin SOC_DAPM_ENUM("Route", esl_asp_enum);
2506d10c914SBrian Austin
2516d10c914SBrian Austin static const struct soc_enum esl_xsp_enum =
2521555b652SBrian Austin SOC_VALUE_ENUM_SINGLE(CS42L73_MMIXCTL, 0, 3,
2536d10c914SBrian Austin ARRAY_SIZE(cs42l73_mono_mix_texts),
2546d10c914SBrian Austin cs42l73_mono_mix_texts,
2556d10c914SBrian Austin cs42l73_mono_mix_values);
2566d10c914SBrian Austin
2576d10c914SBrian Austin static const struct snd_kcontrol_new esl_xsp_mixer =
2586d10c914SBrian Austin SOC_DAPM_ENUM("Route", esl_xsp_enum);
2596d10c914SBrian Austin
2606d10c914SBrian Austin static const char * const cs42l73_ip_swap_text[] = {
2616d10c914SBrian Austin "Stereo", "Mono A", "Mono B", "Swap A-B"};
2626d10c914SBrian Austin
26352a5b545STakashi Iwai static SOC_ENUM_SINGLE_DECL(ip_swap_enum,
26452a5b545STakashi Iwai CS42L73_MIOPC, 6,
26552a5b545STakashi Iwai cs42l73_ip_swap_text);
2666d10c914SBrian Austin
2676d10c914SBrian Austin static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"};
2686d10c914SBrian Austin
26952a5b545STakashi Iwai static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum,
27052a5b545STakashi Iwai CS42L73_MIXERCTL, 5,
27152a5b545STakashi Iwai cs42l73_spo_mixer_text);
2726d10c914SBrian Austin
27352a5b545STakashi Iwai static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum,
27452a5b545STakashi Iwai CS42L73_MIXERCTL, 4,
27552a5b545STakashi Iwai cs42l73_spo_mixer_text);
2766d10c914SBrian Austin
2776d10c914SBrian Austin static const struct snd_kcontrol_new hp_amp_ctl =
2786d10c914SBrian Austin SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 0, 1, 1);
2796d10c914SBrian Austin
2806d10c914SBrian Austin static const struct snd_kcontrol_new lo_amp_ctl =
2816d10c914SBrian Austin SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 1, 1, 1);
2826d10c914SBrian Austin
2836d10c914SBrian Austin static const struct snd_kcontrol_new spk_amp_ctl =
2846d10c914SBrian Austin SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 2, 1, 1);
2856d10c914SBrian Austin
2866d10c914SBrian Austin static const struct snd_kcontrol_new spklo_amp_ctl =
2876d10c914SBrian Austin SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 4, 1, 1);
2886d10c914SBrian Austin
2896d10c914SBrian Austin static const struct snd_kcontrol_new ear_amp_ctl =
2906d10c914SBrian Austin SOC_DAPM_SINGLE("Switch", CS42L73_PWRCTL3, 3, 1, 1);
2916d10c914SBrian Austin
2926d10c914SBrian Austin static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
2936d10c914SBrian Austin SOC_DOUBLE_R_SX_TLV("Headphone Analog Playback Volume",
2941d99f243SBrian Austin CS42L73_HPAAVOL, CS42L73_HPBAVOL, 0,
2951d99f243SBrian Austin 0x41, 0x4B, hpaloa_tlv),
2966d10c914SBrian Austin
2976d10c914SBrian Austin SOC_DOUBLE_R_SX_TLV("LineOut Analog Playback Volume", CS42L73_LOAAVOL,
2981d99f243SBrian Austin CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv),
2996d10c914SBrian Austin
3006d10c914SBrian Austin SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL,
301a0465587SBrian Austin CS42L73_MICBPREPGABVOL, 0, 0x34,
3021d99f243SBrian Austin 0x24, micpga_tlv),
3036d10c914SBrian Austin
3046d10c914SBrian Austin SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL,
3056d10c914SBrian Austin CS42L73_MICBPREPGABVOL, 6, 1, 1),
3066d10c914SBrian Austin
3076d10c914SBrian Austin SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", CS42L73_IPADVOL,
3081d99f243SBrian Austin CS42L73_IPBDVOL, 0, 0xA0, 0x6C, ipd_tlv),
3096d10c914SBrian Austin
3106d10c914SBrian Austin SOC_DOUBLE_R_SX_TLV("HL Digital Playback Volume",
3111d99f243SBrian Austin CS42L73_HLADVOL, CS42L73_HLBDVOL,
3121d99f243SBrian Austin 0, 0x34, 0xE4, hl_tlv),
3136d10c914SBrian Austin
3146d10c914SBrian Austin SOC_SINGLE_TLV("ADC A Boost Volume",
3156d10c914SBrian Austin CS42L73_ADCIPC, 2, 0x01, 1, adc_boost_tlv),
3166d10c914SBrian Austin
3176d10c914SBrian Austin SOC_SINGLE_TLV("ADC B Boost Volume",
3186d10c914SBrian Austin CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
3196d10c914SBrian Austin
3201d99f243SBrian Austin SOC_SINGLE_SX_TLV("Speakerphone Digital Volume",
3211d99f243SBrian Austin CS42L73_SPKDVOL, 0, 0x34, 0xE4, hl_tlv),
3226d10c914SBrian Austin
3231d99f243SBrian Austin SOC_SINGLE_SX_TLV("Ear Speaker Digital Volume",
3241d99f243SBrian Austin CS42L73_ESLDVOL, 0, 0x34, 0xE4, hl_tlv),
3256d10c914SBrian Austin
3266d10c914SBrian Austin SOC_DOUBLE_R("Headphone Analog Playback Switch", CS42L73_HPAAVOL,
3276d10c914SBrian Austin CS42L73_HPBAVOL, 7, 1, 1),
3286d10c914SBrian Austin
3296d10c914SBrian Austin SOC_DOUBLE_R("LineOut Analog Playback Switch", CS42L73_LOAAVOL,
3306d10c914SBrian Austin CS42L73_LOBAVOL, 7, 1, 1),
3316d10c914SBrian Austin SOC_DOUBLE("Input Path Digital Switch", CS42L73_ADCIPC, 0, 4, 1, 1),
3326d10c914SBrian Austin SOC_DOUBLE("HL Digital Playback Switch", CS42L73_PBDC, 0,
3336d10c914SBrian Austin 1, 1, 1),
3346d10c914SBrian Austin SOC_SINGLE("Speakerphone Digital Playback Switch", CS42L73_PBDC, 2, 1,
3356d10c914SBrian Austin 1),
3366d10c914SBrian Austin SOC_SINGLE("Ear Speaker Digital Playback Switch", CS42L73_PBDC, 3, 1,
3376d10c914SBrian Austin 1),
3386d10c914SBrian Austin
3396d10c914SBrian Austin SOC_SINGLE("PGA Soft-Ramp Switch", CS42L73_MIOPC, 3, 1, 0),
3406d10c914SBrian Austin SOC_SINGLE("Analog Zero Cross Switch", CS42L73_MIOPC, 2, 1, 0),
3416d10c914SBrian Austin SOC_SINGLE("Digital Soft-Ramp Switch", CS42L73_MIOPC, 1, 1, 0),
3426d10c914SBrian Austin SOC_SINGLE("Analog Output Soft-Ramp Switch", CS42L73_MIOPC, 0, 1, 0),
3436d10c914SBrian Austin
3446d10c914SBrian Austin SOC_DOUBLE("ADC Signal Polarity Switch", CS42L73_ADCIPC, 1, 5, 1,
3456d10c914SBrian Austin 0),
3466d10c914SBrian Austin
3476d10c914SBrian Austin SOC_SINGLE("HL Limiter Attack Rate", CS42L73_LIMARATEHL, 0, 0x3F,
3486d10c914SBrian Austin 0),
3496d10c914SBrian Austin SOC_SINGLE("HL Limiter Release Rate", CS42L73_LIMRRATEHL, 0,
3506d10c914SBrian Austin 0x3F, 0),
3516d10c914SBrian Austin
3526d10c914SBrian Austin
3536d10c914SBrian Austin SOC_SINGLE("HL Limiter Switch", CS42L73_LIMRRATEHL, 7, 1, 0),
3546d10c914SBrian Austin SOC_SINGLE("HL Limiter All Channels Switch", CS42L73_LIMRRATEHL, 6, 1,
3556d10c914SBrian Austin 0),
3566d10c914SBrian Austin
3576d10c914SBrian Austin SOC_SINGLE_TLV("HL Limiter Max Threshold Volume", CS42L73_LMAXHL, 5, 7,
3586d10c914SBrian Austin 1, limiter_tlv),
3596d10c914SBrian Austin
3606d10c914SBrian Austin SOC_SINGLE_TLV("HL Limiter Cushion Volume", CS42L73_LMAXHL, 2, 7, 1,
3616d10c914SBrian Austin limiter_tlv),
3626d10c914SBrian Austin
3636d10c914SBrian Austin SOC_SINGLE("SPK Limiter Attack Rate Volume", CS42L73_LIMARATESPK, 0,
3646d10c914SBrian Austin 0x3F, 0),
3656d10c914SBrian Austin SOC_SINGLE("SPK Limiter Release Rate Volume", CS42L73_LIMRRATESPK, 0,
3666d10c914SBrian Austin 0x3F, 0),
3676d10c914SBrian Austin SOC_SINGLE("SPK Limiter Switch", CS42L73_LIMRRATESPK, 7, 1, 0),
3686d10c914SBrian Austin SOC_SINGLE("SPK Limiter All Channels Switch", CS42L73_LIMRRATESPK,
3696d10c914SBrian Austin 6, 1, 0),
3706d10c914SBrian Austin SOC_SINGLE_TLV("SPK Limiter Max Threshold Volume", CS42L73_LMAXSPK, 5,
3716d10c914SBrian Austin 7, 1, limiter_tlv),
3726d10c914SBrian Austin
3736d10c914SBrian Austin SOC_SINGLE_TLV("SPK Limiter Cushion Volume", CS42L73_LMAXSPK, 2, 7, 1,
3746d10c914SBrian Austin limiter_tlv),
3756d10c914SBrian Austin
3766d10c914SBrian Austin SOC_SINGLE("ESL Limiter Attack Rate Volume", CS42L73_LIMARATEESL, 0,
3776d10c914SBrian Austin 0x3F, 0),
3786d10c914SBrian Austin SOC_SINGLE("ESL Limiter Release Rate Volume", CS42L73_LIMRRATEESL, 0,
3796d10c914SBrian Austin 0x3F, 0),
3806d10c914SBrian Austin SOC_SINGLE("ESL Limiter Switch", CS42L73_LIMRRATEESL, 7, 1, 0),
3816d10c914SBrian Austin SOC_SINGLE_TLV("ESL Limiter Max Threshold Volume", CS42L73_LMAXESL, 5,
3826d10c914SBrian Austin 7, 1, limiter_tlv),
3836d10c914SBrian Austin
3846d10c914SBrian Austin SOC_SINGLE_TLV("ESL Limiter Cushion Volume", CS42L73_LMAXESL, 2, 7, 1,
3856d10c914SBrian Austin limiter_tlv),
3866d10c914SBrian Austin
3876d10c914SBrian Austin SOC_SINGLE("ALC Attack Rate Volume", CS42L73_ALCARATE, 0, 0x3F, 0),
3886d10c914SBrian Austin SOC_SINGLE("ALC Release Rate Volume", CS42L73_ALCRRATE, 0, 0x3F, 0),
3896d10c914SBrian Austin SOC_DOUBLE("ALC Switch", CS42L73_ALCARATE, 6, 7, 1, 0),
3906d10c914SBrian Austin SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L73_ALCMINMAX, 5, 7, 0,
3916d10c914SBrian Austin limiter_tlv),
3926d10c914SBrian Austin SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L73_ALCMINMAX, 2, 7, 0,
3936d10c914SBrian Austin limiter_tlv),
3946d10c914SBrian Austin
3956d10c914SBrian Austin SOC_DOUBLE("NG Enable Switch", CS42L73_NGCAB, 6, 7, 1, 0),
3966d10c914SBrian Austin SOC_SINGLE("NG Boost Switch", CS42L73_NGCAB, 5, 1, 0),
3976d10c914SBrian Austin /*
3986d10c914SBrian Austin NG Threshold depends on NG_BOOTSAB, which selects
3996d10c914SBrian Austin between two threshold scales in decibels.
4006d10c914SBrian Austin Set linear values for now ..
4016d10c914SBrian Austin */
4026d10c914SBrian Austin SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0),
4036d10c914SBrian Austin SOC_ENUM("NG Delay", ng_delay_enum),
4046d10c914SBrian Austin
4056d10c914SBrian Austin SOC_DOUBLE_R_TLV("XSP-IP Volume",
4066d10c914SBrian Austin CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1,
4076d10c914SBrian Austin attn_tlv),
4086d10c914SBrian Austin SOC_DOUBLE_R_TLV("XSP-XSP Volume",
4096d10c914SBrian Austin CS42L73_XSPAXSPAA, CS42L73_XSPBXSPBA, 0, 0x3F, 1,
4106d10c914SBrian Austin attn_tlv),
4116d10c914SBrian Austin SOC_DOUBLE_R_TLV("XSP-ASP Volume",
4126d10c914SBrian Austin CS42L73_XSPAASPAA, CS42L73_XSPAASPBA, 0, 0x3F, 1,
4136d10c914SBrian Austin attn_tlv),
4146d10c914SBrian Austin SOC_DOUBLE_R_TLV("XSP-VSP Volume",
4156d10c914SBrian Austin CS42L73_XSPAVSPMA, CS42L73_XSPBVSPMA, 0, 0x3F, 1,
4166d10c914SBrian Austin attn_tlv),
4176d10c914SBrian Austin
4186d10c914SBrian Austin SOC_DOUBLE_R_TLV("ASP-IP Volume",
4196d10c914SBrian Austin CS42L73_ASPAIPAA, CS42L73_ASPBIPBA, 0, 0x3F, 1,
4206d10c914SBrian Austin attn_tlv),
4216d10c914SBrian Austin SOC_DOUBLE_R_TLV("ASP-XSP Volume",
4226d10c914SBrian Austin CS42L73_ASPAXSPAA, CS42L73_ASPBXSPBA, 0, 0x3F, 1,
4236d10c914SBrian Austin attn_tlv),
4246d10c914SBrian Austin SOC_DOUBLE_R_TLV("ASP-ASP Volume",
4256d10c914SBrian Austin CS42L73_ASPAASPAA, CS42L73_ASPBASPBA, 0, 0x3F, 1,
4266d10c914SBrian Austin attn_tlv),
4276d10c914SBrian Austin SOC_DOUBLE_R_TLV("ASP-VSP Volume",
4286d10c914SBrian Austin CS42L73_ASPAVSPMA, CS42L73_ASPBVSPMA, 0, 0x3F, 1,
4296d10c914SBrian Austin attn_tlv),
4306d10c914SBrian Austin
4316d10c914SBrian Austin SOC_DOUBLE_R_TLV("VSP-IP Volume",
4326d10c914SBrian Austin CS42L73_VSPAIPAA, CS42L73_VSPBIPBA, 0, 0x3F, 1,
4336d10c914SBrian Austin attn_tlv),
4346d10c914SBrian Austin SOC_DOUBLE_R_TLV("VSP-XSP Volume",
4356d10c914SBrian Austin CS42L73_VSPAXSPAA, CS42L73_VSPBXSPBA, 0, 0x3F, 1,
4366d10c914SBrian Austin attn_tlv),
4376d10c914SBrian Austin SOC_DOUBLE_R_TLV("VSP-ASP Volume",
4386d10c914SBrian Austin CS42L73_VSPAASPAA, CS42L73_VSPBASPBA, 0, 0x3F, 1,
4396d10c914SBrian Austin attn_tlv),
4406d10c914SBrian Austin SOC_DOUBLE_R_TLV("VSP-VSP Volume",
4416d10c914SBrian Austin CS42L73_VSPAVSPMA, CS42L73_VSPBVSPMA, 0, 0x3F, 1,
4426d10c914SBrian Austin attn_tlv),
4436d10c914SBrian Austin
4446d10c914SBrian Austin SOC_DOUBLE_R_TLV("HL-IP Volume",
4456d10c914SBrian Austin CS42L73_HLAIPAA, CS42L73_HLBIPBA, 0, 0x3F, 1,
4466d10c914SBrian Austin attn_tlv),
4476d10c914SBrian Austin SOC_DOUBLE_R_TLV("HL-XSP Volume",
4486d10c914SBrian Austin CS42L73_HLAXSPAA, CS42L73_HLBXSPBA, 0, 0x3F, 1,
4496d10c914SBrian Austin attn_tlv),
4506d10c914SBrian Austin SOC_DOUBLE_R_TLV("HL-ASP Volume",
4516d10c914SBrian Austin CS42L73_HLAASPAA, CS42L73_HLBASPBA, 0, 0x3F, 1,
4526d10c914SBrian Austin attn_tlv),
4536d10c914SBrian Austin SOC_DOUBLE_R_TLV("HL-VSP Volume",
4546d10c914SBrian Austin CS42L73_HLAVSPMA, CS42L73_HLBVSPMA, 0, 0x3F, 1,
4556d10c914SBrian Austin attn_tlv),
4566d10c914SBrian Austin
4576d10c914SBrian Austin SOC_SINGLE_TLV("SPK-IP Mono Volume",
4585807c3bfSBrian Austin CS42L73_SPKMIPMA, 0, 0x3F, 1, attn_tlv),
4596d10c914SBrian Austin SOC_SINGLE_TLV("SPK-XSP Mono Volume",
4605807c3bfSBrian Austin CS42L73_SPKMXSPA, 0, 0x3F, 1, attn_tlv),
4616d10c914SBrian Austin SOC_SINGLE_TLV("SPK-ASP Mono Volume",
4625807c3bfSBrian Austin CS42L73_SPKMASPA, 0, 0x3F, 1, attn_tlv),
4636d10c914SBrian Austin SOC_SINGLE_TLV("SPK-VSP Mono Volume",
4645807c3bfSBrian Austin CS42L73_SPKMVSPMA, 0, 0x3F, 1, attn_tlv),
4656d10c914SBrian Austin
4666d10c914SBrian Austin SOC_SINGLE_TLV("ESL-IP Mono Volume",
4675807c3bfSBrian Austin CS42L73_ESLMIPMA, 0, 0x3F, 1, attn_tlv),
4686d10c914SBrian Austin SOC_SINGLE_TLV("ESL-XSP Mono Volume",
4695807c3bfSBrian Austin CS42L73_ESLMXSPA, 0, 0x3F, 1, attn_tlv),
4706d10c914SBrian Austin SOC_SINGLE_TLV("ESL-ASP Mono Volume",
4715807c3bfSBrian Austin CS42L73_ESLMASPA, 0, 0x3F, 1, attn_tlv),
4726d10c914SBrian Austin SOC_SINGLE_TLV("ESL-VSP Mono Volume",
4735807c3bfSBrian Austin CS42L73_ESLMVSPMA, 0, 0x3F, 1, attn_tlv),
4746d10c914SBrian Austin
4756d10c914SBrian Austin SOC_ENUM("IP Digital Swap/Mono Select", ip_swap_enum),
4766d10c914SBrian Austin
4776d10c914SBrian Austin SOC_ENUM("VSPOUT Mono/Stereo Select", vsp_output_mux_enum),
4786d10c914SBrian Austin SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum),
4796d10c914SBrian Austin };
4806d10c914SBrian Austin
cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)48141df0829SPaul Handrigan static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
48241df0829SPaul Handrigan struct snd_kcontrol *kcontrol, int event)
48341df0829SPaul Handrigan {
484092631bfSKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
485092631bfSKuninori Morimoto struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
48641df0829SPaul Handrigan switch (event) {
48741df0829SPaul Handrigan case SND_SOC_DAPM_POST_PMD:
48841df0829SPaul Handrigan /* 150 ms delay between setting PDN and MCLKDIS */
48941df0829SPaul Handrigan priv->shutdwn_delay = 150;
49041df0829SPaul Handrigan break;
49141df0829SPaul Handrigan default:
49241df0829SPaul Handrigan pr_err("Invalid event = 0x%x\n", event);
49341df0829SPaul Handrigan }
49441df0829SPaul Handrigan return 0;
49541df0829SPaul Handrigan }
49641df0829SPaul Handrigan
cs42l73_ear_amp_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)49741df0829SPaul Handrigan static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
49841df0829SPaul Handrigan struct snd_kcontrol *kcontrol, int event)
49941df0829SPaul Handrigan {
500092631bfSKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
501092631bfSKuninori Morimoto struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
50241df0829SPaul Handrigan switch (event) {
50341df0829SPaul Handrigan case SND_SOC_DAPM_POST_PMD:
50441df0829SPaul Handrigan /* 50 ms delay between setting PDN and MCLKDIS */
50541df0829SPaul Handrigan if (priv->shutdwn_delay < 50)
50641df0829SPaul Handrigan priv->shutdwn_delay = 50;
50741df0829SPaul Handrigan break;
50841df0829SPaul Handrigan default:
50941df0829SPaul Handrigan pr_err("Invalid event = 0x%x\n", event);
51041df0829SPaul Handrigan }
51141df0829SPaul Handrigan return 0;
51241df0829SPaul Handrigan }
51341df0829SPaul Handrigan
51441df0829SPaul Handrigan
cs42l73_hp_amp_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)51541df0829SPaul Handrigan static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
51641df0829SPaul Handrigan struct snd_kcontrol *kcontrol, int event)
51741df0829SPaul Handrigan {
518092631bfSKuninori Morimoto struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
519092631bfSKuninori Morimoto struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
52041df0829SPaul Handrigan switch (event) {
52141df0829SPaul Handrigan case SND_SOC_DAPM_POST_PMD:
52241df0829SPaul Handrigan /* 30 ms delay between setting PDN and MCLKDIS */
52341df0829SPaul Handrigan if (priv->shutdwn_delay < 30)
52441df0829SPaul Handrigan priv->shutdwn_delay = 30;
52541df0829SPaul Handrigan break;
52641df0829SPaul Handrigan default:
52741df0829SPaul Handrigan pr_err("Invalid event = 0x%x\n", event);
52841df0829SPaul Handrigan }
52941df0829SPaul Handrigan return 0;
53041df0829SPaul Handrigan }
53141df0829SPaul Handrigan
5326d10c914SBrian Austin static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
533a1ad500eSPaul Handrigan SND_SOC_DAPM_INPUT("DMICA"),
534a1ad500eSPaul Handrigan SND_SOC_DAPM_INPUT("DMICB"),
5356d10c914SBrian Austin SND_SOC_DAPM_INPUT("LINEINA"),
5366d10c914SBrian Austin SND_SOC_DAPM_INPUT("LINEINB"),
5376d10c914SBrian Austin SND_SOC_DAPM_INPUT("MIC1"),
5386d10c914SBrian Austin SND_SOC_DAPM_SUPPLY("MIC1 Bias", CS42L73_PWRCTL2, 6, 1, NULL, 0),
5396d10c914SBrian Austin SND_SOC_DAPM_INPUT("MIC2"),
5406d10c914SBrian Austin SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS42L73_PWRCTL2, 7, 1, NULL, 0),
5416d10c914SBrian Austin
54233d0188cSBrian Austin SND_SOC_DAPM_AIF_OUT("XSPOUTL", NULL, 0,
5436d10c914SBrian Austin CS42L73_PWRCTL2, 1, 1),
54433d0188cSBrian Austin SND_SOC_DAPM_AIF_OUT("XSPOUTR", NULL, 0,
5456d10c914SBrian Austin CS42L73_PWRCTL2, 1, 1),
54633d0188cSBrian Austin SND_SOC_DAPM_AIF_OUT("ASPOUTL", NULL, 0,
5476d10c914SBrian Austin CS42L73_PWRCTL2, 3, 1),
54833d0188cSBrian Austin SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL, 0,
5496d10c914SBrian Austin CS42L73_PWRCTL2, 3, 1),
5507f3dd4a8SPaul Handrigan SND_SOC_DAPM_AIF_OUT("VSPINOUT", NULL, 0,
5516d10c914SBrian Austin CS42L73_PWRCTL2, 4, 1),
5526d10c914SBrian Austin
5536d10c914SBrian Austin SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0),
5546d10c914SBrian Austin SND_SOC_DAPM_PGA("PGA Right", SND_SOC_NOPM, 0, 0, NULL, 0),
5556d10c914SBrian Austin
5566d10c914SBrian Austin SND_SOC_DAPM_MUX("PGA Left Mux", SND_SOC_NOPM, 0, 0, &pgaa_mux),
5576d10c914SBrian Austin SND_SOC_DAPM_MUX("PGA Right Mux", SND_SOC_NOPM, 0, 0, &pgab_mux),
5586d10c914SBrian Austin
5596d10c914SBrian Austin SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L73_PWRCTL1, 7, 1),
5606d10c914SBrian Austin SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L73_PWRCTL1, 5, 1),
5616d10c914SBrian Austin SND_SOC_DAPM_ADC("DMIC Left", NULL, CS42L73_PWRCTL1, 6, 1),
5626d10c914SBrian Austin SND_SOC_DAPM_ADC("DMIC Right", NULL, CS42L73_PWRCTL1, 4, 1),
5636d10c914SBrian Austin
5646d10c914SBrian Austin SND_SOC_DAPM_MIXER_NAMED_CTL("Input Left Capture", SND_SOC_NOPM,
5656d10c914SBrian Austin 0, 0, input_left_mixer,
5666d10c914SBrian Austin ARRAY_SIZE(input_left_mixer)),
5676d10c914SBrian Austin
5686d10c914SBrian Austin SND_SOC_DAPM_MIXER_NAMED_CTL("Input Right Capture", SND_SOC_NOPM,
5696d10c914SBrian Austin 0, 0, input_right_mixer,
5706d10c914SBrian Austin ARRAY_SIZE(input_right_mixer)),
5716d10c914SBrian Austin
5726d10c914SBrian Austin SND_SOC_DAPM_MIXER("ASPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5736d10c914SBrian Austin SND_SOC_DAPM_MIXER("ASPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5746d10c914SBrian Austin SND_SOC_DAPM_MIXER("XSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5756d10c914SBrian Austin SND_SOC_DAPM_MIXER("XSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5767f3dd4a8SPaul Handrigan SND_SOC_DAPM_MIXER("VSP Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5776d10c914SBrian Austin
57833d0188cSBrian Austin SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0,
5796d10c914SBrian Austin CS42L73_PWRCTL2, 0, 1),
58033d0188cSBrian Austin SND_SOC_DAPM_AIF_IN("XSPINR", NULL, 0,
5816d10c914SBrian Austin CS42L73_PWRCTL2, 0, 1),
58233d0188cSBrian Austin SND_SOC_DAPM_AIF_IN("XSPINM", NULL, 0,
5836d10c914SBrian Austin CS42L73_PWRCTL2, 0, 1),
5846d10c914SBrian Austin
58533d0188cSBrian Austin SND_SOC_DAPM_AIF_IN("ASPINL", NULL, 0,
5866d10c914SBrian Austin CS42L73_PWRCTL2, 2, 1),
58733d0188cSBrian Austin SND_SOC_DAPM_AIF_IN("ASPINR", NULL, 0,
5886d10c914SBrian Austin CS42L73_PWRCTL2, 2, 1),
58933d0188cSBrian Austin SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0,
5906d10c914SBrian Austin CS42L73_PWRCTL2, 2, 1),
5916d10c914SBrian Austin
5927f3dd4a8SPaul Handrigan SND_SOC_DAPM_AIF_IN("VSPINOUT", NULL, 0,
5936d10c914SBrian Austin CS42L73_PWRCTL2, 4, 1),
5946d10c914SBrian Austin
5956d10c914SBrian Austin SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5966d10c914SBrian Austin SND_SOC_DAPM_MIXER("HL Right Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5976d10c914SBrian Austin SND_SOC_DAPM_MIXER("SPK Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5986d10c914SBrian Austin SND_SOC_DAPM_MIXER("ESL Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
5996d10c914SBrian Austin
6006d10c914SBrian Austin SND_SOC_DAPM_MUX("ESL-XSP Mux", SND_SOC_NOPM,
6016d10c914SBrian Austin 0, 0, &esl_xsp_mixer),
6026d10c914SBrian Austin
6036d10c914SBrian Austin SND_SOC_DAPM_MUX("ESL-ASP Mux", SND_SOC_NOPM,
6046d10c914SBrian Austin 0, 0, &esl_asp_mixer),
6056d10c914SBrian Austin
6066d10c914SBrian Austin SND_SOC_DAPM_MUX("SPK-ASP Mux", SND_SOC_NOPM,
6076d10c914SBrian Austin 0, 0, &spk_asp_mixer),
6086d10c914SBrian Austin
6096d10c914SBrian Austin SND_SOC_DAPM_MUX("SPK-XSP Mux", SND_SOC_NOPM,
6106d10c914SBrian Austin 0, 0, &spk_xsp_mixer),
6116d10c914SBrian Austin
6126d10c914SBrian Austin SND_SOC_DAPM_PGA("HL Left DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
6136d10c914SBrian Austin SND_SOC_DAPM_PGA("HL Right DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
6146d10c914SBrian Austin SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
6156d10c914SBrian Austin SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
6166d10c914SBrian Austin
61741df0829SPaul Handrigan SND_SOC_DAPM_SWITCH_E("HP Amp", CS42L73_PWRCTL3, 0, 1,
61841df0829SPaul Handrigan &hp_amp_ctl, cs42l73_hp_amp_event,
61941df0829SPaul Handrigan SND_SOC_DAPM_POST_PMD),
6206d10c914SBrian Austin SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1,
6216d10c914SBrian Austin &lo_amp_ctl),
62241df0829SPaul Handrigan SND_SOC_DAPM_SWITCH_E("SPK Amp", CS42L73_PWRCTL3, 2, 1,
62341df0829SPaul Handrigan &spk_amp_ctl, cs42l73_spklo_spk_amp_event,
62441df0829SPaul Handrigan SND_SOC_DAPM_POST_PMD),
62541df0829SPaul Handrigan SND_SOC_DAPM_SWITCH_E("EAR Amp", CS42L73_PWRCTL3, 3, 1,
62641df0829SPaul Handrigan &ear_amp_ctl, cs42l73_ear_amp_event,
62741df0829SPaul Handrigan SND_SOC_DAPM_POST_PMD),
62841df0829SPaul Handrigan SND_SOC_DAPM_SWITCH_E("SPKLO Amp", CS42L73_PWRCTL3, 4, 1,
62941df0829SPaul Handrigan &spklo_amp_ctl, cs42l73_spklo_spk_amp_event,
63041df0829SPaul Handrigan SND_SOC_DAPM_POST_PMD),
6316d10c914SBrian Austin
6326d10c914SBrian Austin SND_SOC_DAPM_OUTPUT("HPOUTA"),
6336d10c914SBrian Austin SND_SOC_DAPM_OUTPUT("HPOUTB"),
6346d10c914SBrian Austin SND_SOC_DAPM_OUTPUT("LINEOUTA"),
6356d10c914SBrian Austin SND_SOC_DAPM_OUTPUT("LINEOUTB"),
6366d10c914SBrian Austin SND_SOC_DAPM_OUTPUT("EAROUT"),
6376d10c914SBrian Austin SND_SOC_DAPM_OUTPUT("SPKOUT"),
6386d10c914SBrian Austin SND_SOC_DAPM_OUTPUT("SPKLINEOUT"),
6396d10c914SBrian Austin };
6406d10c914SBrian Austin
6416d10c914SBrian Austin static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
6426d10c914SBrian Austin
6436d10c914SBrian Austin /* SPKLO EARSPK Paths */
6446d10c914SBrian Austin {"EAROUT", NULL, "EAR Amp"},
6456d10c914SBrian Austin {"SPKLINEOUT", NULL, "SPKLO Amp"},
6466d10c914SBrian Austin
6476d10c914SBrian Austin {"EAR Amp", "Switch", "ESL DAC"},
6486d10c914SBrian Austin {"SPKLO Amp", "Switch", "ESL DAC"},
6496d10c914SBrian Austin
6506d10c914SBrian Austin {"ESL DAC", "ESL-ASP Mono Volume", "ESL Mixer"},
6516d10c914SBrian Austin {"ESL DAC", "ESL-XSP Mono Volume", "ESL Mixer"},
6527f3dd4a8SPaul Handrigan {"ESL DAC", "ESL-VSP Mono Volume", "VSPINOUT"},
6536d10c914SBrian Austin /* Loopback */
6546d10c914SBrian Austin {"ESL DAC", "ESL-IP Mono Volume", "Input Left Capture"},
6556d10c914SBrian Austin {"ESL DAC", "ESL-IP Mono Volume", "Input Right Capture"},
6566d10c914SBrian Austin
6576d10c914SBrian Austin {"ESL Mixer", NULL, "ESL-ASP Mux"},
6586d10c914SBrian Austin {"ESL Mixer", NULL, "ESL-XSP Mux"},
6596d10c914SBrian Austin
6606d10c914SBrian Austin {"ESL-ASP Mux", "Left", "ASPINL"},
6616d10c914SBrian Austin {"ESL-ASP Mux", "Right", "ASPINR"},
6626d10c914SBrian Austin {"ESL-ASP Mux", "Mono Mix", "ASPINM"},
6636d10c914SBrian Austin
6646d10c914SBrian Austin {"ESL-XSP Mux", "Left", "XSPINL"},
6656d10c914SBrian Austin {"ESL-XSP Mux", "Right", "XSPINR"},
6666d10c914SBrian Austin {"ESL-XSP Mux", "Mono Mix", "XSPINM"},
6676d10c914SBrian Austin
6686d10c914SBrian Austin /* Speakerphone Paths */
6696d10c914SBrian Austin {"SPKOUT", NULL, "SPK Amp"},
6706d10c914SBrian Austin {"SPK Amp", "Switch", "SPK DAC"},
6716d10c914SBrian Austin
6726d10c914SBrian Austin {"SPK DAC", "SPK-ASP Mono Volume", "SPK Mixer"},
6736d10c914SBrian Austin {"SPK DAC", "SPK-XSP Mono Volume", "SPK Mixer"},
6747f3dd4a8SPaul Handrigan {"SPK DAC", "SPK-VSP Mono Volume", "VSPINOUT"},
6756d10c914SBrian Austin /* Loopback */
6766d10c914SBrian Austin {"SPK DAC", "SPK-IP Mono Volume", "Input Left Capture"},
6776d10c914SBrian Austin {"SPK DAC", "SPK-IP Mono Volume", "Input Right Capture"},
6786d10c914SBrian Austin
6796d10c914SBrian Austin {"SPK Mixer", NULL, "SPK-ASP Mux"},
6806d10c914SBrian Austin {"SPK Mixer", NULL, "SPK-XSP Mux"},
6816d10c914SBrian Austin
6826d10c914SBrian Austin {"SPK-ASP Mux", "Left", "ASPINL"},
6836d10c914SBrian Austin {"SPK-ASP Mux", "Mono Mix", "ASPINM"},
6846d10c914SBrian Austin {"SPK-ASP Mux", "Right", "ASPINR"},
6856d10c914SBrian Austin
6866d10c914SBrian Austin {"SPK-XSP Mux", "Left", "XSPINL"},
6876d10c914SBrian Austin {"SPK-XSP Mux", "Mono Mix", "XSPINM"},
6886d10c914SBrian Austin {"SPK-XSP Mux", "Right", "XSPINR"},
6896d10c914SBrian Austin
6906d10c914SBrian Austin /* HP LineOUT Paths */
6916d10c914SBrian Austin {"HPOUTA", NULL, "HP Amp"},
6926d10c914SBrian Austin {"HPOUTB", NULL, "HP Amp"},
6936d10c914SBrian Austin {"LINEOUTA", NULL, "LO Amp"},
6946d10c914SBrian Austin {"LINEOUTB", NULL, "LO Amp"},
6956d10c914SBrian Austin
6966d10c914SBrian Austin {"HP Amp", "Switch", "HL Left DAC"},
6976d10c914SBrian Austin {"HP Amp", "Switch", "HL Right DAC"},
6986d10c914SBrian Austin {"LO Amp", "Switch", "HL Left DAC"},
6996d10c914SBrian Austin {"LO Amp", "Switch", "HL Right DAC"},
7006d10c914SBrian Austin
7016d10c914SBrian Austin {"HL Left DAC", "HL-XSP Volume", "HL Left Mixer"},
7026d10c914SBrian Austin {"HL Right DAC", "HL-XSP Volume", "HL Right Mixer"},
7036d10c914SBrian Austin {"HL Left DAC", "HL-ASP Volume", "HL Left Mixer"},
7046d10c914SBrian Austin {"HL Right DAC", "HL-ASP Volume", "HL Right Mixer"},
7056d10c914SBrian Austin {"HL Left DAC", "HL-VSP Volume", "HL Left Mixer"},
7066d10c914SBrian Austin {"HL Right DAC", "HL-VSP Volume", "HL Right Mixer"},
7076d10c914SBrian Austin /* Loopback */
7086d10c914SBrian Austin {"HL Left DAC", "HL-IP Volume", "HL Left Mixer"},
7096d10c914SBrian Austin {"HL Right DAC", "HL-IP Volume", "HL Right Mixer"},
7106d10c914SBrian Austin {"HL Left Mixer", NULL, "Input Left Capture"},
7116d10c914SBrian Austin {"HL Right Mixer", NULL, "Input Right Capture"},
7126d10c914SBrian Austin
7136d10c914SBrian Austin {"HL Left Mixer", NULL, "ASPINL"},
7146d10c914SBrian Austin {"HL Right Mixer", NULL, "ASPINR"},
7156d10c914SBrian Austin {"HL Left Mixer", NULL, "XSPINL"},
7166d10c914SBrian Austin {"HL Right Mixer", NULL, "XSPINR"},
7177f3dd4a8SPaul Handrigan {"HL Left Mixer", NULL, "VSPINOUT"},
7187f3dd4a8SPaul Handrigan {"HL Right Mixer", NULL, "VSPINOUT"},
7196d10c914SBrian Austin
72033d0188cSBrian Austin {"ASPINL", NULL, "ASP Playback"},
72133d0188cSBrian Austin {"ASPINM", NULL, "ASP Playback"},
72233d0188cSBrian Austin {"ASPINR", NULL, "ASP Playback"},
72333d0188cSBrian Austin {"XSPINL", NULL, "XSP Playback"},
72433d0188cSBrian Austin {"XSPINM", NULL, "XSP Playback"},
72533d0188cSBrian Austin {"XSPINR", NULL, "XSP Playback"},
7267f3dd4a8SPaul Handrigan {"VSPINOUT", NULL, "VSP Playback"},
72733d0188cSBrian Austin
7286d10c914SBrian Austin /* Capture Paths */
7296d10c914SBrian Austin {"MIC1", NULL, "MIC1 Bias"},
7306d10c914SBrian Austin {"PGA Left Mux", "Mic 1", "MIC1"},
7316d10c914SBrian Austin {"MIC2", NULL, "MIC2 Bias"},
7326d10c914SBrian Austin {"PGA Right Mux", "Mic 2", "MIC2"},
7336d10c914SBrian Austin
7346d10c914SBrian Austin {"PGA Left Mux", "Line A", "LINEINA"},
7356d10c914SBrian Austin {"PGA Right Mux", "Line B", "LINEINB"},
7366d10c914SBrian Austin
7376d10c914SBrian Austin {"PGA Left", NULL, "PGA Left Mux"},
7386d10c914SBrian Austin {"PGA Right", NULL, "PGA Right Mux"},
7396d10c914SBrian Austin
7406d10c914SBrian Austin {"ADC Left", NULL, "PGA Left"},
7416d10c914SBrian Austin {"ADC Right", NULL, "PGA Right"},
742a1ad500eSPaul Handrigan {"DMIC Left", NULL, "DMICA"},
743a1ad500eSPaul Handrigan {"DMIC Right", NULL, "DMICB"},
7446d10c914SBrian Austin
7456d10c914SBrian Austin {"Input Left Capture", "ADC Left Input", "ADC Left"},
7466d10c914SBrian Austin {"Input Right Capture", "ADC Right Input", "ADC Right"},
7476d10c914SBrian Austin {"Input Left Capture", "DMIC Left Input", "DMIC Left"},
7486d10c914SBrian Austin {"Input Right Capture", "DMIC Right Input", "DMIC Right"},
7496d10c914SBrian Austin
7506d10c914SBrian Austin /* Audio Capture */
7516d10c914SBrian Austin {"ASPL Output Mixer", NULL, "Input Left Capture"},
7526d10c914SBrian Austin {"ASPR Output Mixer", NULL, "Input Right Capture"},
7536d10c914SBrian Austin
7546d10c914SBrian Austin {"ASPOUTL", "ASP-IP Volume", "ASPL Output Mixer"},
7556d10c914SBrian Austin {"ASPOUTR", "ASP-IP Volume", "ASPR Output Mixer"},
7566d10c914SBrian Austin
7576d10c914SBrian Austin /* Auxillary Capture */
7586d10c914SBrian Austin {"XSPL Output Mixer", NULL, "Input Left Capture"},
7596d10c914SBrian Austin {"XSPR Output Mixer", NULL, "Input Right Capture"},
7606d10c914SBrian Austin
7616d10c914SBrian Austin {"XSPOUTL", "XSP-IP Volume", "XSPL Output Mixer"},
7626d10c914SBrian Austin {"XSPOUTR", "XSP-IP Volume", "XSPR Output Mixer"},
7636d10c914SBrian Austin
7646d10c914SBrian Austin {"XSPOUTL", NULL, "XSPL Output Mixer"},
7656d10c914SBrian Austin {"XSPOUTR", NULL, "XSPR Output Mixer"},
7666d10c914SBrian Austin
7676d10c914SBrian Austin /* Voice Capture */
7687f3dd4a8SPaul Handrigan {"VSP Output Mixer", NULL, "Input Left Capture"},
7697f3dd4a8SPaul Handrigan {"VSP Output Mixer", NULL, "Input Right Capture"},
7706d10c914SBrian Austin
7717f3dd4a8SPaul Handrigan {"VSPINOUT", "VSP-IP Volume", "VSP Output Mixer"},
7726d10c914SBrian Austin
7737f3dd4a8SPaul Handrigan {"VSPINOUT", NULL, "VSP Output Mixer"},
77433d0188cSBrian Austin
77533d0188cSBrian Austin {"ASP Capture", NULL, "ASPOUTL"},
77633d0188cSBrian Austin {"ASP Capture", NULL, "ASPOUTR"},
77733d0188cSBrian Austin {"XSP Capture", NULL, "XSPOUTL"},
77833d0188cSBrian Austin {"XSP Capture", NULL, "XSPOUTR"},
7797f3dd4a8SPaul Handrigan {"VSP Capture", NULL, "VSPINOUT"},
7806d10c914SBrian Austin };
7816d10c914SBrian Austin
7826d10c914SBrian Austin struct cs42l73_mclk_div {
7836d10c914SBrian Austin u32 mclk;
7846d10c914SBrian Austin u32 srate;
7856d10c914SBrian Austin u8 mmcc;
7866d10c914SBrian Austin };
7876d10c914SBrian Austin
788e094e8f3SAxel Lin static const struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = {
7896d10c914SBrian Austin /* MCLK, Sample Rate, xMMCC[5:0] */
7906d10c914SBrian Austin {5644800, 11025, 0x30},
7916d10c914SBrian Austin {5644800, 22050, 0x20},
7926d10c914SBrian Austin {5644800, 44100, 0x10},
7936d10c914SBrian Austin
7946d10c914SBrian Austin {6000000, 8000, 0x39},
7956d10c914SBrian Austin {6000000, 11025, 0x33},
7966d10c914SBrian Austin {6000000, 12000, 0x31},
7976d10c914SBrian Austin {6000000, 16000, 0x29},
7986d10c914SBrian Austin {6000000, 22050, 0x23},
7996d10c914SBrian Austin {6000000, 24000, 0x21},
8006d10c914SBrian Austin {6000000, 32000, 0x19},
8016d10c914SBrian Austin {6000000, 44100, 0x13},
8026d10c914SBrian Austin {6000000, 48000, 0x11},
8036d10c914SBrian Austin
8046d10c914SBrian Austin {6144000, 8000, 0x38},
8056d10c914SBrian Austin {6144000, 12000, 0x30},
8066d10c914SBrian Austin {6144000, 16000, 0x28},
8076d10c914SBrian Austin {6144000, 24000, 0x20},
8086d10c914SBrian Austin {6144000, 32000, 0x18},
8096d10c914SBrian Austin {6144000, 48000, 0x10},
8106d10c914SBrian Austin
8116d10c914SBrian Austin {6500000, 8000, 0x3C},
8126d10c914SBrian Austin {6500000, 11025, 0x35},
8136d10c914SBrian Austin {6500000, 12000, 0x34},
8146d10c914SBrian Austin {6500000, 16000, 0x2C},
8156d10c914SBrian Austin {6500000, 22050, 0x25},
8166d10c914SBrian Austin {6500000, 24000, 0x24},
8176d10c914SBrian Austin {6500000, 32000, 0x1C},
8186d10c914SBrian Austin {6500000, 44100, 0x15},
8196d10c914SBrian Austin {6500000, 48000, 0x14},
8206d10c914SBrian Austin
8216d10c914SBrian Austin {6400000, 8000, 0x3E},
8226d10c914SBrian Austin {6400000, 11025, 0x37},
8236d10c914SBrian Austin {6400000, 12000, 0x36},
8246d10c914SBrian Austin {6400000, 16000, 0x2E},
8256d10c914SBrian Austin {6400000, 22050, 0x27},
8266d10c914SBrian Austin {6400000, 24000, 0x26},
8276d10c914SBrian Austin {6400000, 32000, 0x1E},
8286d10c914SBrian Austin {6400000, 44100, 0x17},
8296d10c914SBrian Austin {6400000, 48000, 0x16},
8306d10c914SBrian Austin };
8316d10c914SBrian Austin
8326d10c914SBrian Austin struct cs42l73_mclkx_div {
8336d10c914SBrian Austin u32 mclkx;
8346d10c914SBrian Austin u8 ratio;
8356d10c914SBrian Austin u8 mclkdiv;
8366d10c914SBrian Austin };
8376d10c914SBrian Austin
838e094e8f3SAxel Lin static const struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = {
8396d10c914SBrian Austin {5644800, 1, 0}, /* 5644800 */
8406d10c914SBrian Austin {6000000, 1, 0}, /* 6000000 */
8416d10c914SBrian Austin {6144000, 1, 0}, /* 6144000 */
8426d10c914SBrian Austin {11289600, 2, 2}, /* 5644800 */
8436d10c914SBrian Austin {12288000, 2, 2}, /* 6144000 */
8446d10c914SBrian Austin {12000000, 2, 2}, /* 6000000 */
8456d10c914SBrian Austin {13000000, 2, 2}, /* 6500000 */
8466d10c914SBrian Austin {19200000, 3, 3}, /* 6400000 */
8476d10c914SBrian Austin {24000000, 4, 4}, /* 6000000 */
8486d10c914SBrian Austin {26000000, 4, 4}, /* 6500000 */
8496d10c914SBrian Austin {38400000, 6, 5} /* 6400000 */
8506d10c914SBrian Austin };
8516d10c914SBrian Austin
cs42l73_get_mclkx_coeff(int mclkx)8526d10c914SBrian Austin static int cs42l73_get_mclkx_coeff(int mclkx)
8536d10c914SBrian Austin {
8546d10c914SBrian Austin int i;
8556d10c914SBrian Austin
8566d10c914SBrian Austin for (i = 0; i < ARRAY_SIZE(cs42l73_mclkx_coeffs); i++) {
8576d10c914SBrian Austin if (cs42l73_mclkx_coeffs[i].mclkx == mclkx)
8586d10c914SBrian Austin return i;
8596d10c914SBrian Austin }
8606d10c914SBrian Austin return -EINVAL;
8616d10c914SBrian Austin }
8626d10c914SBrian Austin
cs42l73_get_mclk_coeff(int mclk,int srate)8636d10c914SBrian Austin static int cs42l73_get_mclk_coeff(int mclk, int srate)
8646d10c914SBrian Austin {
8656d10c914SBrian Austin int i;
8666d10c914SBrian Austin
8676d10c914SBrian Austin for (i = 0; i < ARRAY_SIZE(cs42l73_mclk_coeffs); i++) {
8686d10c914SBrian Austin if (cs42l73_mclk_coeffs[i].mclk == mclk &&
8696d10c914SBrian Austin cs42l73_mclk_coeffs[i].srate == srate)
8706d10c914SBrian Austin return i;
8716d10c914SBrian Austin }
8726d10c914SBrian Austin return -EINVAL;
8736d10c914SBrian Austin
8746d10c914SBrian Austin }
8756d10c914SBrian Austin
cs42l73_set_mclk(struct snd_soc_dai * dai,unsigned int freq)8766d10c914SBrian Austin static int cs42l73_set_mclk(struct snd_soc_dai *dai, unsigned int freq)
8776d10c914SBrian Austin {
878092631bfSKuninori Morimoto struct snd_soc_component *component = dai->component;
879092631bfSKuninori Morimoto struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
8806d10c914SBrian Austin
8816d10c914SBrian Austin int mclkx_coeff;
8826d10c914SBrian Austin u32 mclk = 0;
8836d10c914SBrian Austin u8 dmmcc = 0;
8846d10c914SBrian Austin
8856d10c914SBrian Austin /* MCLKX -> MCLK */
8866d10c914SBrian Austin mclkx_coeff = cs42l73_get_mclkx_coeff(freq);
88786fc4998SJesper Juhl if (mclkx_coeff < 0)
88886fc4998SJesper Juhl return mclkx_coeff;
8896d10c914SBrian Austin
8906d10c914SBrian Austin mclk = cs42l73_mclkx_coeffs[mclkx_coeff].mclkx /
8916d10c914SBrian Austin cs42l73_mclkx_coeffs[mclkx_coeff].ratio;
8926d10c914SBrian Austin
893092631bfSKuninori Morimoto dev_dbg(component->dev, "MCLK%u %u <-> internal MCLK %u\n",
8946d10c914SBrian Austin priv->mclksel + 1, cs42l73_mclkx_coeffs[mclkx_coeff].mclkx,
8956d10c914SBrian Austin mclk);
8966d10c914SBrian Austin
8976d10c914SBrian Austin dmmcc = (priv->mclksel << 4) |
8986d10c914SBrian Austin (cs42l73_mclkx_coeffs[mclkx_coeff].mclkdiv << 1);
8996d10c914SBrian Austin
900092631bfSKuninori Morimoto snd_soc_component_write(component, CS42L73_DMMCC, dmmcc);
9016d10c914SBrian Austin
9026d10c914SBrian Austin priv->sysclk = mclkx_coeff;
9036d10c914SBrian Austin priv->mclk = mclk;
9046d10c914SBrian Austin
9056d10c914SBrian Austin return 0;
9066d10c914SBrian Austin }
9076d10c914SBrian Austin
cs42l73_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)9086d10c914SBrian Austin static int cs42l73_set_sysclk(struct snd_soc_dai *dai,
9096d10c914SBrian Austin int clk_id, unsigned int freq, int dir)
9106d10c914SBrian Austin {
911092631bfSKuninori Morimoto struct snd_soc_component *component = dai->component;
912092631bfSKuninori Morimoto struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
9136d10c914SBrian Austin
9146d10c914SBrian Austin switch (clk_id) {
9156d10c914SBrian Austin case CS42L73_CLKID_MCLK1:
9166d10c914SBrian Austin break;
9176d10c914SBrian Austin case CS42L73_CLKID_MCLK2:
9186d10c914SBrian Austin break;
9196d10c914SBrian Austin default:
9206d10c914SBrian Austin return -EINVAL;
9216d10c914SBrian Austin }
9226d10c914SBrian Austin
9236d10c914SBrian Austin if ((cs42l73_set_mclk(dai, freq)) < 0) {
924092631bfSKuninori Morimoto dev_err(component->dev, "Unable to set MCLK for dai %s\n",
9256d10c914SBrian Austin dai->name);
9266d10c914SBrian Austin return -EINVAL;
9276d10c914SBrian Austin }
9286d10c914SBrian Austin
9296d10c914SBrian Austin priv->mclksel = clk_id;
9306d10c914SBrian Austin
9316d10c914SBrian Austin return 0;
9326d10c914SBrian Austin }
9336d10c914SBrian Austin
cs42l73_set_dai_fmt(struct snd_soc_dai * codec_dai,unsigned int fmt)9346d10c914SBrian Austin static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
9356d10c914SBrian Austin {
936092631bfSKuninori Morimoto struct snd_soc_component *component = codec_dai->component;
937092631bfSKuninori Morimoto struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
9386d10c914SBrian Austin u8 id = codec_dai->id;
939dbb1f516SAxel Lin unsigned int inv, format;
9406d10c914SBrian Austin u8 spc, mmcc;
9416d10c914SBrian Austin
942a11f8a1cSKuninori Morimoto spc = snd_soc_component_read(component, CS42L73_SPC(id));
943a11f8a1cSKuninori Morimoto mmcc = snd_soc_component_read(component, CS42L73_MMCC(id));
9446d10c914SBrian Austin
9456d10c914SBrian Austin switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
9466d10c914SBrian Austin case SND_SOC_DAIFMT_CBM_CFM:
947f9ca0606SBrian Austin mmcc |= CS42L73_MS_MASTER;
9486d10c914SBrian Austin break;
9496d10c914SBrian Austin
9506d10c914SBrian Austin case SND_SOC_DAIFMT_CBS_CFS:
951f9ca0606SBrian Austin mmcc &= ~CS42L73_MS_MASTER;
9526d10c914SBrian Austin break;
9536d10c914SBrian Austin
9546d10c914SBrian Austin default:
9556d10c914SBrian Austin return -EINVAL;
9566d10c914SBrian Austin }
9576d10c914SBrian Austin
9586d10c914SBrian Austin format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
9596d10c914SBrian Austin inv = (fmt & SND_SOC_DAIFMT_INV_MASK);
9606d10c914SBrian Austin
9616d10c914SBrian Austin switch (format) {
9626d10c914SBrian Austin case SND_SOC_DAIFMT_I2S:
963f9ca0606SBrian Austin spc &= ~CS42L73_SPDIF_PCM;
9646d10c914SBrian Austin break;
9656d10c914SBrian Austin case SND_SOC_DAIFMT_DSP_A:
9666d10c914SBrian Austin case SND_SOC_DAIFMT_DSP_B:
967f9ca0606SBrian Austin if (mmcc & CS42L73_MS_MASTER) {
968092631bfSKuninori Morimoto dev_err(component->dev,
9696d10c914SBrian Austin "PCM format in slave mode only\n");
9706d10c914SBrian Austin return -EINVAL;
9716d10c914SBrian Austin }
9726d10c914SBrian Austin if (id == CS42L73_ASP) {
973092631bfSKuninori Morimoto dev_err(component->dev,
9746d10c914SBrian Austin "PCM format is not supported on ASP port\n");
9756d10c914SBrian Austin return -EINVAL;
9766d10c914SBrian Austin }
977f9ca0606SBrian Austin spc |= CS42L73_SPDIF_PCM;
9786d10c914SBrian Austin break;
9796d10c914SBrian Austin default:
9806d10c914SBrian Austin return -EINVAL;
9816d10c914SBrian Austin }
9826d10c914SBrian Austin
983f9ca0606SBrian Austin if (spc & CS42L73_SPDIF_PCM) {
9847b282cbbSAxel Lin /* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */
985f9ca0606SBrian Austin spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER);
9866d10c914SBrian Austin switch (format) {
9876d10c914SBrian Austin case SND_SOC_DAIFMT_DSP_B:
9886d10c914SBrian Austin if (inv == SND_SOC_DAIFMT_IB_IF)
989f9ca0606SBrian Austin spc |= CS42L73_PCM_MODE0;
9906d10c914SBrian Austin if (inv == SND_SOC_DAIFMT_IB_NF)
991f9ca0606SBrian Austin spc |= CS42L73_PCM_MODE1;
9926d10c914SBrian Austin break;
9936d10c914SBrian Austin case SND_SOC_DAIFMT_DSP_A:
9946d10c914SBrian Austin if (inv == SND_SOC_DAIFMT_IB_IF)
995f9ca0606SBrian Austin spc |= CS42L73_PCM_MODE1;
9966d10c914SBrian Austin break;
9976d10c914SBrian Austin default:
9986d10c914SBrian Austin return -EINVAL;
9996d10c914SBrian Austin }
10006d10c914SBrian Austin }
10016d10c914SBrian Austin
10026d10c914SBrian Austin priv->config[id].spc = spc;
10036d10c914SBrian Austin priv->config[id].mmcc = mmcc;
10046d10c914SBrian Austin
10056d10c914SBrian Austin return 0;
10066d10c914SBrian Austin }
10076d10c914SBrian Austin
1008096ae544SLars-Peter Clausen static const unsigned int cs42l73_asrc_rates[] = {
10096d10c914SBrian Austin 8000, 11025, 12000, 16000, 22050,
10106d10c914SBrian Austin 24000, 32000, 44100, 48000
10116d10c914SBrian Austin };
10126d10c914SBrian Austin
cs42l73_get_xspfs_coeff(u32 rate)10136d10c914SBrian Austin static unsigned int cs42l73_get_xspfs_coeff(u32 rate)
10146d10c914SBrian Austin {
10156d10c914SBrian Austin int i;
10166d10c914SBrian Austin for (i = 0; i < ARRAY_SIZE(cs42l73_asrc_rates); i++) {
10176d10c914SBrian Austin if (cs42l73_asrc_rates[i] == rate)
10186d10c914SBrian Austin return i + 1;
10196d10c914SBrian Austin }
10206d10c914SBrian Austin return 0; /* 0 = Don't know */
10216d10c914SBrian Austin }
10226d10c914SBrian Austin
cs42l73_update_asrc(struct snd_soc_component * component,int id,int srate)1023092631bfSKuninori Morimoto static void cs42l73_update_asrc(struct snd_soc_component *component, int id, int srate)
10246d10c914SBrian Austin {
10256d10c914SBrian Austin u8 spfs = 0;
10266d10c914SBrian Austin
10276d10c914SBrian Austin if (srate > 0)
10286d10c914SBrian Austin spfs = cs42l73_get_xspfs_coeff(srate);
10296d10c914SBrian Austin
10306d10c914SBrian Austin switch (id) {
10316d10c914SBrian Austin case CS42L73_XSP:
1032092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_VXSPFS, 0x0f, spfs);
10336d10c914SBrian Austin break;
10346d10c914SBrian Austin case CS42L73_ASP:
1035092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_ASPC, 0x3c, spfs << 2);
10366d10c914SBrian Austin break;
10376d10c914SBrian Austin case CS42L73_VSP:
1038092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_VXSPFS, 0xf0, spfs << 4);
10396d10c914SBrian Austin break;
10406d10c914SBrian Austin default:
10416d10c914SBrian Austin break;
10426d10c914SBrian Austin }
10436d10c914SBrian Austin }
10446d10c914SBrian Austin
cs42l73_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)10456d10c914SBrian Austin static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
10466d10c914SBrian Austin struct snd_pcm_hw_params *params,
10476d10c914SBrian Austin struct snd_soc_dai *dai)
10486d10c914SBrian Austin {
1049092631bfSKuninori Morimoto struct snd_soc_component *component = dai->component;
1050092631bfSKuninori Morimoto struct cs42l73_private *priv = snd_soc_component_get_drvdata(component);
10516d10c914SBrian Austin int id = dai->id;
10526d10c914SBrian Austin int mclk_coeff;
10536d10c914SBrian Austin int srate = params_rate(params);
10546d10c914SBrian Austin
1055f9ca0606SBrian Austin if (priv->config[id].mmcc & CS42L73_MS_MASTER) {
10566d10c914SBrian Austin /* CS42L73 Master */
10576d10c914SBrian Austin /* MCLK -> srate */
10586d10c914SBrian Austin mclk_coeff =
10596d10c914SBrian Austin cs42l73_get_mclk_coeff(priv->mclk, srate);
10606d10c914SBrian Austin
10616d10c914SBrian Austin if (mclk_coeff < 0)
10626d10c914SBrian Austin return -EINVAL;
10636d10c914SBrian Austin
1064092631bfSKuninori Morimoto dev_dbg(component->dev,
10656d10c914SBrian Austin "DAI[%d]: MCLK %u, srate %u, MMCC[5:0] = %x\n",
10666d10c914SBrian Austin id, priv->mclk, srate,
10676d10c914SBrian Austin cs42l73_mclk_coeffs[mclk_coeff].mmcc);
10686d10c914SBrian Austin
10696d10c914SBrian Austin priv->config[id].mmcc &= 0xC0;
10706d10c914SBrian Austin priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc;
10716d10c914SBrian Austin priv->config[id].spc &= 0xFC;
1072cadf2120SPaul Handrigan /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
1073cadf2120SPaul Handrigan if (priv->mclk >= 6400000)
1074f9ca0606SBrian Austin priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
1075cadf2120SPaul Handrigan else
1076f9ca0606SBrian Austin priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK;
10776d10c914SBrian Austin } else {
10786d10c914SBrian Austin /* CS42L73 Slave */
10796d10c914SBrian Austin priv->config[id].spc &= 0xFC;
1080f9ca0606SBrian Austin priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
10816d10c914SBrian Austin }
10826d10c914SBrian Austin /* Update ASRCs */
10836d10c914SBrian Austin priv->config[id].srate = srate;
10846d10c914SBrian Austin
1085092631bfSKuninori Morimoto snd_soc_component_write(component, CS42L73_SPC(id), priv->config[id].spc);
1086092631bfSKuninori Morimoto snd_soc_component_write(component, CS42L73_MMCC(id), priv->config[id].mmcc);
10876d10c914SBrian Austin
1088092631bfSKuninori Morimoto cs42l73_update_asrc(component, id, srate);
10896d10c914SBrian Austin
10906d10c914SBrian Austin return 0;
10916d10c914SBrian Austin }
10926d10c914SBrian Austin
cs42l73_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)1093092631bfSKuninori Morimoto static int cs42l73_set_bias_level(struct snd_soc_component *component,
10946d10c914SBrian Austin enum snd_soc_bias_level level)
10956d10c914SBrian Austin {
1096092631bfSKuninori Morimoto struct cs42l73_private *cs42l73 = snd_soc_component_get_drvdata(component);
10976d10c914SBrian Austin
10986d10c914SBrian Austin switch (level) {
10996d10c914SBrian Austin case SND_SOC_BIAS_ON:
1100092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_DMMCC, CS42L73_MCLKDIS, 0);
1101092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 0);
11026d10c914SBrian Austin break;
11036d10c914SBrian Austin
11046d10c914SBrian Austin case SND_SOC_BIAS_PREPARE:
11056d10c914SBrian Austin break;
11066d10c914SBrian Austin
11076d10c914SBrian Austin case SND_SOC_BIAS_STANDBY:
1108092631bfSKuninori Morimoto if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
11096d10c914SBrian Austin regcache_cache_only(cs42l73->regmap, false);
11106d10c914SBrian Austin regcache_sync(cs42l73->regmap);
11116d10c914SBrian Austin }
1112092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 1);
11136d10c914SBrian Austin break;
11146d10c914SBrian Austin
11156d10c914SBrian Austin case SND_SOC_BIAS_OFF:
1116092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_PWRCTL1, CS42L73_PDN, 1);
111741df0829SPaul Handrigan if (cs42l73->shutdwn_delay > 0) {
111841df0829SPaul Handrigan mdelay(cs42l73->shutdwn_delay);
111941df0829SPaul Handrigan cs42l73->shutdwn_delay = 0;
112041df0829SPaul Handrigan } else {
112141df0829SPaul Handrigan mdelay(15); /* Min amount of time requred to power
112241df0829SPaul Handrigan * down.
112341df0829SPaul Handrigan */
112441df0829SPaul Handrigan }
1125092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
11266d10c914SBrian Austin break;
11276d10c914SBrian Austin }
11286d10c914SBrian Austin return 0;
11296d10c914SBrian Austin }
11306d10c914SBrian Austin
cs42l73_set_tristate(struct snd_soc_dai * dai,int tristate)11316d10c914SBrian Austin static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate)
11326d10c914SBrian Austin {
1133092631bfSKuninori Morimoto struct snd_soc_component *component = dai->component;
11346d10c914SBrian Austin int id = dai->id;
11356d10c914SBrian Austin
1136092631bfSKuninori Morimoto return snd_soc_component_update_bits(component, CS42L73_SPC(id), CS42L73_SP_3ST,
11378626e5ebSAxel Lin tristate << 7);
11386d10c914SBrian Austin }
11396d10c914SBrian Austin
1140096ae544SLars-Peter Clausen static const struct snd_pcm_hw_constraint_list constraints_12_24 = {
11416d10c914SBrian Austin .count = ARRAY_SIZE(cs42l73_asrc_rates),
11426d10c914SBrian Austin .list = cs42l73_asrc_rates,
11436d10c914SBrian Austin };
11446d10c914SBrian Austin
cs42l73_pcm_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)11456d10c914SBrian Austin static int cs42l73_pcm_startup(struct snd_pcm_substream *substream,
11466d10c914SBrian Austin struct snd_soc_dai *dai)
11476d10c914SBrian Austin {
11486d10c914SBrian Austin snd_pcm_hw_constraint_list(substream->runtime, 0,
11496d10c914SBrian Austin SNDRV_PCM_HW_PARAM_RATE,
11506d10c914SBrian Austin &constraints_12_24);
11516d10c914SBrian Austin return 0;
11526d10c914SBrian Austin }
11536d10c914SBrian Austin
11546d10c914SBrian Austin
11556d10c914SBrian Austin #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
11566d10c914SBrian Austin SNDRV_PCM_FMTBIT_S24_LE)
11576d10c914SBrian Austin
1158890754a8SLars-Peter Clausen static const struct snd_soc_dai_ops cs42l73_ops = {
11596d10c914SBrian Austin .startup = cs42l73_pcm_startup,
11606d10c914SBrian Austin .hw_params = cs42l73_pcm_hw_params,
11616d10c914SBrian Austin .set_fmt = cs42l73_set_dai_fmt,
11626d10c914SBrian Austin .set_sysclk = cs42l73_set_sysclk,
11636d10c914SBrian Austin .set_tristate = cs42l73_set_tristate,
11646d10c914SBrian Austin };
11656d10c914SBrian Austin
11666d10c914SBrian Austin static struct snd_soc_dai_driver cs42l73_dai[] = {
11676d10c914SBrian Austin {
11686d10c914SBrian Austin .name = "cs42l73-xsp",
11696d10c914SBrian Austin .id = CS42L73_XSP,
11706d10c914SBrian Austin .playback = {
11716d10c914SBrian Austin .stream_name = "XSP Playback",
11726d10c914SBrian Austin .channels_min = 1,
11736d10c914SBrian Austin .channels_max = 2,
11746e84b976SLars-Peter Clausen .rates = SNDRV_PCM_RATE_KNOT,
11756d10c914SBrian Austin .formats = CS42L73_FORMATS,
11766d10c914SBrian Austin },
11776d10c914SBrian Austin .capture = {
11786d10c914SBrian Austin .stream_name = "XSP Capture",
11796d10c914SBrian Austin .channels_min = 1,
11806d10c914SBrian Austin .channels_max = 2,
11816e84b976SLars-Peter Clausen .rates = SNDRV_PCM_RATE_KNOT,
11826d10c914SBrian Austin .formats = CS42L73_FORMATS,
11836d10c914SBrian Austin },
11846d10c914SBrian Austin .ops = &cs42l73_ops,
1185260b668cSKuninori Morimoto .symmetric_rate = 1,
11866d10c914SBrian Austin },
11876d10c914SBrian Austin {
11886d10c914SBrian Austin .name = "cs42l73-asp",
11896d10c914SBrian Austin .id = CS42L73_ASP,
11906d10c914SBrian Austin .playback = {
11916d10c914SBrian Austin .stream_name = "ASP Playback",
11926d10c914SBrian Austin .channels_min = 2,
11936d10c914SBrian Austin .channels_max = 2,
11946e84b976SLars-Peter Clausen .rates = SNDRV_PCM_RATE_KNOT,
11956d10c914SBrian Austin .formats = CS42L73_FORMATS,
11966d10c914SBrian Austin },
11976d10c914SBrian Austin .capture = {
11986d10c914SBrian Austin .stream_name = "ASP Capture",
11996d10c914SBrian Austin .channels_min = 2,
12006d10c914SBrian Austin .channels_max = 2,
12016e84b976SLars-Peter Clausen .rates = SNDRV_PCM_RATE_KNOT,
12026d10c914SBrian Austin .formats = CS42L73_FORMATS,
12036d10c914SBrian Austin },
12046d10c914SBrian Austin .ops = &cs42l73_ops,
1205260b668cSKuninori Morimoto .symmetric_rate = 1,
12066d10c914SBrian Austin },
12076d10c914SBrian Austin {
12086d10c914SBrian Austin .name = "cs42l73-vsp",
12096d10c914SBrian Austin .id = CS42L73_VSP,
12106d10c914SBrian Austin .playback = {
12116d10c914SBrian Austin .stream_name = "VSP Playback",
12126d10c914SBrian Austin .channels_min = 1,
12136d10c914SBrian Austin .channels_max = 2,
12146e84b976SLars-Peter Clausen .rates = SNDRV_PCM_RATE_KNOT,
12156d10c914SBrian Austin .formats = CS42L73_FORMATS,
12166d10c914SBrian Austin },
12176d10c914SBrian Austin .capture = {
12186d10c914SBrian Austin .stream_name = "VSP Capture",
12196d10c914SBrian Austin .channels_min = 1,
12206d10c914SBrian Austin .channels_max = 2,
12216e84b976SLars-Peter Clausen .rates = SNDRV_PCM_RATE_KNOT,
12226d10c914SBrian Austin .formats = CS42L73_FORMATS,
12236d10c914SBrian Austin },
12246d10c914SBrian Austin .ops = &cs42l73_ops,
1225260b668cSKuninori Morimoto .symmetric_rate = 1,
12266d10c914SBrian Austin }
12276d10c914SBrian Austin };
12286d10c914SBrian Austin
cs42l73_probe(struct snd_soc_component * component)1229092631bfSKuninori Morimoto static int cs42l73_probe(struct snd_soc_component *component)
12306d10c914SBrian Austin {
1231092631bfSKuninori Morimoto struct cs42l73_private *cs42l73 = snd_soc_component_get_drvdata(component);
12326d10c914SBrian Austin
12333d8c8bc0SBrian Austin /* Set Charge Pump Frequency */
12343d8c8bc0SBrian Austin if (cs42l73->pdata.chgfreq)
1235092631bfSKuninori Morimoto snd_soc_component_update_bits(component, CS42L73_CPFCHC,
12363d8c8bc0SBrian Austin CS42L73_CHARGEPUMP_MASK,
12373d8c8bc0SBrian Austin cs42l73->pdata.chgfreq << 4);
12383d8c8bc0SBrian Austin
12393d8c8bc0SBrian Austin /* MCLK1 as master clk */
12403d8c8bc0SBrian Austin cs42l73->mclksel = CS42L73_CLKID_MCLK1;
12416d10c914SBrian Austin cs42l73->mclk = 0;
12426d10c914SBrian Austin
12435d6be5aaSXiubo Li return 0;
12446d10c914SBrian Austin }
12456d10c914SBrian Austin
1246092631bfSKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_cs42l73 = {
12476d10c914SBrian Austin .probe = cs42l73_probe,
12486d10c914SBrian Austin .set_bias_level = cs42l73_set_bias_level,
1249951cd7e6SKuninori Morimoto .controls = cs42l73_snd_controls,
1250951cd7e6SKuninori Morimoto .num_controls = ARRAY_SIZE(cs42l73_snd_controls),
12516d10c914SBrian Austin .dapm_widgets = cs42l73_dapm_widgets,
12526d10c914SBrian Austin .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets),
12536d10c914SBrian Austin .dapm_routes = cs42l73_audio_map,
12546d10c914SBrian Austin .num_dapm_routes = ARRAY_SIZE(cs42l73_audio_map),
1255092631bfSKuninori Morimoto .suspend_bias_off = 1,
1256092631bfSKuninori Morimoto .idle_bias_on = 1,
1257092631bfSKuninori Morimoto .use_pmdown_time = 1,
1258092631bfSKuninori Morimoto .endianness = 1,
12596d10c914SBrian Austin };
12606d10c914SBrian Austin
1261cd2ee8adSKrzysztof Kozlowski static const struct regmap_config cs42l73_regmap = {
12626d10c914SBrian Austin .reg_bits = 8,
12636d10c914SBrian Austin .val_bits = 8,
12646d10c914SBrian Austin
12656d10c914SBrian Austin .max_register = CS42L73_MAX_REGISTER,
12666d10c914SBrian Austin .reg_defaults = cs42l73_reg_defaults,
12676d10c914SBrian Austin .num_reg_defaults = ARRAY_SIZE(cs42l73_reg_defaults),
12686d10c914SBrian Austin .volatile_reg = cs42l73_volatile_register,
12696d10c914SBrian Austin .readable_reg = cs42l73_readable_register,
1270*7e39a718SMark Brown .cache_type = REGCACHE_MAPLE,
127127fb5851SCharles Keepax
127227fb5851SCharles Keepax .use_single_read = true,
127327fb5851SCharles Keepax .use_single_write = true,
12746d10c914SBrian Austin };
12756d10c914SBrian Austin
cs42l73_i2c_probe(struct i2c_client * i2c_client)12764a404345SStephen Kitt static int cs42l73_i2c_probe(struct i2c_client *i2c_client)
12776d10c914SBrian Austin {
12786d10c914SBrian Austin struct cs42l73_private *cs42l73;
12793d8c8bc0SBrian Austin struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
128026495252SCharles Keepax int ret, devid;
12816d10c914SBrian Austin unsigned int reg;
12827b09eea5SBrian Austin u32 val32;
12836d10c914SBrian Austin
128468fa08c6SMarkus Elfring cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(*cs42l73), GFP_KERNEL);
128510d95ad4SSachin Kamat if (!cs42l73)
12866d10c914SBrian Austin return -ENOMEM;
12876d10c914SBrian Austin
1288571f6a7fSBrian Austin cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);
12896d10c914SBrian Austin if (IS_ERR(cs42l73->regmap)) {
12906d10c914SBrian Austin ret = PTR_ERR(cs42l73->regmap);
12916d10c914SBrian Austin dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
1292571f6a7fSBrian Austin return ret;
12936d10c914SBrian Austin }
12943d8c8bc0SBrian Austin
12957b09eea5SBrian Austin if (pdata) {
12963d8c8bc0SBrian Austin cs42l73->pdata = *pdata;
12977b09eea5SBrian Austin } else {
129868fa08c6SMarkus Elfring pdata = devm_kzalloc(&i2c_client->dev, sizeof(*pdata),
12997b09eea5SBrian Austin GFP_KERNEL);
1300ddedd797SMarkus Elfring if (!pdata)
13017b09eea5SBrian Austin return -ENOMEM;
1302ddedd797SMarkus Elfring
13037b09eea5SBrian Austin if (i2c_client->dev.of_node) {
13047b09eea5SBrian Austin if (of_property_read_u32(i2c_client->dev.of_node,
13057b09eea5SBrian Austin "chgfreq", &val32) >= 0)
13067b09eea5SBrian Austin pdata->chgfreq = val32;
13077b09eea5SBrian Austin }
13087b09eea5SBrian Austin pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
13097b09eea5SBrian Austin "reset-gpio", 0);
13107b09eea5SBrian Austin cs42l73->pdata = *pdata;
13117b09eea5SBrian Austin }
13123d8c8bc0SBrian Austin
13133d8c8bc0SBrian Austin i2c_set_clientdata(i2c_client, cs42l73);
13143d8c8bc0SBrian Austin
13153d8c8bc0SBrian Austin if (cs42l73->pdata.reset_gpio) {
13162b21694fSAxel Lin ret = devm_gpio_request_one(&i2c_client->dev,
13172b21694fSAxel Lin cs42l73->pdata.reset_gpio,
13182b21694fSAxel Lin GPIOF_OUT_INIT_HIGH,
13192b21694fSAxel Lin "CS42L73 /RST");
13203d8c8bc0SBrian Austin if (ret < 0) {
13213d8c8bc0SBrian Austin dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
13223d8c8bc0SBrian Austin cs42l73->pdata.reset_gpio, ret);
13233d8c8bc0SBrian Austin return ret;
13243d8c8bc0SBrian Austin }
13253d8c8bc0SBrian Austin gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
13263d8c8bc0SBrian Austin gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
13273d8c8bc0SBrian Austin }
13283d8c8bc0SBrian Austin
13296d10c914SBrian Austin /* initialize codec */
133026495252SCharles Keepax devid = cirrus_read_device_id(cs42l73->regmap, CS42L73_DEVID_AB);
133126495252SCharles Keepax if (devid < 0) {
133226495252SCharles Keepax ret = devid;
133326495252SCharles Keepax dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret);
133426495252SCharles Keepax goto err_reset;
133526495252SCharles Keepax }
13366d10c914SBrian Austin
13376d10c914SBrian Austin if (devid != CS42L73_DEVID) {
1338ea075615SAxel Lin ret = -ENODEV;
13396d10c914SBrian Austin dev_err(&i2c_client->dev,
13406d10c914SBrian Austin "CS42L73 Device ID (%X). Expected %X\n",
13416d10c914SBrian Austin devid, CS42L73_DEVID);
134226495252SCharles Keepax goto err_reset;
13436d10c914SBrian Austin }
13446d10c914SBrian Austin
13456d10c914SBrian Austin ret = regmap_read(cs42l73->regmap, CS42L73_REVID, ®);
13466d10c914SBrian Austin if (ret < 0) {
13476d10c914SBrian Austin dev_err(&i2c_client->dev, "Get Revision ID failed\n");
134826495252SCharles Keepax goto err_reset;
13496d10c914SBrian Austin }
13506d10c914SBrian Austin
13516d10c914SBrian Austin dev_info(&i2c_client->dev,
13528421f620SAxel Lin "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
13536d10c914SBrian Austin
1354092631bfSKuninori Morimoto ret = devm_snd_soc_register_component(&i2c_client->dev,
1355092631bfSKuninori Morimoto &soc_component_dev_cs42l73, cs42l73_dai,
13566d10c914SBrian Austin ARRAY_SIZE(cs42l73_dai));
13576d10c914SBrian Austin if (ret < 0)
135826495252SCharles Keepax goto err_reset;
135926495252SCharles Keepax
1360571f6a7fSBrian Austin return 0;
136126495252SCharles Keepax
136226495252SCharles Keepax err_reset:
136326495252SCharles Keepax gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
136426495252SCharles Keepax
136526495252SCharles Keepax return ret;
13666d10c914SBrian Austin }
13676d10c914SBrian Austin
13687b09eea5SBrian Austin static const struct of_device_id cs42l73_of_match[] = {
13697b09eea5SBrian Austin { .compatible = "cirrus,cs42l73", },
13707b09eea5SBrian Austin {},
13717b09eea5SBrian Austin };
13727b09eea5SBrian Austin MODULE_DEVICE_TABLE(of, cs42l73_of_match);
13737b09eea5SBrian Austin
13746d10c914SBrian Austin static const struct i2c_device_id cs42l73_id[] = {
13756d10c914SBrian Austin {"cs42l73", 0},
13766d10c914SBrian Austin {}
13776d10c914SBrian Austin };
13786d10c914SBrian Austin
13796d10c914SBrian Austin MODULE_DEVICE_TABLE(i2c, cs42l73_id);
13806d10c914SBrian Austin
13816d10c914SBrian Austin static struct i2c_driver cs42l73_i2c_driver = {
13826d10c914SBrian Austin .driver = {
13836d10c914SBrian Austin .name = "cs42l73",
13847b09eea5SBrian Austin .of_match_table = cs42l73_of_match,
13856d10c914SBrian Austin },
13866d10c914SBrian Austin .id_table = cs42l73_id,
13879abcd240SUwe Kleine-König .probe = cs42l73_i2c_probe,
13886d10c914SBrian Austin
13896d10c914SBrian Austin };
13906d10c914SBrian Austin
13915edd3c27SBrian Austin module_i2c_driver(cs42l73_i2c_driver);
13926d10c914SBrian Austin
13936d10c914SBrian Austin MODULE_DESCRIPTION("ASoC CS42L73 driver");
13946d10c914SBrian Austin MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
13956d10c914SBrian Austin MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
13966d10c914SBrian Austin MODULE_LICENSE("GPL");
1397